]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Implement httpReadRequest and httpWriteResponse.
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Fri, 2 Nov 2012 14:20:27 +0000 (14:20 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Fri, 2 Nov 2012 14:20:27 +0000 (14:20 +0000)
Add ippAddStringf/fv.

Fix Upgrade: headers from scheduler.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@10676 7a7537e8-13f0-0310-91df-b6672ffda945

cups/http.c
cups/http.h
cups/ipp.c
cups/ipp.h
scheduler/client.c

index 11990e62d2e8c43e06cbea7fda6417547c897aa0..64237d5f9cee26933a17a4676a327ba6fb1c767e 100644 (file)
@@ -2463,11 +2463,104 @@ httpReadRequest(http_t *http,          /* I - HTTP connection */
                 char   *uri,           /* I - URI buffer */
                size_t urilen)          /* I - Size of URI buffer */
 {
-  (void)http;
-  (void)uri;
-  (void)urilen;
+  char line[4096],                     /* HTTP request line */
+       *req_method,                    /* HTTP request method */
+       *req_uri,                       /* HTTP request URI */
+       *req_version;                   /* HTTP request version number string */
 
-  return (HTTP_STATE_ERROR);
+
+ /*
+  * Range check input...
+  */
+
+  if (uri)
+    *uri = '\0';
+
+  if (!http || !uri || urilen < 1 || http->state != HTTP_WAITING)
+    return (HTTP_STATE_ERROR);
+
+ /*
+  * Read a line from the socket...
+  */
+
+  httpClearFields(http);
+
+  if (!httpGets(line, sizeof(line), http))
+    return (HTTP_STATE_ERROR);
+
+  if (!line[0])
+    return (HTTP_WAITING);
+
+ /*
+  * Parse it...
+  */
+
+  req_method = line;
+  req_uri    = line;
+
+  while (*req_uri && !isspace(*req_uri & 255))
+    req_uri ++;
+
+  if (!*req_uri)
+    return (HTTP_STATE_ERROR);
+
+  *req_uri++ = '\0';
+
+  while (*req_uri && isspace(*req_uri & 255))
+    req_uri ++;
+
+  req_version = req_uri;
+
+  while (*req_version && !isspace(*req_version & 255))
+    req_version ++;
+
+  if (!*req_version)
+    return (HTTP_STATE_ERROR);
+
+  *req_version++ = '\0';
+
+  while (*req_version && isspace(*req_version & 255))
+    req_version ++;
+
+ /*
+  * Validate...
+  */
+
+  if (!strcmp(req_method, "OPTIONS"))
+    http->state = HTTP_STATE_OPTIONS;
+  else if (!strcmp(req_method, "GET"))
+    http->state = HTTP_STATE_GET;
+  else if (!strcmp(req_method, "HEAD"))
+    http->state = HTTP_STATE_HEAD;
+  else if (!strcmp(req_method, "POST"))
+    http->state = HTTP_STATE_POST;
+  else if (!strcmp(req_method, "PUT"))
+    http->state = HTTP_STATE_PUT;
+  else if (!strcmp(req_method, "DELETE"))
+    http->state = HTTP_STATE_DELETE;
+  else if (!strcmp(req_method, "TRACE"))
+    http->state = HTTP_STATE_TRACE;
+  else if (!strcmp(req_method, "CONNECT"))
+    http->state = HTTP_STATE_CONNECT;
+  else
+    return (HTTP_STATE_UNKNOWN_METHOD);
+
+  if (!strcmp(req_version, "HTTP/1.0"))
+  {
+    http->version    = HTTP_VERSION_1_0;
+    http->keep_alive = HTTP_KEEPALIVE_OFF;
+  }
+  else if (!strcmp(req_version, "HTTP/1.1"))
+  {
+    http->version    = HTTP_VERSION_1_1;
+    http->keep_alive = HTTP_KEEPALIVE_ON;
+  }
+  else
+    return (HTTP_STATE_UNKNOWN_VERSION);
+
+  strlcpy(uri, req_uri, urilen);
+
+  return (http->state);
 }
 
 
@@ -3552,14 +3645,126 @@ _httpWriteGNUTLS(
  * @since CUPS 1.7@
  */
 
-http_state_t                           /* O - New HTTP connection state */
+int                                    /* O - 0 on success, -1 on error */
 httpWriteResponse(http_t        *http, /* I - HTTP connection */
                  http_status_t status) /* I - Status code */
 {
-  (void)http;
-  (void)status;
+ /*
+  * Range check input...
+  */
+
+  if (!http || status < HTTP_CONTINUE)
+    return (-1);
+
+ /*
+  * Set the various standard fields if they aren't already...
+  */
 
-  return (HTTP_STATE_ERROR);
+  if (!http->fields[HTTP_FIELD_DATE][0])
+    httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
+
+  if (status >= HTTP_BAD_REQUEST && http->keep_alive)
+  {
+    http->keep_alive = 0;
+    httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
+  }
+
+  if (http->version == HTTP_VERSION_1_1)
+  {
+    if (!http->fields[HTTP_FIELD_CONNECTION][0])
+    {
+      if (http->keep_alive)
+       httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
+      else
+       httpSetField(http, HTTP_FIELD_CONNECTION, "close");
+    }
+
+    if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE][0])
+      httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
+  }
+
+#ifdef HAVE_SSL
+  if (status == HTTP_UPGRADE_REQUIRED)
+  {
+    if (!http->fields[HTTP_FIELD_CONNECTION][0])
+      httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
+
+    if (!http->fields[HTTP_FIELD_UPGRADE][0])
+      httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
+  }
+#endif /* HAVE_SSL */
+
+  if (!http->server)
+    httpSetField(http, HTTP_FIELD_SERVER, CUPS_MINIMAL);
+
+ /*
+  * Send the response header...
+  */
+
+  http->data_encoding = HTTP_ENCODING_FIELDS;
+
+  if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100,
+                 http->version % 100, (int)status, httpStatus(status)) < 0)
+  {
+    http->status        = HTTP_STATUS_ERROR;
+    http->data_encoding = HTTP_ENCODING_LENGTH;
+    return (-1);
+  }
+
+  if (status != HTTP_CONTINUE)
+  {
+   /*
+    * 100 Continue doesn't have the rest of the response headers...
+    */
+
+    int                i;                      /* Looping var */
+    const char *value;                 /* Field value */
+
+    for (i = 0; i < HTTP_FIELD_MAX; i ++)
+    {
+      if ((value = httpGetField(http, i)) != NULL && *value)
+      {
+       if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
+       {
+         http->status        = HTTP_STATUS_ERROR;
+         http->data_encoding = HTTP_ENCODING_LENGTH;
+         return (-1);
+       }
+      }
+    }
+
+    if (http->cookie)
+    {
+      if (httpPrintf(http, "Set-Cookie: %s path=/%s\r\n", http->cookie,
+                     http->tls ? " secure" : "") < 1)
+      {
+       http->status        = HTTP_ERROR;
+       http->data_encoding = HTTP_ENCODING_LENGTH;
+       return (-1);
+      }
+    }
+  }
+
+  if (httpWrite2(http, "\r\n", 2) < 2)
+  {
+    http->status        = HTTP_ERROR;
+    http->data_encoding = HTTP_ENCODING_LENGTH;
+    return (-1);
+  }
+
+  if (httpFlushWrite(http) < 0)
+  {
+    http->status        = HTTP_ERROR;
+    http->data_encoding = HTTP_ENCODING_LENGTH;
+    return (-1);
+  }
+
+  (void)httpGetLength2(http);
+
+  http_content_coding_start(http,
+                           httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
+
+  return (0);
 }
 
 
