]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/client.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / client.c
index 44a76f49e9a9e614c42036121730691da7e0305b..9c0a17dc68191759b1e521f654192352769283b9 100644 (file)
@@ -1,9 +1,12 @@
 /*
- * "$Id: client.c 6247 2007-02-07 20:54:37Z mike $"
+ * "$Id: client.c 6329 2007-03-12 14:48:28Z mike $"
  *
  *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ *   This file contains Kerberos support code, copyright 2006 by
+ *   Jelmer Vernooij.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -33,6 +36,7 @@
  *   cupsdSendHeader()       - Send an HTTP request.
  *   cupsdUpdateCGI()        - Read status messages from CGI scripts and programs.
  *   cupsdWriteClient()      - Write data to a client as needed.
+ *   cupsdWritePipe()        - Flag that data is available on the CGI pipe.
  *   check_if_modified()     - Decode an "If-Modified-Since" line.
  *   encrypt_client()        - Enable encryption for the client...
  *   get_cdsa_certificate()  - Convert a keychain name into the CFArrayRef
@@ -94,7 +98,7 @@ static int            encrypt_client(cupsd_client_t *con);
 #ifdef HAVE_CDSASSL
 static CFArrayRef      get_cdsa_certificate(cupsd_client_t *con);
 #endif /* HAVE_CDSASSL */
-static char            *get_file(cupsd_client_t *con, struct stat *filestats, 
+static char            *get_file(cupsd_client_t *con, struct stat *filestats,
                                  char *filename, int len);
 static http_status_t   install_conf_file(cupsd_client_t *con);
 static int             is_cgi(cupsd_client_t *con, const char *filename,
@@ -405,7 +409,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   */
 
   val = 1;
-  setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 
+  setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
 
  /*
   * Close this file on all execs...
@@ -417,10 +421,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   * Add the socket to the select() input mask.
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdAcceptClient: Adding fd %d to InputSet...",
-                  con->http.fd);
-  FD_SET(con->http.fd, InputSet);
+  cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
 
  /*
   * Temporarily suspend accept()'s until we lose a client...
@@ -587,13 +588,7 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
 
   if (con->file >= 0)
   {
-    if (FD_ISSET(con->file, InputSet))
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdCloseClient: %d Removing fd %d from InputSet...",
-                     con->http.fd, con->file);
-      FD_CLR(con->file, InputSet);
-    }
+    cupsdRemoveSelect(con->file);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "cupsdCloseClient: %d Closing data file %d.",
@@ -615,11 +610,8 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
       * Only do a partial close so that the encrypted client gets everything.
       */
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdCloseClient: Removing fd %d from OutputSet...",
-                     con->http.fd);
       shutdown(con->http.fd, 0);
-      FD_CLR(con->http.fd, OutputSet);
+      cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
     }
     else
     {
@@ -627,12 +619,8 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
       * Shut the socket down fully...
       */
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdCloseClient: Removing fd %d from InputSet and OutputSet...",
-                     con->http.fd);
+      cupsdRemoveSelect(con->http.fd);
       close(con->http.fd);
-      FD_CLR(con->http.fd, InputSet);
-      FD_CLR(con->http.fd, OutputSet);
       con->http.fd = -1;
     }
   }
@@ -671,6 +659,14 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
       con->language = NULL;
     }
 
+#ifdef HAVE_AUTHORIZATION_H
+    if (con->authref)
+    {
+      AuthorizationFree(con->authref, kAuthorizationFlagDefaults);
+      con->authref = NULL;
+    }
+#endif /* HAVE_AUTHORIZATION_H */
+
    /*
     * Re-enable new client connections if we are going back under the
     * limit...
@@ -711,7 +707,7 @@ cupsdFlushHeader(cupsd_client_t *con)       /* I - Client to flush to */
  * 'cupsdReadClient()' - Read data from a client.
  */
 
-int                                    /* O - 1 on success, 0 on error */
+void
 cupsdReadClient(cupsd_client_t *con)   /* I - Client to read from */
 {
   char                 line[32768],    /* Line from client... */
@@ -740,7 +736,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
   if (con->http.error)
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: http error seen...");
-    return (cupsdCloseClient(con));
+    cupsdCloseClient(con);
+    return;
   }
 
 #ifdef HAVE_SSL
