/*
- * "$Id: ipp.c,v 1.31 2000/01/21 20:33:16 mike Exp $"
+ * "$Id: ipp.c,v 1.56 2001/04/15 11:52:43 mike Exp $"
*
* Internet Printing Protocol support functions for the Common UNIX
* Printing System (CUPS).
*
- * Copyright 1997-2000 by Easy Software Products, all rights reserved.
+ * Copyright 1997-2001 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* property of Easy Software Products and are protected by Federal
* ippErrorString() - Return a textual message for the given error message.
* ippFindAttribute() - Find a named attribute in a request...
* ippLength() - Compute the length of an IPP request.
+ * ippNew() - Allocate a new IPP request.
* ippPort() - Return the default IPP port number.
* ippRead() - Read data for an IPP request.
+ * ippSetPort() - Set the default port number.
* ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
* ippWrite() - Write data for an IPP request.
- * _ipp_add_attr() - Add a new attribute to the request.
+ * _ipp_add_attr() - Add a new attribute to the request.
+ * _ipp_free_attr() - Free an attribute.
* ipp_read() - Semi-blocking read on a HTTP connection...
*/
#include "ipp.h"
#include "debug.h"
+#include <ctype.h>
+
+
+/*
+ * Local globals...
+ */
+
+static int ipp_port = 0;
/*
ipp_attribute_t *attr; /* New attribute */
- DEBUG_printf(("ippAddBoolean(%08x, %02x, \'%s\', %d)\n", ipp, group, name, value));
+ DEBUG_printf(("ippAddBoolean(%p, %02x, \'%s\', %d)\n", ipp, group, name, value));
if (ipp == NULL || name == NULL)
return (NULL);
ipp_attribute_t *attr; /* New attribute */
- DEBUG_printf(("ippAddBooleans(%08x, %02x, \'%s\', %d, %08x)\n", ipp,
+ DEBUG_printf(("ippAddBooleans(%p, %02x, \'%s\', %d, %p)\n", ipp,
group, name, num_values, values));
if (ipp == NULL || name == NULL)
ipp_attribute_t *attr; /* New attribute */
- DEBUG_printf(("ippAddDate(%08x, %02x, \'%s\', %08x)\n", ipp, group, name,
+ DEBUG_printf(("ippAddDate(%p, %02x, \'%s\', %p)\n", ipp, group, name,
value));
if (ipp == NULL || name == NULL || value == NULL)
ipp_attribute_t *attr; /* New attribute */
- DEBUG_printf(("ippAddInteger(%08x, %d, \'%s\', %d)\n", ipp, group, name,
+ DEBUG_printf(("ippAddInteger(%p, %d, \'%s\', %d)\n", ipp, group, name,
value));
if (ipp == NULL || name == NULL)
attr->group_tag = group;
attr->value_tag = type;
attr->values[0].string.charset = charset ? strdup(charset) : NULL;
- attr->values[0].string.text = strdup(value);
+ attr->values[0].string.text = value ? strdup(value) : NULL;
+
+ if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) &&
+ attr->values[0].string.text)
+ {
+ /*
+ * Convert to lowercase and change _ to - as needed...
+ */
+
+ char *p;
+
+
+ for (p = attr->values[0].string.text; *p; p ++)
+ if (*p == '_')
+ *p = '-';
+ else
+ *p = tolower(*p);
+ }
return (attr);
}
ipp_attribute_t *attr; /* New attribute */
- DEBUG_printf(("ippAddSeparator(%08x)\n", ipp));
+ DEBUG_printf(("ippAddSeparator(%p)\n", ipp));
if (ipp == NULL)
return (NULL);
void
ippDelete(ipp_t *ipp) /* I - IPP request */
{
- int i; /* Looping var */
ipp_attribute_t *attr, /* Current attribute */
*next; /* Next attribute */
+ DEBUG_printf(("ippNew(): %p\n", ipp));
+
if (ipp == NULL)
return;
for (attr = ipp->attrs; attr != NULL; attr = next)
{
- switch (attr->value_tag)
- {
- case IPP_TAG_TEXT :
- case IPP_TAG_NAME :
- case IPP_TAG_KEYWORD :
- case IPP_TAG_STRING :
- case IPP_TAG_URI :
- case IPP_TAG_URISCHEME :
- case IPP_TAG_CHARSET :
- case IPP_TAG_LANGUAGE :
- case IPP_TAG_MIMETYPE :
- for (i = 0; i < attr->num_values; i ++)
- free(attr->values[i].string.text);
- break;
-
- case IPP_TAG_TEXTLANG :
- case IPP_TAG_NAMELANG :
- for (i = 0; i < attr->num_values; i ++)
- {
- if (attr->values[i].string.charset)
- free(attr->values[i].string.charset);
- free(attr->values[i].string.text);
- }
- break;
- }
-
next = attr->next;
-
- if (attr->name != NULL)
- free(attr->name);
-
- free(attr);
+ _ipp_free_attr(attr);
}
free(ipp);
const char * /* O - Text string */
ippErrorString(ipp_status_t error) /* I - Error status */
{
- static cups_lang_t *language = 0; /* Language info */
+ static char unknown[255]; /* Unknown error statuses */
+ static const char *status_oks[] = /* "OK" status codes */
+ {
+ "successful-ok",
+ "successful-ok-ignored-or-substituted-attributes",
+ "successful-ok-conflicting-attributes",
+ "successful-ok-ignored-subscriptions",
+ "successful-ok-ignored-notifications",
+ "successful-ok-too-many-events",
+ "successful-ok-but-cancel-subscription"
+ },
+ *status_400s[] = /* Client errors */
+ {
+ "client-error-bad-request",
+ "client-error-forbidden",
+ "client-error-not-authenticated",
+ "client-error-not-authorized",
+ "client-error-not-possible",
+ "client-error-timeout",
+ "client-error-not-found",
+ "client-error-gone",
+ "client-error-request-entity-too-large",
+ "client-error-request-value-too-long",
+ "client-error-document-format-not-supported",
+ "client-error-attributes-or-values-not-supported",
+ "client-error-uri-scheme-not-supported",
+ "client-error-charset-not-supported",
+ "client-error-conflicting-attributes",
+ "client-error-compression-not-supported",
+ "client-error-compression-error",
+ "client-error-document-format-error",
+ "client-error-document-access-error",
+ "client-error-attributes-not-settable",
+ "client-error-ignored-all-subscriptions",
+ "client-error-too-many-subscriptions",
+ "client-error-ignored-all-notifications",
+ "client-error-print-support-file-not-found"
+ },
+ *status_500s[] = /* Server errors */
+ {
+ "server-error-internal-error",
+ "server-error-operation-not-supported",
+ "server-error-service-unavailable",
+ "server-error-version-not-supported",
+ "server-error-device-error",
+ "server-error-temporary-error",
+ "server-error-not-accepting-jobs",
+ "server-error-busy",
+ "server-error-job-canceled",
+ "server-error-multiple-document-jobs-not-supported",
+ "server-error-printer-is-deactivated"
+ };
/*
- * Load the localized message file as needed...
+ * See if the error code is a known value...
*/
- if (!language)
- language = cupsLangDefault();
+ if (error >= IPP_OK && error <= IPP_OK_BUT_CANCEL_SUBSCRIPTION)
+ return (status_oks[error]);
+ else if (error == IPP_REDIRECTION_OTHER_SITE)
+ return ("redirection-other-site");
+ else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND)
+ return (status_400s[error - IPP_BAD_REQUEST]);
+ else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED)
+ return (status_500s[error - IPP_INTERNAL_ERROR]);
/*
- * Return the appropriate message...
+ * No, build an "unknown-xxxx" error string...
*/
- switch (error)
- {
- case IPP_OK :
- case IPP_OK_SUBST :
- case IPP_OK_CONFLICT :
- return ("OK");
-
- case IPP_BAD_REQUEST :
- return (cupsLangString(language, HTTP_BAD_REQUEST));
-
- case IPP_FORBIDDEN :
- return (cupsLangString(language, HTTP_FORBIDDEN));
-
- case IPP_NOT_AUTHENTICATED :
- case IPP_NOT_AUTHORIZED :
- return (cupsLangString(language, HTTP_UNAUTHORIZED));
-
- case IPP_NOT_POSSIBLE :
- return (cupsLangString(language, HTTP_METHOD_NOT_ALLOWED));
-
- case IPP_TIMEOUT :
- return (cupsLangString(language, HTTP_REQUEST_TIMEOUT));
-
- case IPP_NOT_FOUND :
- return (cupsLangString(language, HTTP_NOT_FOUND));
-
- case IPP_GONE :
- return (cupsLangString(language, HTTP_GONE));
-
- case IPP_DOCUMENT_FORMAT :
- return (cupsLangString(language, HTTP_UNSUPPORTED_MEDIATYPE));
-
- case IPP_CONFLICT :
- return (cupsLangString(language, HTTP_CONFLICT));
-
- case IPP_INTERNAL_ERROR :
- return (cupsLangString(language, HTTP_SERVER_ERROR));
-
- case IPP_OPERATION_NOT_SUPPORTED :
- case IPP_VERSION_NOT_SUPPORTED :
- return (cupsLangString(language, HTTP_NOT_SUPPORTED));
-
- case IPP_SERVICE_UNAVAILABLE :
- case IPP_DEVICE_UNAVAILABLE :
- case IPP_TEMPORARY_ERROR :
- case IPP_PRINTER_BUSY :
- return (cupsLangString(language, HTTP_SERVICE_UNAVAILABLE));
-
- case IPP_NOT_ACCEPTING :
- return (cupsLangString(language, CUPS_MSG_NOT_ACCEPTING_JOBS));
- }
+ sprintf(unknown, "unknown-%04x", error);
- return ("ERROR");
+ return (unknown);
}
const char *name, /* I - Name of attribute */
ipp_tag_t type) /* I - Type of attribute */
{
- ipp_attribute_t *attr; /* Current atttribute */
+ ipp_attribute_t *attr; /* Current atttribute */
+ ipp_tag_t value_tag; /* Value tag */
- DEBUG_printf(("ippFindAttribute(%08x, \'%s\')\n", ipp, name));
+ DEBUG_printf(("ippFindAttribute(%p, \'%s\')\n", ipp, name));
if (ipp == NULL || name == NULL)
return (NULL);
for (attr = ipp->attrs; attr != NULL; attr = attr->next)
{
- DEBUG_printf(("ippFindAttribute: attr = %08x, name = \'%s\'\n", attr,
+ DEBUG_printf(("ippFindAttribute: attr = %p, name = \'%s\'\n", attr,
attr->name));
+ value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
+
if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
- (attr->value_tag == type ||
- (attr->value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
- (attr->value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
+ (value_tag == type || type == IPP_TAG_ZERO ||
+ (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
+ (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
return (attr);
}
bytes += 2 * attr->num_values; /* Name lengths */
bytes += 2 * attr->num_values; /* Value lengths */
- switch (attr->value_tag)
+ switch (attr->value_tag & ~IPP_TAG_COPY)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
- bytes += 2 * attr->num_values;/* Charset length */
+ bytes += 4 * attr->num_values;/* Charset + text length */
for (i = 0; i < attr->num_values; i ++)
bytes += strlen(attr->values[i].string.charset) +
strlen(attr->values[i].string.text);
break;
+
+ default :
+ for (i = 0; i < attr->num_values; i ++)
+ bytes += attr->values[0].unknown.length;
+ break;
}
}
}
+/*
+ * 'ippNew()' - Allocate a new IPP request.
+ */
+
ipp_t * /* O - New IPP request */
ippNew(void)
{
- return ((ipp_t *)calloc(sizeof(ipp_t), 1));
+ ipp_t *temp; /* New IPP request */
+
+
+ if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
+ {
+ /*
+ * Default to IPP 1.1...
+ */
+
+ temp->request.any.version[0] = 1;
+ temp->request.any.version[1] = 1;
+ }
+
+ DEBUG_printf(("ippNew(): %p\n", temp));
+
+ return (temp);
}
ipp_t *ipp) /* I - IPP data */
{
int n; /* Length of data */
- unsigned char buffer[8192]; /* Data buffer */
+ unsigned char buffer[8192], /* Data buffer */
+ *bufptr; /* Pointer into buffer */
ipp_attribute_t *attr; /* Current attribute */
ipp_tag_t tag; /* Current tag */
- DEBUG_printf(("ippRead(%08x, %08x)\n", http, ipp));
+ DEBUG_printf(("ippRead(%p, %p)\n", http, ipp));
if (http == NULL || ipp == NULL)
return (IPP_ERROR);
ipp->current = NULL;
ipp->curtag = IPP_TAG_ZERO;
+ DEBUG_printf(("ippRead: version=%d.%d\n", buffer[0], buffer[1]));
+ DEBUG_printf(("ippRead: op_status=%04x\n", ipp->request.any.op_status));
+ DEBUG_printf(("ippRead: request_id=%d\n", ipp->request.any.request_id));
+
/*
* If blocking is disabled, stop here...
*/
attr = ipp->current;
+ /*
+ * Make sure we aren't adding a new value of a different
+ * type...
+ */
+
+ if (attr->value_tag == IPP_TAG_STRING ||
+ (attr->value_tag >= IPP_TAG_TEXTLANG &&
+ attr->value_tag <= IPP_TAG_MIMETYPE))
+ {
+ /*
+ * String values can sometimes come across in different
+ * forms; accept sets of differing values...
+ */
+
+ if (tag != IPP_TAG_STRING &&
+ (tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE))
+ return (IPP_ERROR);
+ }
+ else if (attr->value_tag != tag)
+ return (IPP_ERROR);
+
+ /*
+ * Finally, make sure we don't have too many elements in the
+ * attribute array...
+ */
+
if (attr->num_values >= IPP_MAX_VALUES)
return (IPP_ERROR);
}
if (ipp_read(http, buffer, n) < n)
return (IPP_ERROR);
- buffer[n] = '\0';
+ bufptr = buffer;
- attr->values[attr->num_values].string.charset = strdup((char *)buffer);
+ /*
+ * text-with-language and name-with-language are composite
+ * values:
+ *
+ * charset-length
+ * charset
+ * text-length
+ * text
+ */
- if (ipp_read(http, buffer, 2) < 2)
- return (IPP_ERROR);
+ n = (bufptr[0] << 8) | bufptr[1];
- n = (buffer[0] << 8) | buffer[1];
+ attr->values[attr->num_values].string.charset = calloc(n + 1, 1);
- if (ipp_read(http, buffer, n) < n)
- return (IPP_ERROR);
+ memcpy(attr->values[attr->num_values].string.charset,
+ bufptr + 2, n);
- buffer[n] = '\0';
+ bufptr += 2 + n;
+ n = (bufptr[0] << 8) | bufptr[1];
- attr->values[attr->num_values].string.text = strdup((char *)buffer);
+ attr->values[attr->num_values].string.text = calloc(n + 1, 1);
+
+ memcpy(attr->values[attr->num_values].string.text,
+ bufptr + 2, n);
+
+ break;
+
+ default : /* Other unsupported values */
+ attr->values[attr->num_values].unknown.length = n;
+ if (n > 0)
+ {
+ attr->values[attr->num_values].unknown.data = malloc(n);
+ if (ipp_read(http, attr->values[attr->num_values].unknown.data, n) < n)
+ return (IPP_ERROR);
+ }
+ else
+ attr->values[attr->num_values].unknown.data = NULL;
break;
}
case IPP_DATA :
break;
+
+ default :
+ break; /* anti-compiler-warning-code */
}
return (ipp->state);
bufptr = buffer;
- *bufptr++ = 1;
- *bufptr++ = 0;
+ *bufptr++ = ipp->request.any.version[0];
+ *bufptr++ = ipp->request.any.version[1];
*bufptr++ = ipp->request.any.op_status >> 8;
*bufptr++ = ipp->request.any.op_status;
*bufptr++ = ipp->request.any.request_id >> 24;
ipp->current = ipp->attrs;
ipp->curtag = IPP_TAG_ZERO;
+ DEBUG_printf(("ippWrite: version=%d.%d\n", buffer[0], buffer[1]));
+ DEBUG_printf(("ippWrite: op_status=%04x\n", ipp->request.any.op_status));
+ DEBUG_printf(("ippWrite: request_id=%d\n", ipp->request.any.request_id));
+
/*
* If blocking is disabled, stop here...
*/
*bufptr++ = attr->group_tag;
}
- n = strlen(attr->name);
+ if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
+ return (IPP_ERROR);
DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag));
DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name));
memcpy(bufptr, attr->name, n);
bufptr += n;
- switch (attr->value_tag)
+ switch (attr->value_tag & ~IPP_TAG_COPY)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
for (i = 0; i < attr->num_values; i ++)
{
+ if ((sizeof(buffer) - (bufptr - buffer)) < 9)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
if (i)
{
/*
case IPP_TAG_BOOLEAN :
for (i = 0; i < attr->num_values; i ++)
{
+ if ((sizeof(buffer) - (bufptr - buffer)) < 6)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
if (i)
{
/*
attr->value_tag));
DEBUG_printf(("ippWrite: writing name = 0, \'\'\n"));
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
n = strlen(attr->values[i].string.text);
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n,
attr->values[i].string.text));
case IPP_TAG_DATE :
for (i = 0; i < attr->num_values; i ++)
{
+ if ((sizeof(buffer) - (bufptr - buffer)) < 16)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
if (i)
{
/*
case IPP_TAG_RESOLUTION :
for (i = 0; i < attr->num_values; i ++)
{
+ if ((sizeof(buffer) - (bufptr - buffer)) < 14)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
if (i)
{
/*
case IPP_TAG_RANGE :
for (i = 0; i < attr->num_values; i ++)
{
+ if ((sizeof(buffer) - (bufptr - buffer)) < 13)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
if (i)
{
/*
* values with a zero-length name...
*/
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
*bufptr++ = attr->value_tag;
*bufptr++ = 0;
*bufptr++ = 0;
}
- n = strlen(attr->values[i].string.charset);
+ n = strlen(attr->values[i].string.charset) +
+ strlen(attr->values[i].string.text) +
+ 4;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
{
bufptr = buffer;
}
+ /* Length of entire value */
*bufptr++ = n >> 8;
*bufptr++ = n;
+
+ /* Length of charset */
+ n = strlen(attr->values[i].string.charset);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Charset */
memcpy(bufptr, attr->values[i].string.charset, n);
bufptr += n;
+ /* Length of text */
n = strlen(attr->values[i].string.text);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Text */
+ memcpy(bufptr, attr->values[i].string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ default :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = attr->values[i].unknown.length;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
{
bufptr = buffer;
}
+ /* Length of unknown value */
*bufptr++ = n >> 8;
*bufptr++ = n;
- memcpy(bufptr, attr->values[i].string.text, n);
- bufptr += n;
+
+ /* Value */
+ if (n > 0)
+ {
+ memcpy(bufptr, attr->values[i].unknown.data, n);
+ bufptr += n;
+ }
}
break;
}
case IPP_DATA :
break;
+
+ default :
+ break; /* anti-compiler-warning-code */
}
return (ipp->state);
struct servent *port; /* Port number info */
- if ((server_port = getenv("IPP_PORT")) != NULL)
- return (atoi(server_port));
+ if (ipp_port)
+ return (ipp_port);
+ else if ((server_port = getenv("IPP_PORT")) != NULL)
+ return (ipp_port = atoi(server_port));
else if ((port = getservbyname("ipp", NULL)) == NULL)
- return (IPP_PORT);
+ return (ipp_port = IPP_PORT);
else
- return (ntohs(port->s_port));
+ return (ipp_port = ntohs(port->s_port));
+}
+
+
+/*
+ * 'ippSetPort()' - Set the default port number.
+ */
+
+void
+ippSetPort(int p) /* I - Port number to use */
+{
+ ipp_port = p;
}
ipp_attribute_t *attr; /* New attribute */
- DEBUG_printf(("_ipp_add_attr(%08x, %d)\n", ipp, num_values));
+ DEBUG_printf(("_ipp_add_attr(%p, %d)\n", ipp, num_values));
if (ipp == NULL || num_values < 0)
return (NULL);
ipp->last = attr;
+ DEBUG_printf(("_ipp_add_attr(): %p\n", attr));
+
return (attr);
}
+/*
+ * '_ipp_free_attr()' - Free an attribute.
+ */
+
+void
+_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
+{
+ int i; /* Looping var */
+
+
+ DEBUG_printf(("_ipp_free_attr(): %p\n", attr));
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_STRING :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0; i < attr->num_values; i ++)
+ free(attr->values[i].string.text);
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (attr->values[i].string.charset && i == 0)
+ free(attr->values[i].string.charset);
+ free(attr->values[i].string.text);
+ }
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+
+ if (attr->name != NULL)
+ free(attr->name);
+
+ free(attr);
+}
+
+
/*
* 'ipp_read()' - Semi-blocking read on a HTTP connection...
*/
* Loop until all bytes are read...
*/
- for (tbytes = 0; tbytes < length; tbytes += bytes, buffer += bytes)
+ for (tbytes = 0, bytes = 0; tbytes < length; tbytes += bytes, buffer += bytes)
if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0)
break;
* Return the number of bytes read...
*/
- return (tbytes);
+ if (tbytes == 0 && bytes < 0)
+ return (-1);
+ else
+ return (tbytes);
}
/*
- * End of "$Id: ipp.c,v 1.31 2000/01/21 20:33:16 mike Exp $".
+ * End of "$Id: ipp.c,v 1.56 2001/04/15 11:52:43 mike Exp $".
*/