@@ -4009,16 +4214,16 @@ http_read_ssl(http_t *http,             /* I - Connection to server */
  * 'http_send()' - Send a request with all fields and the trailing blank line.
  */
 
-static int                     /* O - 0 on success, non-zero on error */
-http_send(http_t       *http,  /* I - Connection to server */
-          http_state_t request,        /* I - Request code */
-         const char   *uri)    /* I - URI */
+static int                             /* O - 0 on success, non-zero on error */
+http_send(http_t       *http,          /* I - Connection to server */
+          http_state_t request,                /* I - Request code */
+         const char   *uri)            /* I - URI */
 {
-  int          i;              /* Looping var */
-  char         buf[1024];      /* Encoded URI buffer */
-  const char   *value;         /* Field value */
-  static const char * const codes[] =
-               {               /* Request code strings */
+  int          i;                      /* Looping var */
+  char         buf[1024];              /* Encoded URI buffer */
+  const char   *value;                 /* Field value */
+  static const char * const codes[] =  /* Request code strings */
+               {
                  NULL,
                  "OPTIONS",
                  "GET",
index 2a117f070034dc310b52b93f635c81c624bb7572..cbdb003b6e600b03c2e34d6cb4c170680483d4b7 100644 (file)
@@ -126,17 +126,30 @@ typedef enum http_auth_e          /**** HTTP authentication types ****/
 
 typedef enum http_encoding_e           /**** HTTP transfer encoding values ****/
 {
-  HTTP_ENCODE_LENGTH,                  /* Data is sent with Content-Length */
-  HTTP_ENCODE_CHUNKED,                 /* Data is chunked */
-  HTTP_ENCODE_FIELDS                   /* Sending HTTP fields */
+  HTTP_ENCODING_LENGTH,                        /* Data is sent with Content-Length */
+  HTTP_ENCODING_CHUNKED,               /* Data is chunked */
+  HTTP_ENCODING_FIELDS                 /* Sending HTTP fields */
+
+#  ifndef CUPS_NO_DEPRECATED
+#    define HTTP_ENCODE_LENGTH HTTP_ENCODING_LENGTH
+#    define HTTP_ENCODE_CHUNKED        HTTP_ENCODING_CHUNKED
+#    define HTTP_ENCODE_FIELDS HTTP_ENCODING_FIELDS
+#  endif /* !CUPS_NO_DEPRECATED */
 } http_encoding_t;
 
 typedef enum http_encryption_e         /**** HTTP encryption values ****/
 {
-  HTTP_ENCRYPT_IF_REQUESTED,           /* Encrypt if requested (TLS upgrade) */
-  HTTP_ENCRYPT_NEVER,                  /* Never encrypt */
-  HTTP_ENCRYPT_REQUIRED,               /* Encryption is required (TLS upgrade) */
-  HTTP_ENCRYPT_ALWAYS                  /* Always encrypt (SSL) */
+  HTTP_ENCRYPTION_IF_REQUESTED,                /* Encrypt if requested (TLS upgrade) */
+  HTTP_ENCRYPTION_NEVER,               /* Never encrypt */
+  HTTP_ENCRYPTION_REQUIRED,            /* Encryption is required (TLS upgrade) */
+  HTTP_ENCRYPTION_ALWAYS               /* Always encrypt (SSL) */
+
+#  ifndef CUPS_NO_DEPRECATED
+#    define HTTP_ENCRYPT_IF_REQUESTED  HTTP_ENCRYPTION_IF_REQUESTED
+#    define HTTP_ENCRYPT_NEVER         HTTP_ENCRYPTION_NEVER
+#    define HTTP_ENCRYPT_REQUIRED      HTTP_ENCRYPTION_REQUIRED
+#    define HTTP_ENCRYPT_ALWAYS                HTTP_ENCRYPTION_ALWAYS
+#  endif /* !CUPS_NO_DEPRECATED */
 } http_encryption_t;
 
 typedef enum http_field_e              /**** HTTP field names ****/
@@ -186,91 +199,180 @@ typedef enum http_state_e                /**** HTTP state values; states
                                         ****/
 {
   HTTP_STATE_ERROR = -1,               /* Error on socket */
-  HTTP_WAITING,                                /* Waiting for command */
-  HTTP_OPTIONS,                                /* OPTIONS command, waiting for blank line */
-  HTTP_GET,                            /* GET command, waiting for blank line */
-  HTTP_GET_SEND,                       /* GET command, sending data */
-  HTTP_HEAD,                           /* HEAD command, waiting for blank line */
-  HTTP_POST,                           /* POST command, waiting for blank line */
-  HTTP_POST_RECV,                      /* POST command, receiving data */
-  HTTP_POST_SEND,                      /* POST command, sending data */
-  HTTP_PUT,                            /* PUT command, waiting for blank line */
-  HTTP_PUT_RECV,                       /* PUT command, receiving data */
-  HTTP_DELETE,                         /* DELETE command, waiting for blank line */
-  HTTP_TRACE,                          /* TRACE command, waiting for blank line */
-  HTTP_CLOSE,                          /* CLOSE command, waiting for blank line */
-  HTTP_STATUS,                         /* Command complete, sending status */
-  HTTP_STATE_UNKNOWN                   /* Unknown request method, waiting for blank line */
+  HTTP_STATE_WAITING,                  /* Waiting for command */
+  HTTP_STATE_OPTIONS,                  /* OPTIONS command, waiting for blank line */
+  HTTP_STATE_GET,                      /* GET command, waiting for blank line */
+  HTTP_STATE_GET_SEND,                 /* GET command, sending data */
+  HTTP_STATE_HEAD,                     /* HEAD command, waiting for blank line */
+  HTTP_STATE_POST,                     /* POST command, waiting for blank line */
+  HTTP_STATE_POST_RECV,                        /* POST command, receiving data */
+  HTTP_STATE_POST_SEND,                        /* POST command, sending data */
+  HTTP_STATE_PUT,                      /* PUT command, waiting for blank line */
+  HTTP_STATE_PUT_RECV,                 /* PUT command, receiving data */
+  HTTP_STATE_DELETE,                   /* DELETE command, waiting for blank line */
+  HTTP_STATE_TRACE,                    /* TRACE command, waiting for blank line */
+  HTTP_STATE_CONNECT,                  /* CONNECT command, waiting for blank line */
+  HTTP_STATE_STATUS,                   /* Command complete, sending status */
+  HTTP_STATE_UNKNOWN_METHOD,           /* Unknown request method, waiting for blank line */
+  HTTP_STATE_UNKNOWN_VERSION           /* Unknown request method, waiting for blank line */
+
+#  ifndef CUPS_NO_DEPRECATED
+/* Old names for this enumeration */
+#    define HTTP_WAITING       HTTP_STATE_WAITING
+#    define HTTP_OPTIONS       HTTP_STATE_OPTIONS
+#    define HTTP_GET           HTTP_STATE_GET
+#    define HTTP_GET_SEND      HTTP_STATE_GET_SEND
+#    define HTTP_HEAD          HTTP_STATE_HEAD
+#    define HTTP_POST          HTTP_STATE_POST
+#    define HTTP_POST_RECV     HTTP_STATE_POST_RECV
+#    define HTTP_POST_SEND     HTTP_STATE_POST_SEND
+#    define HTTP_PUT           HTTP_STATE_PUT
+#    define HTTP_PUT_RECV      HTTP_STATE_PUT_RECV
+#    define HTTP_DELETE                HTTP_STATE_DELETE
+#    define HTTP_TRACE         HTTP_STATE_TRACE
+#    define HTTP_CLOSE         HTTP_STATE_CONNECT
+#    define HTTP_STATUS                HTTP_STATE_STATUS
+#  endif /* !CUPS_NO_DEPRECATED */
 } http_state_t;
 
 typedef enum http_status_e             /**** HTTP status codes ****/
 {
-  HTTP_ERROR = -1,                     /* An error response from httpXxxx() */
-
-  HTTP_CONTINUE = 100,                 /* Everything OK, keep going... */
-  HTTP_SWITCHING_PROTOCOLS,            /* HTTP upgrade to TLS/SSL */
-
-  HTTP_OK = 200,                       /* OPTIONS/GET/HEAD/POST/TRACE command was successful */
-  HTTP_CREATED,                                /* PUT command was successful */
-  HTTP_ACCEPTED,                       /* DELETE command was successful */
-  HTTP_NOT_AUTHORITATIVE,              /* Information isn't authoritative */
-  HTTP_NO_CONTENT,                     /* Successful command, no new data */
-  HTTP_RESET_CONTENT,                  /* Content was reset/recreated */
-  HTTP_PARTIAL_CONTENT,                        /* Only a partial file was recieved/sent */
-
-  HTTP_MULTIPLE_CHOICES = 300,         /* Multiple files match request */
-  HTTP_MOVED_PERMANENTLY,              /* Document has moved permanently */
-  HTTP_MOVED_TEMPORARILY,              /* Document has moved temporarily */
-  HTTP_SEE_OTHER,                      /* See this other link... */
-  HTTP_NOT_MODIFIED,                   /* File not modified */
-  HTTP_USE_PROXY,                      /* Must use a proxy to access this URI */
-
-  HTTP_BAD_REQUEST = 400,              /* Bad request */
-  HTTP_UNAUTHORIZED,                   /* Unauthorized to access host */
-  HTTP_PAYMENT_REQUIRED,               /* Payment required */
-  HTTP_FORBIDDEN,                      /* Forbidden to access this URI */
-  HTTP_NOT_FOUND,                      /* URI was not found */
-  HTTP_METHOD_NOT_ALLOWED,             /* Method is not allowed */
-  HTTP_NOT_ACCEPTABLE,                 /* Not Acceptable */
-  HTTP_PROXY_AUTHENTICATION,           /* Proxy Authentication is Required */
-  HTTP_REQUEST_TIMEOUT,                        /* Request timed out */
-  HTTP_CONFLICT,                       /* Request is self-conflicting */
-  HTTP_GONE,                           /* Server has gone away */
-  HTTP_LENGTH_REQUIRED,                        /* A content length or encoding is required */
-  HTTP_PRECONDITION,                   /* Precondition failed */
-  HTTP_REQUEST_TOO_LARGE,              /* Request entity too large */
-  HTTP_URI_TOO_LONG,                   /* URI too long */
-  HTTP_UNSUPPORTED_MEDIATYPE,          /* The requested media type is unsupported */
-  HTTP_REQUESTED_RANGE,                        /* The requested range is not satisfiable */
-  HTTP_EXPECTATION_FAILED,             /* The expectation given in an Expect header field was not met */
-  HTTP_UPGRADE_REQUIRED = 426,         /* Upgrade to SSL/TLS required */
-
-  HTTP_SERVER_ERROR = 500,             /* Internal server error */
-  HTTP_NOT_IMPLEMENTED,                        /* Feature not implemented */
-  HTTP_BAD_GATEWAY,                    /* Bad gateway */
-  HTTP_SERVICE_UNAVAILABLE,            /* Service is unavailable */
-  HTTP_GATEWAY_TIMEOUT,                        /* Gateway connection timed out */
-  HTTP_NOT_SUPPORTED,                  /* HTTP version not supported */
-
-  HTTP_AUTHORIZATION_CANCELED = 1000,  /* User canceled authorization @since CUPS 1.4@ */
-  HTTP_PKI_ERROR,                      /* Error negotiating a secure connection @since CUPS 1.5/OS X 10.7@ */
-  HTTP_WEBIF_DISABLED                  /* Web interface is disabled @private@ */
+  HTTP_STATUS_ERROR = -1,              /* An error response from httpXxxx() */
+
+  HTTP_STATUS_CONTINUE = 100,          /* Everything OK, keep going... */
+  HTTP_STATUS_SWITCHING_PROTOCOLS,     /* HTTP upgrade to TLS/SSL */
+
+  HTTP_STATUS_OK = 200,                        /* OPTIONS/GET/HEAD/POST/TRACE command was successful */
+  HTTP_STATUS_CREATED,                 /* PUT command was successful */
+  HTTP_STATUS_ACCEPTED,                        /* DELETE command was successful */
+  HTTP_STATUS_NOT_AUTHORITATIVE,       /* Information isn't authoritative */
+  HTTP_STATUS_NO_CONTENT,              /* Successful command, no new data */
+  HTTP_STATUS_RESET_CONTENT,           /* Content was reset/recreated */
+  HTTP_STATUS_PARTIAL_CONTENT,         /* Only a partial file was recieved/sent */
+
+  HTTP_STATUS_MULTIPLE_CHOICES = 300,  /* Multiple files match request */
+  HTTP_STATUS_MOVED_PERMANENTLY,       /* Document has moved permanently */
+  HTTP_STATUS_MOVED_TEMPORARILY,       /* Document has moved temporarily */
+  HTTP_STATUS_SEE_OTHER,               /* See this other link... */
+  HTTP_STATUS_NOT_MODIFIED,            /* File not modified */
+  HTTP_STATUS_USE_PROXY,               /* Must use a proxy to access this URI */
+
+  HTTP_STATUS_BAD_REQUEST = 400,       /* Bad request */
+  HTTP_STATUS_UNAUTHORIZED,            /* Unauthorized to access host */
+  HTTP_STATUS_PAYMENT_REQUIRED,                /* Payment required */
+  HTTP_STATUS_FORBIDDEN,               /* Forbidden to access this URI */
+  HTTP_STATUS_NOT_FOUND,               /* URI was not found */
+  HTTP_STATUS_METHOD_NOT_ALLOWED,      /* Method is not allowed */
+  HTTP_STATUS_NOT_ACCEPTABLE,          /* Not Acceptable */
+  HTTP_STATUS_PROXY_AUTHENTICATION,    /* Proxy Authentication is Required */
+  HTTP_STATUS_REQUEST_TIMEOUT,         /* Request timed out */
+  HTTP_STATUS_CONFLICT,                        /* Request is self-conflicting */
+  HTTP_STATUS_GONE,                    /* Server has gone away */
+  HTTP_STATUS_LENGTH_REQUIRED,         /* A content length or encoding is required */
+  HTTP_STATUS_PRECONDITION,            /* Precondition failed */
+  HTTP_STATUS_REQUEST_TOO_LARGE,       /* Request entity too large */
+  HTTP_STATUS_URI_TOO_LONG,            /* URI too long */
+  HTTP_STATUS_UNSUPPORTED_MEDIATYPE,   /* The requested media type is unsupported */
+  HTTP_STATUS_REQUESTED_RANGE,         /* The requested range is not satisfiable */
+  HTTP_STATUS_EXPECTATION_FAILED,      /* The expectation given in an Expect header field was not met */
+  HTTP_STATUS_UPGRADE_REQUIRED = 426,  /* Upgrade to SSL/TLS required */
+
+  HTTP_STATUS_SERVER_ERROR = 500,      /* Internal server error */
+  HTTP_STATUS_NOT_IMPLEMENTED,         /* Feature not implemented */
+  HTTP_STATUS_BAD_GATEWAY,             /* Bad gateway */
+  HTTP_STATUS_SERVICE_UNAVAILABLE,     /* Service is unavailable */
+  HTTP_STATUS_GATEWAY_TIMEOUT,         /* Gateway connection timed out */
+  HTTP_STATUS_NOT_SUPPORTED,           /* HTTP version not supported */
+
+  CUPS_STATUS_AUTHORIZATION_CANCELED = 1000,
+                                       /* User canceled authorization @since CUPS 1.4@ */
+  CUPS_STATUS_PKI_ERROR,               /* Error negotiating a secure connection @since CUPS 1.5/OS X 10.7@ */
+  CUPS_STATUS_WEBIF_DISABLED           /* Web interface is disabled @private@ */
+
+#  ifndef CUPS_NO_DEPRECATED
+/* Old names for this enumeration */
+#    define HTTP_ERROR                 HTTP_STATUS_ERROR
+
+#    define HTTP_CONTINUE              HTTP_STATUS_CONTINUE
+#    define HTTP_SWITCHING_PROTOCOLS   HTTP_STATUS_SWITCHING_PROTOCOLS
+
+#    define HTTP_OK                    HTTP_STATUS_OK
+#    define HTTP_CREATED               HTTP_STATUS_CREATED
+#    define HTTP_ACCEPTED              HTTP_STATUS_ACCEPTED
+#    define HTTP_NOT_AUTHORITATIVE     HTTP_STATUS_NOT_AUTHORITATIVE
+#    define HTTP_NO_CONTENT            HTTP_STATUS_NO_CONTENT
+#    define HTTP_RESET_CONTENT         HTTP_STATUS_RESET_CONTENT
+#    define HTTP_PARTIAL_CONTENT       HTTP_STATUS_PARTIAL_CONTENT
+
+#    define HTTP_MULTIPLE_CHOICES      HTTP_STATUS_MULTIPLE_CHOICES
+#    define HTTP_MOVED_PERMANENTLY     HTTP_STATUS_MOVED_PERMANENTLY
+#    define HTTP_MOVED_TEMPORARILY     HTTP_STATUS_MOVED_TEMPORARILY
+#    define HTTP_SEE_OTHER             HTTP_STATUS_SEE_OTHER
+#    define HTTP_NOT_MODIFIED          HTTP_STATUS_NOT_MODIFIED
+#    define HTTP_USE_PROXY             HTTP_STATUS_USE_PROXY
+
+#    define HTTP_BAD_REQUEST           HTTP_STATUS_BAD_REQUEST
+#    define HTTP_UNAUTHORIZED          HTTP_STATUS_UNAUTHORIZED
+#    define HTTP_PAYMENT_REQUIRED      HTTP_STATUS_PAYMENT_REQUIRED
+#    define HTTP_FORBIDDEN             HTTP_STATUS_FORBIDDEN
+#    define HTTP_NOT_FOUND             HTTP_STATUS_NOT_FOUND
+#    define HTTP_METHOD_NOT_ALLOWED    HTTP_STATUS_METHOD_NOT_ALLOWED
+#    define HTTP_NOT_ACCEPTABLE                HTTP_STATUS_NOT_ACCEPTABLE
+#    define HTTP_PROXY_AUTHENTICATION  HTTP_STATUS_PROXY_AUTHENTICATION
+#    define HTTP_REQUEST_TIMEOUT       HTTP_STATUS_REQUEST_TIMEOUT
+#    define HTTP_CONFLICT              HTTP_STATUS_CONFLICT
+#    define HTTP_GONE                  HTTP_STATUS_GONE
+#    define HTTP_LENGTH_REQUIRED       HTTP_STATUS_LENGTH_REQUIRED
+#    define HTTP_PRECONDITION          HTTP_STATUS_PRECONDITION
+#    define HTTP_REQUEST_TOO_LARGE     HTTP_STATUS_REQUEST_TOO_LARGE
+#    define HTTP_URI_TOO_LONG          HTTP_STATUS_URI_TOO_LONG
+#    define HTTP_UNSUPPORTED_MEDIATYPE HTTP_STATUS_UNSUPPORTED_MEDIATYPE
+#    define HTTP_REQUESTED_RANGE       HTTP_STATUS_REQUESTED_RANGE
+#    define HTTP_EXPECTATION_FAILED    HTTP_STATUS_EXPECTATION_FAILED
+#    define HTTP_UPGRADE_REQUIRED      HTTP_STATUS_UPGRADE_REQUIRED
+
+#    define HTTP_SERVER_ERROR          HTTP_STATUS_SERVER_ERROR
+#    define HTTP_NOT_IMPLEMENTED       HTTP_STATUS_NOT_IMPLEMENTED
+#    define HTTP_BAD_GATEWAY           HTTP_STATUS_BAD_GATEWAY
+#    define HTTP_SERVICE_UNAVAILABLE   HTTP_STATUS_SERVICE_UNAVAILABLE
+#    define HTTP_GATEWAY_TIMEOUT       HTTP_STATUS_GATEWAY_TIMEOUT
+#    define HTTP_NOT_SUPPORTED         HTTP_STATUS_NOT_SUPPORTED
+
+#    define HTTP_AUTHORIZATION_CANCELED        CUPS_STATUS_AUTHORIZATION_CANCELED
+#    define HTTP_PKI_ERROR             CUPS_STATUS_PKI_ERROR
+#    define HTTP_WEBIF_DISABLED                CUPS_STATUS_WEBIF_DISABLED
+#  endif /* !CUPS_NO_DEPRECATED */
 } http_status_t;
 
 typedef enum http_uri_status_e         /**** URI separation status @since CUPS 1.2@ ****/
 {
-  HTTP_URI_OVERFLOW = -8,              /* URI buffer for httpAssembleURI is too small */
-  HTTP_URI_BAD_ARGUMENTS = -7,         /* Bad arguments to function (error) */
-  HTTP_URI_BAD_RESOURCE = -6,          /* Bad resource in URI (error) */
-  HTTP_URI_BAD_PORT = -5,              /* Bad port number in URI (error) */
-  HTTP_URI_BAD_HOSTNAME = -4,          /* Bad hostname in URI (error) */
-  HTTP_URI_BAD_USERNAME = -3,          /* Bad username in URI (error) */
-  HTTP_URI_BAD_SCHEME = -2,            /* Bad scheme in URI (error) */
-  HTTP_URI_BAD_URI = -1,               /* Bad/empty URI (error) */
-  HTTP_URI_OK = 0,                     /* URI decoded OK */
-  HTTP_URI_MISSING_SCHEME,             /* Missing scheme in URI (warning) */
-  HTTP_URI_UNKNOWN_SCHEME,             /* Unknown scheme in URI (warning) */
-  HTTP_URI_MISSING_RESOURCE            /* Missing resource in URI (warning) */
+  HTTP_URI_STATUS_OVERFLOW = -8,       /* URI buffer for httpAssembleURI is too small */
+  HTTP_URI_STATUS_BAD_ARGUMENTS = -7,  /* Bad arguments to function (error) */
+  HTTP_URI_STATUS_BAD_RESOURCE = -6,   /* Bad resource in URI (error) */
+  HTTP_URI_STATUS_BAD_PORT = -5,       /* Bad port number in URI (error) */
+  HTTP_URI_STATUS_BAD_HOSTNAME = -4,   /* Bad hostname in URI (error) */
+  HTTP_URI_STATUS_BAD_USERNAME = -3,   /* Bad username in URI (error) */
+  HTTP_URI_STATUS_BAD_SCHEME = -2,     /* Bad scheme in URI (error) */
+  HTTP_URI_STATUS_BAD_URI = -1,                /* Bad/empty URI (error) */
+  HTTP_URI_STATUS_OK = 0,              /* URI decoded OK */
+  HTTP_URI_STATUS_MISSING_SCHEME,      /* Missing scheme in URI (warning) */
+  HTTP_URI_STATUS_UNKNOWN_SCHEME,      /* Unknown scheme in URI (warning) */
+  HTTP_URI_STATUS_MISSING_RESOURCE     /* Missing resource in URI (warning) */
+
+#  ifndef CUPS_NO_DEPRECATED
+#    define HTTP_URI_OVERFLOW          HTTP_URI_STATUS_OVERFLOW
+#    define HTTP_URI_BAD_ARGUMENTS     HTTP_URI_STATUS_BAD_ARGUMENTS
+#    define HTTP_URI_BAD_RESOURCE      HTTP_URI_STATUS_BAD_RESOURCE
+#    define HTTP_URI_BAD_PORT          HTTP_URI_STATUS_BAD_PORT
+#    define HTTP_URI_BAD_HOSTNAME      HTTP_URI_STATUS_BAD_HOSTNAME
+#    define HTTP_URI_BAD_USERNAME      HTTP_URI_STATUS_BAD_USERNAME
+#    define HTTP_URI_BAD_SCHEME                HTTP_URI_STATUS_BAD_SCHEME
+#    define HTTP_URI_BAD_URI           HTTP_URI_STATUS_BAD_URI
+#    define HTTP_URI_OK                        HTTP_URI_STATUS_OK
+#    define HTTP_URI_MISSING_SCHEME    HTTP_URI_STATUS_MISSING_SCHEME
+#    define HTTP_URI_UNKNOWN_SCHEME    HTTP_URI_STATUS_UNKNOWN_SCHEME
+#    define HTTP_URI_MISSING_RESOURCE  HTTP_URI_STATUS_MISSING_RESOURCE
+#  endif /* !CUPS_NO_DEPRECATED */
 } http_uri_status_t;
 
 typedef enum http_uri_coding_e         /**** URI en/decode flags ****/
@@ -286,9 +388,15 @@ typedef enum http_uri_coding_e             /**** URI en/decode flags ****/
 
 typedef enum http_version_e            /**** HTTP version numbers ****/
 {
-  HTTP_0_9 = 9,                                /* HTTP/0.9 */
-  HTTP_1_0 = 100,                      /* HTTP/1.0 */
-  HTTP_1_1 = 101                       /* HTTP/1.1 */
+  HTTP_VERSION_0_9 = 9,                        /* HTTP/0.9 */
+  HTTP_VERSION_1_0 = 100,              /* HTTP/1.0 */
+  HTTP_VERSION_1_1 = 101               /* HTTP/1.1 */
+
+#  ifndef CUPS_NO_DEPRECATED
+#    define HTTP_0_9   HTTP_VERSION_0_9
+#    define HTTP_1_0   HTTP_VERSION_1_0
+#    define HTTP_1_1   HTTP_VERSION_1_1
+#  endif /* !CUPS_NO_DEPRECATED */
 } http_version_t;
 
 typedef union _http_addr_u             /**** Socket address union, which
index f24d50b7cbc5f5516573fe0c6a6604091e0adf9a..74c82d745be26277bd4fbfdf201e33e7d3c85fec 100644 (file)
@@ -33,6 +33,8 @@
  *   ippAddResolutions()    - Add resolution values to an IPP message.
  *   ippAddSeparator()     - Add a group separator to an IPP message.
  *   ippAddString()        - Add a language-encoded string to an IPP message.
+ *   ippAddStringf()       - Add a formatted string to an IPP message.
+ *   ippAddStringfv()      - Add a formatted string to an IPP message.
  *   ippAddStrings()       - Add language-encoded strings to an IPP message.
  *   ippCopyAttribute()     - Copy an attribute.
  *   ippCopyAttributes()    - Copy attributes from one IPP message to another.
  *   ippGetBoolean()       - Get a boolean value for an attribute.
  *   ippGetCollection()     - Get a collection value for an attribute.
  *   ippGetCount()         - Get the number of values in an attribute.
- *   ippGetDate()           - Get a date value for an attribute.
+ *   ippGetDate()          - Get a date value for an attribute.
  *   ippGetGroupTag()      - Get the group associated with an attribute.
  *   ippGetInteger()       - Get the integer/enum value for an attribute.
  *   ippGetName()          - Get the attribute name.
  *   ippGetOperation()     - Get the operation ID in an IPP message.
- *   ippGetRange()          - Get a rangeOfInteger value from an attribute.
+ *   ippGetRange()         - Get a rangeOfInteger value from an attribute.
  *   ippGetRequestId()     - Get the request ID from an IPP message.
  *   ippGetResolution()     - Get a resolution value for an attribute.
+ *   ippGetState()         - Get the IPP message state.
  *   ippGetStatusCode()     - Get the status code from an IPP response or event
  *                           message.
  *   ippGetString()        - Get the string and optionally the language code
  *   ippNextAttribute()     - Return the next attribute in the message.
  *   ippNew()              - Allocate a new IPP message.
  *   ippNewRequest()       - Allocate a new IPP request message.
+ *   ippNewResponse()      - Allocate a new IPP response message.
  *   ippRead()             - Read data for an IPP message from a HTTP
  *                           connection.
  *   ippReadFile()         - Read data for an IPP message from a file.
  *   ippReadIO()           - Read data for an IPP message.
  *   ippSetBoolean()       - Set a boolean value in an attribute.
  *   ippSetCollection()     - Set a collection value in an attribute.
- *   ippSetDate()           - Set a date value in an attribute.
+ *   ippSetDate()          - Set a date value in an attribute.
  *   ippSetGroupTag()      - Set the group tag of an attribute.
  *   ippSetInteger()       - Set an integer or enum value in an attribute.
  *   ippSetName()          - Set the name of an attribute.
@@ -80,7 +84,7 @@
  *   ippSetRange()         - Set a rangeOfInteger value in an attribute.
  *   ippSetRequestId()     - Set the request ID in an IPP message.
  *   ippSetResolution()     - Set a resolution value in an attribute.
- *   ippSetState()          - Set the current state of the IPP message.
+ *   ippSetState()         - Set the current state of the IPP message.
  *   ippSetStatusCode()     - Set the status code in an IPP response or event
  *                           message.
  *   ippSetString()        - Set a string value in an attribute.
@@ -196,8 +200,8 @@ _cupsBufferRelease(char *b)         /* I - Buffer to release */
 /*
  * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -242,8 +246,8 @@ ippAddBoolean(ipp_t      *ipp,              /* I - IPP message */
 /*
  * 'ippAddBooleans()' - Add an array of boolean values.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -299,8 +303,8 @@ ippAddBooleans(ipp_t      *ipp,             /* I - IPP message */
 /*
  * 'ippAddCollection()' - Add a collection value.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -350,8 +354,8 @@ ippAddCollection(ipp_t      *ipp,   /* I - IPP message */
 /*
  * 'ippAddCollections()' - Add an array of collection values.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -414,8 +418,8 @@ ippAddCollections(
 /*
  * 'ippAddDate()' - Add a date attribute to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -460,8 +464,8 @@ ippAddDate(ipp_t             *ipp,  /* I - IPP message */
 /*
  * 'ippAddInteger()' - Add a integer attribute to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -528,8 +532,8 @@ ippAddInteger(ipp_t      *ipp,              /* I - IPP message */
 /*
  * 'ippAddIntegers()' - Add an array of integer values.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -600,8 +604,8 @@ ippAddIntegers(ipp_t      *ipp,             /* I - IPP message */
 /*
  * 'ippAddOctetString()' - Add an octetString value to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -658,8 +662,8 @@ ippAddOctetString(ipp_t      *ipp,  /* I - IPP message */
 /*
  * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -714,8 +718,8 @@ ippAddOutOfBand(ipp_t      *ipp,    /* I - IPP message */
 /*
  * 'ippAddRange()' - Add a range of values to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -765,8 +769,8 @@ ippAddRange(ipp_t      *ipp,                /* I - IPP message */
 /*
  * 'ippAddRanges()' - Add ranges of values to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -826,8 +830,8 @@ ippAddRanges(ipp_t      *ipp,               /* I - IPP message */
 /*
  * 'ippAddResolution()' - Add a resolution value to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -879,8 +883,8 @@ ippAddResolution(ipp_t      *ipp,   /* I - IPP message */
 /*
  * 'ippAddResolutions()' - Add resolution values to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -943,8 +947,8 @@ ippAddResolutions(ipp_t      *ipp,  /* I - IPP message */
 /*
  * 'ippAddSeparator()' - Add a group separator to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  */
 
 ipp_attribute_t *                      /* O - New attribute */
@@ -970,8 +974,8 @@ ippAddSeparator(ipp_t *ipp)         /* I - IPP message */
 /*
  * 'ippAddString()' - Add a language-encoded string to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -1084,11 +1088,226 @@ ippAddString(ipp_t      *ipp,          /* I - IPP message */
 }
 
 
+/*
+ * 'ippAddStringf()' - Add a formatted string to an IPP message.
+ *
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
+ *
+ * The @code group@ parameter specifies the IPP attribute group tag: none
+ * (@code IPP_TAG_ZERO@, for member attributes), document
+ * (@code IPP_TAG_DOCUMENT@), event notification
+ * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
+ * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
+ * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
+ *
+ * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
+ * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
+ * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
+ * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
+ * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
+ * (@code IPP_TAG_URISCHEME@).
+ *
+ * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
+ * and textWithLanguage string values and must be @code NULL@ for all other
+ * string values.
+ *
+ * The @code format@ parameter uses formatting characters compatible with the
+ * printf family of standard functions.  Additional arguments follow it as
+ * needed.  The formatted string is truncated as needed to the maximum length of
+ * the corresponding value type.
+ *
+ * @since CUPS 1.7@
+ */
+
+ipp_attribute_t *                      /* O - New attribute */
+ippAddStringf(ipp_t      *ipp,         /* I - IPP message */
+              ipp_tag_t  group,                /* I - IPP group */
+             ipp_tag_t  value_tag,     /* I - Type of attribute */
+             const char *name,         /* I - Name of attribute */
+             const char *language,     /* I - Language code (@code NULL@ for default) */
+             const char *format,       /* I - Printf-style format string */
+             ...)                      /* I - Additional arguments as needed */
+{
+  ipp_attribute_t      *attr;          /* New attribute */
+  va_list              ap;             /* Argument pointer */
+
+
+  va_start(ap, format);
+  attr = ippAddStringfv(ipp, group, value_tag, name, language, format, ap);
+  va_end(ap);
+
+  return (attr);
+}
+
+
+/*
+ * 'ippAddStringfv()' - Add a formatted string to an IPP message.
+ *
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
+ *
+ * The @code group@ parameter specifies the IPP attribute group tag: none
+ * (@code IPP_TAG_ZERO@, for member attributes), document
+ * (@code IPP_TAG_DOCUMENT@), event notification
+ * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
+ * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
+ * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
+ *
+ * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
+ * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
+ * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
+ * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
+ * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
+ * (@code IPP_TAG_URISCHEME@).
+ *
+ * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
+ * and textWithLanguage string values and must be @code NULL@ for all other
+ * string values.
+ *
+ * The @code format@ parameter uses formatting characters compatible with the
+ * printf family of standard functions.  Additional arguments are passed in the
+ * stdarg pointer @code ap@.  The formatted string is truncated as needed to the
+ * maximum length of the corresponding value type.
+ *
+ * @since CUPS 1.7@
+ */
+
+ipp_attribute_t *                      /* O - New attribute */
+ippAddStringfv(ipp_t      *ipp,                /* I - IPP message */
+               ipp_tag_t  group,       /* I - IPP group */
+              ipp_tag_t  value_tag,    /* I - Type of attribute */
+              const char *name,        /* I - Name of attribute */
+              const char *language,    /* I - Language code (@code NULL@ for default) */
+              const char *format,      /* I - Printf-style format string */
+              va_list    ap)           /* I - Additional arguments */
+{
+  char         buffer[IPP_MAX_TEXT + 4];
+                                       /* Formatted text string */
+  ssize_t      bytes,                  /* Length of formatted value */
+               max_bytes;              /* Maximum number of bytes for value */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!ipp || !name || group < IPP_TAG_ZERO ||
+      group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
+      (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
+       value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
+      !format || !ap)
+    return (NULL);
+
+  if ((value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG)
+          != (language != NULL))
+    return (NULL);
+
+ /*
+  * Format the string...
+  */
+
+  if (!strcmp(format, "%s"))
+  {
+   /*
+    * Optimize the simple case...
+    */
+
+    const char *s = va_arg(ap, char *);
+
+    if (!s)
+      s = "(null)";
+
+    bytes = strlen(s);
+    strlcpy(buffer, s, sizeof(buffer));
+  }
+  else
+  {
+   /*
+    * Do a full formatting of the message...
+    */
+
+    if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
+      return (NULL);
+  }
+
+ /*
+  * Limit the length of the string...
+  */
+
+  switch (value_tag)
+  {
+    default :
+    case IPP_TAG_TEXT :
+    case IPP_TAG_TEXTLANG :
+        max_bytes = IPP_MAX_TEXT;
+        break;
+
+    case IPP_TAG_NAME :
+    case IPP_TAG_NAMELANG :
+        max_bytes = IPP_MAX_NAME;
+        break;
+
+    case IPP_TAG_CHARSET :
+        max_bytes = IPP_MAX_CHARSET;
+        break;
+
+    case IPP_TAG_KEYWORD :
+        max_bytes = IPP_MAX_KEYWORD;
+        break;
+
+    case IPP_TAG_LANGUAGE :
+        max_bytes = IPP_MAX_LANGUAGE;
+        break;
+
+    case IPP_TAG_MIMETYPE :
+        max_bytes = IPP_MAX_MIMETYPE;
+        break;
+
+    case IPP_TAG_URI :
+        max_bytes = IPP_MAX_URI;
+        break;
+
+    case IPP_TAG_URISCHEME :
+        max_bytes = IPP_MAX_URISCHEME;
+        break;
+  }
+
+  if (bytes >= max_bytes)
+  {
+    char       *bufmax,                /* Buffer at max_bytes */
+               *bufptr;                /* Pointer into buffer */
+
+    bufptr = buffer + strlen(buffer) - 1;
+    bufmax = buffer + max_bytes - 1;
+
+    while (bufptr > bufmax)
+    {
+      if (*bufptr & 0x80)
+      {
+        while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
+          bufptr --;
+      }
+
+      bufptr --;
+    }
+
+    *bufptr = '\0';
+  }
+
+ /*
+  * Add the formatted string and return...
+  */
+
+  return (ippAddString(ipp, group, value_tag, name, language, buffer));
+}
+
+
 /*
  * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code group@ parameter specifies the IPP attribute group tag: none
  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
@@ -2415,6 +2634,114 @@ ippNewRequest(ipp_op_t op)              /* I - Operation code */
 }
 
 
+/*
+ * 'ippNewResponse()' - Allocate a new IPP response message.
+ *
+ * The new response message is initialized with the same version-number,
+ * request-id, attributes-charset, and attributes-natural-language as the
+ * provided request message.  If the attributes-charset or
+ * attributes-natural-language attributes are missing from the request,
+ * "utf-8" and a value derived from the current locale are substituted,
+ * respectively.
+ *
+ * @since CUPS 1.7@
+ */
+
+ipp_t *                                        /* O - IPP response message */
+ippNewResponse(ipp_t *request)         /* I - IPP request message */
+{
+  ipp_t                        *response;      /* IPP response message */
+  ipp_attribute_t      *attr;          /* Current attribute */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!request)
+    return (NULL);
+
+ /*
+  * Create a new IPP message...
+  */
+
+  if ((response = ippNew()) == NULL)
+    return (NULL);
+
+ /*
+  * Copy the request values over to the response...
+  */
+
+  response->request.status.version[0] = request->request.op.version[0];
+  response->request.status.version[1] = request->request.op.version[1];
+  response->request.status.request_id = request->request.op.request_id;
+
+ /*
+  * The first attribute MUST be attributes-charset...
+  */
+
+  attr = request->attrs;
+
+  if (attr && attr->name && !strcmp(attr->name, "attributes-charset") &&
+      attr->group_tag == IPP_TAG_OPERATION &&
+      attr->value_tag == IPP_TAG_CHARSET &&
+      attr->num_values == 1)
+  {
+   /*
+    * Copy charset from request...
+    */
+
+    ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                "attributes-charset", NULL, attr->values[0].string.text);
+  }
+  else
+  {
+   /*
+    * Use "utf-8" as the default...
+    */
+
+    ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                "attributes-charset", NULL, "utf-8");
+  }
+
+ /*
+  * Then attributes-natural-language...
+  */
+
+  if (attr)
+    attr = attr->next;
+
+  if (attr && attr->name &&
+      !strcmp(attr->name, "attributes-natural-language") &&
+      attr->group_tag == IPP_TAG_OPERATION &&
+      attr->value_tag == IPP_TAG_LANGUAGE &&
+      attr->num_values == 1)
+  {
+   /*
+    * Copy language from request...
+    */
+
+    ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                "attributes-natural-language", NULL,
+                attr->values[0].string.text);
+  }
+  else
+  {
+   /*
+    * Use the language from the current locale...
+    */
+
+    cups_lang_t *language = cupsLangDefault();
+                                       /* Current locale */
+
+    ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                "attributes-natural-language", NULL, language->language);
+  }
+
+  return (response);
+}
+
+
 /*
  * 'ippRead()' - Read data for an IPP message from a HTTP connection.
  */