@@ -764,9 +761,9 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                       buf[0] & 255);
 
       if (!encrypt_client(con))
-        return (cupsdCloseClient(con));
+        cupsdCloseClient(con);
 
-      return (1);
+      return;
     }
   }
 #endif /* HAVE_SSL */
@@ -782,7 +779,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
        {
          cupsdLogMessage(CUPSD_LOG_DEBUG2,
                          "cupsdReadClient: httpGets returned EOF...");
-          return (cupsdCloseClient(con));
+         cupsdCloseClient(con);
+         return;
        }
 
        /*
@@ -846,7 +844,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                              "Bad request line \"%s\" from %s!", line,
                              con->http.hostname);
              cupsdSendError(con, HTTP_BAD_REQUEST);
-             return (cupsdCloseClient(con));
+             cupsdCloseClient(con);
+             return;
          case 2 :
              con->http.version = HTTP_0_9;
              break;
@@ -857,7 +856,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                                "Bad request line \"%s\" from %s!", line,
                                con->http.hostname);
                cupsdSendError(con, HTTP_BAD_REQUEST);
-               return (cupsdCloseClient(con));
+               cupsdCloseClient(con);
+               return;
              }
 
              if (major < 2)
@@ -871,7 +871,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
              else
              {
                cupsdSendError(con, HTTP_NOT_SUPPORTED);
-               return (cupsdCloseClient(con));
+               cupsdCloseClient(con);
+               return;
              }
              break;
        }
@@ -916,7 +917,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
            cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!",
                            con->uri);
            cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED);
-           return (cupsdCloseClient(con));
+           cupsdCloseClient(con);
+           return;
          }
 
          /*
@@ -949,7 +951,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
        {
          cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation);
          cupsdSendError(con, HTTP_BAD_REQUEST);
-         return (cupsdCloseClient(con));
+         cupsdCloseClient(con);
+         return;
        }
 
         con->start     = time(NULL);
@@ -972,12 +975,16 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         * Parse incoming parameters until the status changes...
        */
 
-        status = httpUpdate(HTTP(con));
+        while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE)
+         if (con->http.used == 0 ||
+             !memchr(con->http.buffer, '\n', con->http.used))
+           break;
 
        if (status != HTTP_OK && status != HTTP_CONTINUE)
        {
          cupsdSendError(con, HTTP_BAD_REQUEST);
-         return (cupsdCloseClient(con));
+         cupsdCloseClient(con);
+         return;
        }
        break;
 
@@ -1044,7 +1051,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
       */
 
       if (!cupsdSendError(con, HTTP_BAD_REQUEST))
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
     }
     else if (con->operation == HTTP_OPTIONS)
     {
@@ -1055,7 +1065,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
       if (con->best && con->best->type != AUTH_NONE)
       {
        if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
       }
 
       if (!strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") &&
@@ -1067,7 +1080,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
        */
 
        if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
        httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
@@ -1075,25 +1091,40 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
        httpPrintf(HTTP(con), "\r\n");
 
        if (cupsdFlushHeader(con) < 0)
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 
         if (!encrypt_client(con))
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 #else
        if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 #endif /* HAVE_SSL */
       }
 
       if (!cupsdSendHeader(con, HTTP_OK, NULL))
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
 
       httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
       httpPrintf(HTTP(con), "Content-Length: 0\r\n");
       httpPrintf(HTTP(con), "\r\n");
 
       if (cupsdFlushHeader(con) < 0)
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
     }
     else if (!is_path_absolute(con->uri))
     {
@@ -1102,7 +1133,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
       */
 
       if (!cupsdSendError(con, HTTP_FORBIDDEN))
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
     }
     else
     {
@@ -1115,7 +1149,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
        */
 
        if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
        httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
@@ -1123,13 +1160,22 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
        httpPrintf(HTTP(con), "\r\n");
 
        if (cupsdFlushHeader(con) < 0)
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 
         if (!encrypt_client(con))
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 #else
        if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 #endif /* HAVE_SSL */
       }
 
@@ -1139,7 +1185,8 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                        "cupsdReadClient: Unauthorized request for %s...\n",
                        con->uri);
        cupsdSendError(con, status);
-       return (cupsdCloseClient(con));
+       cupsdCloseClient(con);
+       return;
       }
 
       if (con->http.expect &&
@@ -1152,7 +1199,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
          */
 
          if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL))
-           return (cupsdCloseClient(con));
+         {
+           cupsdCloseClient(con);
+           return;
+         }
        }
        else
        {
@@ -1161,13 +1211,19 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
          */
 
          if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL))
-           return (cupsdCloseClient(con));
+         {
+           cupsdCloseClient(con);
+           return;
+         }
 
          httpPrintf(HTTP(con), "Content-Length: 0\r\n");
          httpPrintf(HTTP(con), "\r\n");
 
          if (cupsdFlushHeader(con) < 0)
-           return (cupsdCloseClient(con));
+          {
+           cupsdCloseClient(con);
+           return;
+         }
        }
       }
 
@@ -1189,7 +1245,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              else
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1258,7 +1317,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
               if (!cupsdSendCommand(con, con->command, con->options, 0))
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
               }
              else
                cupsdLogRequest(con, HTTP_OK);
@@ -1279,7 +1341,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1293,7 +1358,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                                       sizeof(buf))) == NULL)
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1310,7 +1378,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                if (!cupsdSendCommand(con, con->command, con->options, 0))
                {
                  if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                   return (cupsdCloseClient(con));
+                 {
+                   cupsdCloseClient(con);
+                   return;
+                 }
                }
                else
                  cupsdLogRequest(con, HTTP_OK);
@@ -1323,7 +1394,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              if (!check_if_modified(con, &filestats))
               {
                if (!cupsdSendError(con, HTTP_NOT_MODIFIED))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
              }
              else
               {
@@ -1333,7 +1407,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                  snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
                if (!write_file(con, HTTP_OK, filename, line, &filestats))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
              }
            }
             break;
@@ -1357,7 +1434,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
             }
@@ -1368,7 +1448,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_BAD_REQUEST))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1460,7 +1543,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                                       sizeof(buf))) == NULL)
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1474,7 +1560,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                */
 
                if (!cupsdSendError(con, HTTP_UNAUTHORIZED))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
              }
            }
            break;
@@ -1494,7 +1583,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1517,7 +1609,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
             }
@@ -1528,7 +1623,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_BAD_REQUEST))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1548,7 +1646,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
            if (con->file < 0)
            {
              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
            }
 
            fchmod(con->file, 0640);
@@ -1559,7 +1660,8 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        case HTTP_DELETE :
        case HTTP_TRACE :
             cupsdSendError(con, HTTP_NOT_IMPLEMENTED);
-           return (cupsdCloseClient(con));
+           cupsdCloseClient(con);
+           return;
 
        case HTTP_HEAD :
             if (!strncmp(con->uri, "/printers/", 10) &&
@@ -1577,7 +1679,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              else
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1596,13 +1701,22 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
              */
 
               if (!cupsdSendHeader(con, HTTP_OK, "text/html"))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (httpPrintf(HTTP(con), "\r\n") < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (cupsdFlushHeader(con) < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_OK);
            }
@@ -1619,7 +1733,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1627,14 +1744,20 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                                          sizeof(buf))) == NULL)
            {
              if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html"))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_NOT_FOUND);
            }
            else if (!check_if_modified(con, &filestats))
             {
               if (!cupsdSendError(con, HTTP_NOT_MODIFIED))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_NOT_MODIFIED);
            }
@@ -1651,24 +1774,39 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
               if (!cupsdSendHeader(con, HTTP_OK, line))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
                             httpGetDateString(filestats.st_mtime)) < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
                             (unsigned long)filestats.st_size) < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_OK);
            }
 
             if (httpPrintf(HTTP(con), "\r\n") < 0)
-             return (cupsdCloseClient(con));
+           {
+             cupsdCloseClient(con);
+             return;
+           }
 
            if (cupsdFlushHeader(con) < 0)
-             return (cupsdCloseClient(con));
+            {
+             cupsdCloseClient(con);
+             return;
+           }
 
             con->http.state = HTTP_WAITING;
             break;
@@ -1694,35 +1832,45 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                            "CHUNKED" : "LENGTH",
                        CUPS_LLCAST con->http.data_remaining, con->file);
 