@@ -3271,8 +3598,8 @@ ippReadIO(void       *src,                /* I - Data source */
 /*
  * 'ippSetBoolean()' - Set a boolean value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3313,8 +3640,8 @@ ippSetBoolean(ipp_t           *ipp,       /* IO - IPP message */
 /*
  * 'ippSetCollection()' - Set a collection value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3362,8 +3689,8 @@ ippSetCollection(
 /*
  * 'ippSetDate()' - Set a date value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3404,8 +3731,8 @@ ippSetDate(ipp_t             *ipp,        /* IO - IPP message */
 /*
  * 'ippSetGroupTag()' - Set the group tag of an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3445,8 +3772,8 @@ ippSetGroupTag(
 /*
  * 'ippSetInteger()' - Set an integer or enum value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3488,8 +3815,8 @@ ippSetInteger(ipp_t           *ipp,       /* IO - IPP message */
 /*
  * 'ippSetName()' - Set the name of an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3530,8 +3857,8 @@ ippSetName(ipp_t           *ipp,  /* IO - IPP message */
 /*
  * 'ippSetOperation()' - Set the operation ID in an IPP request message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * @since CUPS 1.6/OS X 10.8@
  */
@@ -3560,8 +3887,8 @@ ippSetOperation(ipp_t    *ipp,            /* I - IPP request message */
 /*
  * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3606,8 +3933,8 @@ ippSetRange(ipp_t           *ipp, /* IO - IPP message */
 /*
  * 'ippSetRequestId()' - Set the request ID in an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code request_id@ parameter must be greater than 0.
  *
@@ -3640,8 +3967,8 @@ ippSetRequestId(ipp_t *ipp,               /* I - IPP message */
 /*
  * 'ippSetResolution()' - Set a resolution value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3718,8 +4045,8 @@ ippSetState(ipp_t       *ipp,             /* I - IPP message */
 /*
  * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * @since CUPS 1.6/OS X 10.8@
  */
@@ -3748,8 +4075,8 @@ ippSetStatusCode(ipp_t        *ipp,       /* I - IPP response or event message */
 /*
  * 'ippSetString()' - Set a string value in an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3810,8 +4137,8 @@ ippSetString(ipp_t           *ipp,        /* IO - IPP message */
 /*
  * 'ippSetValueTag()' - Set the value tag of an attribute.
  *
- * The @code ipp@ parameter refers to the IPP message containing the attribute that was
- * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
@@ -3979,8 +4306,8 @@ ippSetValueTag(
 /*
  * 'ippSetVersion()' - Set the version number in an IPP message.
  *
- * The @code ipp@ parameter refers to an IPP message previously created using the
- * @link ippNew@ or @link ippNewRequest@ functions.
+ * The @code ipp@ parameter refers to an IPP message previously created using
+ * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
  *
  * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
  *
index 6a1357003035c9fabaeaed1624e6de3ea832be95..cba543bb8b69e033e3d6bf666cce41099ee02b11 100644 (file)
@@ -694,6 +694,18 @@ extern int         ippSetValueTag(ipp_t *ipp, ipp_attribute_t **attr,
 extern int             ippSetVersion(ipp_t *ipp, int major, int minor)
                                      _CUPS_API_1_6;
 
+/**** New in CUPS 1.7 ****/
+extern ipp_attribute_t *ippAddStringf(ipp_t *ipp, ipp_tag_t group,
+                                      ipp_tag_t value_tag, const char *name,
+                                      const char *language, const char *format,
+                                      ...) _CUPS_API_1_7;
+extern ipp_attribute_t *ippAddStringfv(ipp_t *ipp, ipp_tag_t group,
+                                       ipp_tag_t value_tag, const char *name,
+                                       const char *language,
+                                       const char *format, va_list ap)
+                                       _CUPS_API_1_7;
+extern ipp_t           *ippNewResponse(ipp_t *request) _CUPS_API_1_7;
+
 
 /*
  * C++ magic...
index fe083d3ce3e630f72c4bffda5b1105c9eb86255f..f1ab62c9f4c70605387e49eec92cc3cc70a6874f 100644 (file)
@@ -1124,7 +1124,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
-       httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+       httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n");
        httpPrintf(HTTP(con), "Content-Length: 0\r\n");
        httpPrintf(HTTP(con), "\r\n");
 
@@ -1198,7 +1198,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
-       httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+       httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n");
        httpPrintf(HTTP(con), "Content-Length: 0\r\n");
        httpPrintf(HTTP(con), "\r\n");