-        if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
-         return (cupsdCloseClient(con));
-       else if (bytes > 0)
+        do
        {
-         con->bytes += bytes;
+          if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+         {
+           cupsdCloseClient(con);
+           return;
+         }
+         else if (bytes > 0)
+         {
+           con->bytes += bytes;
 
-          cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                         "cupsdReadClient: %d writing %d bytes to %d",
-                         con->http.fd, bytes, con->file);
+            cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                           "cupsdReadClient: %d writing %d bytes to %d",
+                           con->http.fd, bytes, con->file);
 
-          if (write(con->file, line, bytes) < bytes)
-         {
-            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "cupsdReadClient: Unable to write %d bytes to %s: %s",
-                           bytes, con->filename, strerror(errno));
+            if (write(con->file, line, bytes) < bytes)
+           {
+              cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "cupsdReadClient: Unable to write %d bytes to %s: %s",
+                             bytes, con->filename, strerror(errno));
 
-           cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                           "cupsdReadClient: Closing data file %d...",
-                           con->file);
+             cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                             "cupsdReadClient: Closing data file %d...",
+                             con->file);
 
-           close(con->file);
-           con->file = -1;
-           unlink(con->filename);
-           cupsdClearString(&con->filename);
+             close(con->file);
+             con->file = -1;
+             unlink(con->filename);
+             cupsdClearString(&con->filename);
 
-            if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-             return (cupsdCloseClient(con));
+              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+           }
          }
-       }
+        }
+       while (con->http.state == HTTP_PUT_RECV && con->http.used > 0);
 
         if (con->http.state == HTTP_WAITING)
        {
@@ -1755,7 +1903,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
            cupsdClearString(&con->filename);
 
             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-             return (cupsdCloseClient(con));
+           {
+             cupsdCloseClient(con);
+             return;
+           }
          }
 
          /*
@@ -1769,7 +1920,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
          */
 
           if (!cupsdSendError(con, status))
-           return (cupsdCloseClient(con));
+         {
+           cupsdCloseClient(con);
+           return;
+         }
        }
         break;
 
@@ -1782,94 +1936,112 @@ cupsdReadClient(cupsd_client_t *con)   /* I - Client to read from */
                            "CHUNKED" : "LENGTH",
                        CUPS_LLCAST con->http.data_remaining, con->file);
 
-        if (con->request)
+        do
        {
-        /*
-         * Grab any request data from the connection...
-         */
-
-         if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
+          if (con->request)
          {
-            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "cupsdReadClient: %d IPP Read Error!",
-                           con->http.fd);
+          /*
+           * Grab any request data from the connection...
+           */
 
-           cupsdSendError(con, HTTP_BAD_REQUEST);
-           return (cupsdCloseClient(con));
-         }
-         else if (ipp_state != IPP_DATA)
-         {
-            if (con->http.state == HTTP_POST_SEND)
+           if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
            {
+              cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "cupsdReadClient: %d IPP Read Error!",
+                             con->http.fd);
+
              cupsdSendError(con, HTTP_BAD_REQUEST);
-             return (cupsdCloseClient(con));
+             cupsdCloseClient(con);
+             return;
            }
+           else if (ipp_state != IPP_DATA)
+           {
+              if (con->http.state == HTTP_POST_SEND)
+             {
+               cupsdSendError(con, HTTP_BAD_REQUEST);
+               cupsdCloseClient(con);
+               return;
+             }
 
-           break;
-          }
-         else
-           con->bytes += ippLength(con->request);
-       }
+             break;
+            }
+           else
+             con->bytes += ippLength(con->request);
+         }
 
-        if (con->file < 0 && con->http.state != HTTP_POST_SEND)
-       {
-         /*
-         * Create a file as needed for the request data...
-         */
+          if (con->file < 0 && con->http.state != HTTP_POST_SEND)
+         {
+           /*
+           * Create a file as needed for the request data...
+           */
 
-          cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
-         con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+            cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
+           con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
 
-          cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
-                         con->filename, con->file);
+            cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
+                           con->filename, con->file);
 
-         if (con->file < 0)
-         {
-           if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-             return (cupsdCloseClient(con));
-         }
+           if (con->file < 0)
+           {
+             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+           }
 
-         fchmod(con->file, 0640);
-         fchown(con->file, RunUser, Group);
-          fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
-       }
+           fchmod(con->file, 0640);
+           fchown(con->file, RunUser, Group);
+            fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+         }
 
-       if (con->http.state != HTTP_POST_SEND)
-       {
-          if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
-           return (cupsdCloseClient(con));
-         else if (bytes > 0)
+         if (con->http.state != HTTP_POST_SEND)
          {
-           con->bytes += bytes;
+            if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+           {
+             cupsdCloseClient(con);
+             return;
+           }
+           else if (bytes > 0)
+           {
+             con->bytes += bytes;
 
-            cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                           "cupsdReadClient: %d writing %d bytes to %d",
-                           con->http.fd, bytes, con->file);
+              cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                             "cupsdReadClient: %d writing %d bytes to %d",
+                             con->http.fd, bytes, con->file);
 
-            if (write(con->file, line, bytes) < bytes)
-           {
-              cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdReadClient: Unable to write %d bytes to %s: %s",
-                             bytes, con->filename, strerror(errno));
+              if (write(con->file, line, bytes) < bytes)
+             {
+               cupsdLogMessage(CUPSD_LOG_ERROR,
+                               "cupsdReadClient: Unable to write %d bytes to %s: %s",
+                               bytes, con->filename, strerror(errno));
 
-             cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                             "cupsdReadClient: Closing file %d...",
-                             con->file);
+               cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                               "cupsdReadClient: Closing file %d...",
+                               con->file);
 
-             close(con->file);
-             con->file = -1;
-             unlink(con->filename);
-             cupsdClearString(&con->filename);
+               close(con->file);
+               con->file = -1;
+               unlink(con->filename);
+               cupsdClearString(&con->filename);
 
-              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
+             }
+           }
+           else if (con->http.state == HTTP_POST_RECV)
+              return;
+           else if (con->http.state != HTTP_POST_SEND)
+           {
+             cupsdCloseClient(con);
+             return;
            }
          }
-         else if (con->http.state == HTTP_POST_RECV)
-            return (1); /* ??? */
-         else if (con->http.state != HTTP_POST_SEND)
-           return (cupsdCloseClient(con));
-       }
+        }
+       while (con->http.state == HTTP_POST_RECV && con->http.used > 0);
 
        if (con->http.state == HTTP_POST_SEND)
        {
@@ -1910,7 +2082,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
               }
 
               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
            }
 
            if (con->command)
@@ -1918,7 +2093,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              if (!cupsdSendCommand(con, con->command, con->options, 0))
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
               }
              else
                cupsdLogRequest(con, HTTP_OK);
@@ -1926,7 +2104,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
          }
 
           if (con->request)
-           return (cupsdProcessIPPRequest(con));
+         {
+           cupsdProcessIPPRequest(con);
+           return;
+         }
        }
         break;
 
@@ -1935,9 +2116,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
   }
 
   if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
-    return (cupsdCloseClient(con));
-  else
-    return (1);
+    cupsdCloseClient(con);
 }
 
 
@@ -1989,14 +2168,7 @@ cupsdSendCommand(
 
   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdSendCommand: Adding fd %d to InputSet...", con->file);
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdSendCommand: Adding fd %d to OutputSet...",
-                  con->http.fd);
-
-  FD_SET(con->file, InputSet);
-  FD_SET(con->http.fd, OutputSet);
+  cupsdAddSelect(con->file, (cupsd_selfunc_t)cupsdWritePipe, NULL, con);
 
   con->sent_header = 0;
   con->file_ready  = 0;
@@ -2044,9 +2216,12 @@ cupsdSendError(cupsd_client_t *con,      /* I - Connection */
  /*
   * To work around bugs in some proxies, don't use Keep-Alive for some
   * error messages...
+  *
+  * Kerberos authentication doesn't work without Keep-Alive, so
+  * never disable it in that case.
   */
 
-  if (code >= HTTP_BAD_REQUEST)
+  if (code >= HTTP_BAD_REQUEST && con->http.auth_type != AUTH_KERBEROS)
     con->http.keep_alive = HTTP_KEEPALIVE_OFF;
 
  /*
@@ -2066,8 +2241,8 @@ cupsdSendError(cupsd_client_t *con,       /* I - Connection */
     return (0);
 #endif /* HAVE_SSL */
 
-  if ((con->http.version >= HTTP_1_1 && !con->http.keep_alive) ||
-      (code >= HTTP_BAD_REQUEST && code != HTTP_UPGRADE_REQUIRED))
+  if (con->http.version >= HTTP_1_1 &&
+      con->http.keep_alive == HTTP_KEEPALIVE_OFF)
   {
     if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0)
       return (0);
@@ -2091,7 +2266,8 @@ cupsdSendError(cupsd_client_t *con,       /* I - Connection */
       text = _cupsLangString(con->language,
                              _("Enter your username and password or the "
                               "root username and password to access this "
-                              "page."));
+                              "page. If you are using Kerberos authentication, "
+                              "make sure you have a valid Kerberos ticket."));
     else if (code == HTTP_UPGRADE_REQUIRED)
     {
       text = urltext;
@@ -2162,6 +2338,9 @@ cupsdSendHeader(cupsd_client_t *con,      /* I - Client to send to */
                 http_status_t  code,   /* I - HTTP status code */
                char           *type)   /* I - MIME type of document */
 {
+  char auth_str[1024];                 /* Authorization string */
+
+
  /*
   * Send the HTTP status header...
   */
@@ -2209,22 +2388,77 @@ cupsdSendHeader(cupsd_client_t *con,    /* I - Client to send to */
       auth_type = DefaultAuthType;
     else
       auth_type = con->best->type;
-      
-    if (auth_type != AUTH_DIGEST)
-    {
-      if (httpPrintf(HTTP(con),
-                     "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
-       return (0);
-    }
-    else
+
+    auth_str[0] = '\0';
+
+    if (auth_type == AUTH_BASIC || auth_type == AUTH_BASICDIGEST)
+      strlcpy(auth_str, "Basic realm=\"CUPS\"", sizeof(auth_str));
+    else if (auth_type == AUTH_DIGEST)
+      snprintf(auth_str, sizeof(auth_str), "Digest realm=\"CUPS\", nonce=\"%s\"",
+              con->http.hostname);
+#ifdef HAVE_GSSAPI
+    else if (auth_type == AUTH_KERBEROS && !con->no_negotiate &&
+            con->gss_output_token.length == 0)
+      strlcpy(auth_str, "Negotiate", sizeof(auth_str));
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_AUTHORIZATION_H
+    if (con->best)
     {
-      if (httpPrintf(HTTP(con),
-                     "WWW-Authenticate: Digest realm=\"CUPS\", nonce=\"%s\"\r\n",
-                    con->http.hostname) < 0)
-       return (0);
+      int       i;                     /* Looping var */
+      char     *auth_key;              /* Auth key buffer */
+      size_t   auth_size;              /* Size of remaining buffer */
+
+
+      auth_key  = auth_str + strlen(auth_str);
+      auth_size = sizeof(auth_str) - (auth_key - auth_str);
+
+      for (i = 0; i < con->best->num_names; i ++)
+      {
+       if (!strncasecmp(con->best->names[i], "@AUTHKEY(", 9))
+       {
+         snprintf(auth_key, auth_size, ", authkey=\"%s\"",
+                  con->best->names[i] + 9);
+         /* end parenthesis is stripped in conf.c */
+         break;
+        }
+       else if (!strcasecmp(con->best->names[i], "@SYSTEM") &&
+                SystemGroupAuthKey)
+       {
+         snprintf(auth_key, auth_size, ", authkey=\"%s\"", SystemGroupAuthKey);
+         break;
+       }
+      }
     }
+#endif /* HAVE_AUTHORIZATION_H */
+
+    if (auth_str[0] &&
+       httpPrintf(HTTP(con), "WWW-Authenticate: %s\r\n", auth_str) < 0)
+      return (0);
   }
 
+#ifdef HAVE_GSSAPI
+ /*
+  * WWW-Authenticate: Negotiate can be included even for
+  * non-401 replies...
+  */
+
+  if (con->gss_output_token.length > 0)
+  {
+    char       buf[2048];              /* Output token buffer */
+    OM_uint32  minor_status;           /* Minor status code */
+
+
+    httpEncode64_2(buf, sizeof(buf),
+                  con->gss_output_token.value,
+                  con->gss_output_token.length);
+    gss_release_buffer(&minor_status, &con->gss_output_token);
+
+    if (httpPrintf(HTTP(con), "WWW-Authenticate: Negotiate %s\r\n", buf) < 0)
+      return (0);
+  }
+#endif /* HAVE_GSSAPI */
+
   if (con->language && strcmp(con->language->language, "C"))
   {
     if (httpPrintf(HTTP(con), "Content-Language: %s\r\n",
@@ -2282,7 +2516,7 @@ cupsdUpdateCGI(void)
  * 'cupsdWriteClient()' - Write data to a client as needed.
  */
 
-int                                    /* O - 1 if success, 0 if fail */
+void
 cupsdWriteClient(cupsd_client_t *con)  /* I - Client connection */
 {
   int          bytes;                  /* Number of bytes written */
@@ -2301,7 +2535,28 @@ cupsdWriteClient(cupsd_client_t *con)    /* I - Client connection */
 
   if (con->http.state != HTTP_GET_SEND &&
       con->http.state != HTTP_POST_SEND)
-    return (1);
+    return;
+
+  if (con->pipe_pid)
+  {
+   /*
+    * Make sure we select on the CGI output...
+    */
+
+    cupsdAddSelect(con->file, (cupsd_selfunc_t)cupsdWritePipe, NULL, con);
+
+    if (!con->file_ready)
+    {
+     /*
+      * Try again later when there is CGI output available...
+      */
+
+      cupsdRemoveSelect(con->http.fd);
+      return;
+    }
+
+    con->file_ready = 0;
+  }
 
   if (con->response)
   {
@@ -2347,7 +2602,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
              con->sent_header = 2;
 
              if (httpPrintf(HTTP(con), "Content-Length: 0\r\n") < 0)
-               return (0);
+               return;
            }
            else if (!strncasecmp(buf, "Status:", 7))
            {
@@ -2362,7 +2617,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
              if (con->http.version == HTTP_1_1)
              {
                if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
-                 return (0);
+                 return;
              }
             }
          }
@@ -2392,7 +2647,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
             if (cupsdFlushHeader(con) < 0)
            {
              cupsdCloseClient(con);
-             return (0);
+             return;
            }
 
            if (con->http.version == HTTP_1_1)
@@ -2417,7 +2672,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
         httpPrintf(HTTP(con), "%s", buf);
 
         con->http.activity = time(NULL);
-        return (1);
+        return;
       }
       else if (bytes == 0)
         con->http.activity = time(NULL);
@@ -2432,7 +2687,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
                        con->http.fd, bytes);
 
        cupsdCloseClient(con);
-       return (0);
+       return;
       }
 
       con->bytes += bytes;
@@ -2456,27 +2711,17 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
       if (httpWrite2(HTTP(con), "", 0) < 0)
       {
         cupsdCloseClient(con);
-       return (0);
+       return;
       }
     }
 
     con->http.state = HTTP_WAITING;
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdWriteClient: Removing fd %d from OutputSet...",
-                    con->http.fd);
-
-    FD_CLR(con->http.fd, OutputSet);
+    cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
 
     if (con->file >= 0)
     {
-      if (FD_ISSET(con->file, InputSet))
-      {
-       cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                       "cupsdWriteClient: Removing fd %d from InputSet...",
-                        con->file);
-       FD_CLR(con->file, InputSet);
-      }
+      cupsdRemoveSelect(con->file);
 
       if (con->pipe_pid)
        cupsdEndProcess(con->pipe_pid, 0);
@@ -2518,25 +2763,28 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
     if (!con->http.keep_alive)
     {
       cupsdCloseClient(con);
-      return (0);
-    }
-  }
-  else
-  {
-    con->file_ready = 0;
-
-    if (con->pipe_pid && !FD_ISSET(con->file, InputSet))
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdWriteClient: Adding fd %d to InputSet...",
-                     con->file);
-      FD_SET(con->file, InputSet);
+      return;
     }
   }
 
   con->http.activity = time(NULL);
+}
 
-  return (1);
+
+/*
+ * 'cupsdWritePipe()' - Flag that data is available on the CGI pipe.
+ */
+
+void
+cupsdWritePipe(cupsd_client_t *con)    /* I - Client connection */
+{
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdWritePipe: CGI output on fd %d...",
+                  con->file);
+
+  con->file_ready = 1;
+
+  cupsdRemoveSelect(con->file);
+  cupsdAddSelect(con->http.fd, NULL, (cupsd_selfunc_t)cupsdWriteClient, con);
 }
 
 
@@ -2667,7 +2915,7 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
 
   con->http.tls = conn;
   return (1);
-  
+
 #  elif defined(HAVE_GNUTLS)
   http_tls_t   *conn;                  /* TLS session object */
   int          error;                  /* Error code */
@@ -2712,7 +2960,7 @@ encrypt_client(cupsd_client_t *con)       /* I - Client to encrypt */
   }
 
   gnutls_certificate_allocate_credentials(credentials);
-  gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, 
+  gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate,
                                       ServerKey, GNUTLS_X509_FMT_PEM);
 
   gnutls_init(&(conn->session), GNUTLS_SERVER);
@@ -2979,11 +3227,13 @@ get_file(cupsd_client_t *con,           /* I  - Client connection */
 
 
  /*
-  * Need to add DocumentRoot global...
+  * Figure out the real filename...
   */
 
   if (!strncmp(con->uri, "/ppd/", 5))
     snprintf(filename, len, "%s%s", ServerRoot, con->uri);
+  else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
+    snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5);
   else if (!strncmp(con->uri, "/admin/conf/", 12))
     snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11);
   else if (!strncmp(con->uri, "/admin/log/", 11))
@@ -3472,7 +3722,7 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
   int          pid,                    /* Process ID of command */
                status;                 /* Status of command */
   char         command[1024],          /* Command */
-               *argv[11],              /* Command-line arguments */
+               *argv[12],              /* Command-line arguments */
                *envp[MAX_ENV + 1],     /* Environment variables */
                home[1024],             /* HOME environment variable */
                infofile[1024],         /* Type-in information for cert */
@@ -3548,7 +3798,7 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
     envp[envc++] = home;
     envp[envc]   = NULL;
 
-    if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, 1, &pid))
+    if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, &pid))
     {
       unlink(seedfile);
       return (0);
@@ -3625,7 +3875,7 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
 
   infofd = open(infofile, O_RDONLY);
 
-  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, 1, &pid))
+  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid))
   {
     close(infofd);
     unlink(infofile);
@@ -3858,7 +4108,7 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
 
   infofd = open(infofile, O_RDONLY);
 
-  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, 1, &pid))
+  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid))
   {
     close(infofd);
     unlink(infofile);
@@ -3928,10 +4178,11 @@ pipe_command(cupsd_client_t *con,       /* I - Client connection */
   int          envc;                   /* Number of environment variables */
   char         argbuf[10240],          /* Argument buffer */
                *argv[100],             /* Argument strings */
-               *envp[MAX_ENV + 17];    /* Environment variables */
+               *envp[MAX_ENV + 18];    /* Environment variables */
   char         content_length[1024],   /* CONTENT_LENGTH environment variable */
                content_type[1024],     /* CONTENT_TYPE environment variable */
                http_cookie[32768],     /* HTTP_COOKIE environment variable */
+               http_referer[1024],     /* HTTP_REFERER environment variable */
                http_user_agent[1024],  /* HTTP_USER_AGENT environment variable */
                lang[1024],             /* LANG environment variable */
                path_info[1024],        /* PATH_INFO environment variable */
@@ -4126,6 +4377,13 @@ pipe_command(cupsd_client_t *con,        /* I - Client connection */
     envp[envc ++] = http_user_agent;
   }
 
+  if (con->http.fields[HTTP_FIELD_REFERER][0])
+  {
+    snprintf(http_referer, sizeof(http_referer), "HTTP_REFERER=%s",
+             con->http.fields[HTTP_FIELD_REFERER]);
+    envp[envc ++] = http_referer;
+  }
+
   if (con->operation == HTTP_GET)
   {
     envp[envc ++] = "REQUEST_METHOD=GET";
@@ -4190,7 +4448,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   */
 
   if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
-                       -1, root, &pid) < 0)
+                       -1, -1, root, &pid) < 0)
   {
    /*
     * Error - can't fork!
@@ -4267,15 +4525,13 @@ write_file(cupsd_client_t *con,         /* I - Client connection */
   else
     con->http._data_remaining = INT_MAX;
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "write_file: Adding fd %d to OutputSet...", con->http.fd);
-
-  FD_SET(con->http.fd, OutputSet);
+  cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
+                 (cupsd_selfunc_t)cupsdWriteClient, con);
 
   return (1);
 }
 
 
 /*
- * End of "$Id: client.c 6247 2007-02-07 20:54:37Z mike $".
+ * End of "$Id: client.c 6329 2007-03-12 14:48:28Z mike $".
  */