ippWriteIO(void       *dst,		/* I - Destination */
           ipp_iocb_t cb,		/* I - Write callback function */
	   int        blocking,		/* I - Use blocking IO? */
	   ipp_t      *parent,		/* I - Parent IPP message */
           ipp_t      *ipp)		/* I - IPP data */
{
  int			i;		/* Looping var */
  int			n;		/* Length of data */
  unsigned char		*buffer,	/* Data buffer */
			*bufptr;	/* Pointer into buffer */
  ipp_attribute_t	*attr;		/* Current attribute */
  _ipp_value_t		*value;		/* Current value */


  DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp));

  if (!dst || !ipp)
    return (IPP_STATE_ERROR);

  if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
  {
    DEBUG_puts("1ippWriteIO: Unable to get write buffer");
    return (IPP_STATE_ERROR);
  }

  switch (ipp->state)
  {
    case IPP_STATE_IDLE :
        ipp->state ++; /* Avoid common problem... */

    case IPP_STATE_HEADER :
        if (parent == NULL)
	{
	 /*
	  * Send the request header:
	  *
	  *                 Version = 2 bytes
	  *   Operation/Status Code = 2 bytes
	  *              Request ID = 4 bytes
	  *                   Total = 8 bytes
	  */

          bufptr = buffer;

	  *bufptr++ = ipp->request.any.version[0];
	  *bufptr++ = ipp->request.any.version[1];
	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
	  *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
	  *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;

	  DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
	  DEBUG_printf(("2ippWriteIO: op_status=%04x",
			ipp->request.any.op_status));
	  DEBUG_printf(("2ippWriteIO: request_id=%d",
			ipp->request.any.request_id));

          if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	  {
	    DEBUG_puts("1ippWriteIO: Could not write IPP header...");
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }
	}

       /*
	* Reset the state engine to point to the first attribute
	* in the request/response, with no current group.
	*/

        ipp->state   = IPP_STATE_ATTRIBUTE;
	ipp->current = ipp->attrs;
	ipp->curtag  = IPP_TAG_ZERO;

	DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current));

       /*
        * If blocking is disabled, stop here...
	*/

        if (!blocking)
	  break;

    case IPP_STATE_ATTRIBUTE :
        while (ipp->current != NULL)
	{
	 /*
	  * Write this attribute...
	  */

	  bufptr = buffer;
	  attr   = ipp->current;

	  ipp->current = ipp->current->next;

          if (!parent)
	  {
	    if (ipp->curtag != attr->group_tag)
	    {
	     /*
	      * Send a group tag byte...
	      */

	      ipp->curtag = attr->group_tag;

	      if (attr->group_tag == IPP_TAG_ZERO)
		continue;

	      DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
			    attr->group_tag, ippTagString(attr->group_tag)));
	      *bufptr++ = (ipp_uchar_t)attr->group_tag;
	    }
	    else if (attr->group_tag == IPP_TAG_ZERO)
	      continue;
	  }

	  DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
	                attr->num_values > 1 ? "1setOf " : "",
			ippTagString(attr->value_tag)));

         /*
	  * Write the attribute tag and name.
	  *
	  * The attribute name length does not include the trailing nul
	  * character in the source string.
	  *
	  * Collection values (parent != NULL) are written differently...
	  */

          if (parent == NULL)
	  {
           /*
	    * Get the length of the attribute name, and make sure it won't
	    * overflow the buffer...
	    */

            if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
	    {
	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

           /*
	    * Write the value tag, name length, and name string...
	    */

            DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
	                  attr->value_tag, ippTagString(attr->value_tag)));
            DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
	                  attr->name));

            if (attr->value_tag > 0xff)
            {
              *bufptr++ = IPP_TAG_EXTENSION;
	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
            }
            else
	      *bufptr++ = (ipp_uchar_t)attr->value_tag;

	    *bufptr++ = (ipp_uchar_t)(n >> 8);
	    *bufptr++ = (ipp_uchar_t)n;
	    memcpy(bufptr, attr->name, (size_t)n);
	    bufptr += n;
          }
	  else
	  {
           /*
	    * Get the length of the attribute name, and make sure it won't
	    * overflow the buffer...
	    */

            if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
	    {
	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

           /*
	    * Write the member name tag, name length, name string, value tag,
	    * and empty name for the collection member attribute...
	    */

            DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
	                  IPP_TAG_MEMBERNAME));
            DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
	                  attr->name));
            DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
	                  attr->value_tag, ippTagString(attr->value_tag)));
            DEBUG_puts("2ippWriteIO: writing name=0,\"\"");

            *bufptr++ = IPP_TAG_MEMBERNAME;
	    *bufptr++ = 0;
	    *bufptr++ = 0;
	    *bufptr++ = (ipp_uchar_t)(n >> 8);
	    *bufptr++ = (ipp_uchar_t)n;
	    memcpy(bufptr, attr->name, (size_t)n);
	    bufptr += n;

            if (attr->value_tag > 0xff)
            {
              *bufptr++ = IPP_TAG_EXTENSION;
	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
            }
            else
	      *bufptr++ = (ipp_uchar_t)attr->value_tag;

            *bufptr++ = 0;
            *bufptr++ = 0;
	  }

         /*
	  * Now write the attribute value(s)...
	  */

	  switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
	  {
	    case IPP_TAG_UNSUPPORTED_VALUE :
	    case IPP_TAG_DEFAULT :
	    case IPP_TAG_UNKNOWN :
	    case IPP_TAG_NOVALUE :
	    case IPP_TAG_NOTSETTABLE :
	    case IPP_TAG_DELETEATTR :
	    case IPP_TAG_ADMINDEFINE :
		*bufptr++ = 0;
		*bufptr++ = 0;
	        break;

	    case IPP_TAG_INTEGER :
	    case IPP_TAG_ENUM :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

		 /*
	          * Integers and enumerations are both 4-byte signed
		  * (twos-complement) values.
		  *
		  * Put the 2-byte length and 4-byte value into the buffer...
		  */

	          *bufptr++ = 0;
		  *bufptr++ = 4;
		  *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
		  *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
		  *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
		  *bufptr++ = (ipp_uchar_t)value->integer;
		}
		break;

	    case IPP_TAG_BOOLEAN :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * Boolean values are 1-byte; 0 = false, 1 = true.
		  *
		  * Put the 2-byte length and 1-byte value into the buffer...
		  */

	          *bufptr++ = 0;
		  *bufptr++ = 1;
		  *bufptr++ = (ipp_uchar_t)value->boolean;
		}
		break;

	    case IPP_TAG_TEXT :
	    case IPP_TAG_NAME :
	    case IPP_TAG_KEYWORD :
	    case IPP_TAG_URI :
	    case IPP_TAG_URISCHEME :
	    case IPP_TAG_CHARSET :
	    case IPP_TAG_LANGUAGE :
	    case IPP_TAG_MIMETYPE :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

        	    DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
		                  attr->value_tag,
				  ippTagString(attr->value_tag)));
        	    DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));

                    if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
		    {
                      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	              {
	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
			           "attribute...");
			_cupsBufferRelease((char *)buffer);
	        	return (IPP_STATE_ERROR);
	              }

		      bufptr = buffer;
		    }

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                  if (value->string.text != NULL)
                    n = (int)strlen(value->string.text);
		  else
		    n = 0;

                  if (n > (IPP_BUF_SIZE - 2))
		  {
		    DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
		  }

                  DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
		                value->string.text));

                  if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		 /*
		  * All simple strings consist of the 2-byte length and
		  * character data without the trailing nul normally found
		  * in C strings.  Also, strings cannot be longer than IPP_MAX_LENGTH
		  * bytes since the 2-byte length is a signed (twos-complement)
		  * value.
		  *
		  * Put the 2-byte length and string characters in the buffer.
		  */

	          *bufptr++ = (ipp_uchar_t)(n >> 8);
		  *bufptr++ = (ipp_uchar_t)n;

		  if (n > 0)
		  {
		    memcpy(bufptr, value->string.text, (size_t)n);
		    bufptr += n;
		  }
		}
		break;

	    case IPP_TAG_DATE :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * Date values consist of a 2-byte length and an
		  * 11-byte date/time structure defined by RFC 1903.
		  *
		  * Put the 2-byte length and 11-byte date/time
		  * structure in the buffer.
		  */

	          *bufptr++ = 0;
		  *bufptr++ = 11;
		  memcpy(bufptr, value->date, 11);
		  bufptr += 11;
		}
		break;

	    case IPP_TAG_RESOLUTION :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
		      return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * Resolution values consist of a 2-byte length,
		  * 4-byte horizontal resolution value, 4-byte vertical
		  * resolution value, and a 1-byte units value.
		  *
		  * Put the 2-byte length and resolution value data
		  * into the buffer.
		  */

	          *bufptr++ = 0;
		  *bufptr++ = 9;
		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
		  *bufptr++ = (ipp_uchar_t)value->resolution.xres;
		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
		  *bufptr++ = (ipp_uchar_t)value->resolution.yres;
		  *bufptr++ = (ipp_uchar_t)value->resolution.units;
		}
		break;

	    case IPP_TAG_RANGE :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * Range values consist of a 2-byte length,
		  * 4-byte lower value, and 4-byte upper value.
		  *
		  * Put the 2-byte length and range value data
		  * into the buffer.
		  */

	          *bufptr++ = 0;
		  *bufptr++ = 8;
		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
		  *bufptr++ = (ipp_uchar_t)value->range.lower;
		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
		  *bufptr++ = (ipp_uchar_t)value->range.upper;
		}
		break;

	    case IPP_TAG_TEXTLANG :
	    case IPP_TAG_NAMELANG :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
		    {
                      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	              {
	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
		                   "attribute...");
			_cupsBufferRelease((char *)buffer);
	        	return (IPP_STATE_ERROR);
	              }

		      bufptr = buffer;
		    }

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * textWithLanguage and nameWithLanguage values consist
		  * of a 2-byte length for both strings and their
		  * individual lengths, a 2-byte length for the
		  * character string, the character string without the
		  * trailing nul, a 2-byte length for the character
		  * set string, and the character set string without
		  * the trailing nul.
		  */

                  n = 4;

		  if (value->string.language != NULL)
                    n += (int)strlen(value->string.language);

		  if (value->string.text != NULL)
                    n += (int)strlen(value->string.text);

                  if (n > (IPP_BUF_SIZE - 2))
		  {
		    DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
		                  "too long (%d)", n));
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
                  }

                  if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

                 /* Length of entire value */
	          *bufptr++ = (ipp_uchar_t)(n >> 8);
		  *bufptr++ = (ipp_uchar_t)n;

                 /* Length of language */
		  if (value->string.language != NULL)
		    n = (int)strlen(value->string.language);
		  else
		    n = 0;

	          *bufptr++ = (ipp_uchar_t)(n >> 8);
		  *bufptr++ = (ipp_uchar_t)n;

                 /* Language */
		  if (n > 0)
		  {
		    memcpy(bufptr, value->string.language, (size_t)n);
		    bufptr += n;
		  }

                 /* Length of text */
                  if (value->string.text != NULL)
		    n = (int)strlen(value->string.text);
		  else
		    n = 0;

	          *bufptr++ = (ipp_uchar_t)(n >> 8);
		  *bufptr++ = (ipp_uchar_t)n;

                 /* Text */
		  if (n > 0)
		  {
		    memcpy(bufptr, value->string.text, (size_t)n);
		    bufptr += n;
		  }
		}
		break;

            case IPP_TAG_BEGIN_COLLECTION :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
		 /*
		  * Collections are written with the begin-collection
		  * tag first with a value of 0 length, followed by the
		  * attributes in the collection, then the end-collection
		  * value...
		  */

                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * Write a data length of 0 and flush the buffer...
		  */

	          *bufptr++ = 0;
		  *bufptr++ = 0;

                  if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	          {
	            DEBUG_puts("1ippWriteIO: Could not write IPP "
		               "attribute...");
		    _cupsBufferRelease((char *)buffer);
	            return (IPP_STATE_ERROR);
	          }

		  bufptr = buffer;

                 /*
		  * Then write the collection attribute...
		  */

                  value->collection->state = IPP_STATE_IDLE;

		  if (ippWriteIO(dst, cb, 1, ipp,
		                 value->collection) == IPP_STATE_ERROR)
		  {
		    DEBUG_puts("1ippWriteIO: Unable to write collection value");
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
		  }
		}
		break;

            default :
	        for (i = 0, value = attr->values;
		     i < attr->num_values;
		     i ++, value ++)
		{
		  if (i)
		  {
		   /*
		    * Arrays and sets are done by sending additional
		    * values with a zero-length name...
		    */

                    if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
		    {
                      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	              {
	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
		                   "attribute...");
			_cupsBufferRelease((char *)buffer);
	        	return (IPP_STATE_ERROR);
	              }

		      bufptr = buffer;
		    }

                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
		    *bufptr++ = 0;
		    *bufptr++ = 0;
		  }

                 /*
		  * An unknown value might some new value that a
		  * vendor has come up with. It consists of a
		  * 2-byte length and the bytes in the unknown
		  * value buffer.
		  */

                  n = value->unknown.length;

                  if (n > (IPP_BUF_SIZE - 2))
		  {
		    DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
		                  n));
		    _cupsBufferRelease((char *)buffer);
		    return (IPP_STATE_ERROR);
		  }

                  if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
		  {
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	            {
	              DEBUG_puts("1ippWriteIO: Could not write IPP "
		                 "attribute...");
		      _cupsBufferRelease((char *)buffer);
	              return (IPP_STATE_ERROR);
	            }

		    bufptr = buffer;
		  }

                 /* Length of unknown value */
	          *bufptr++ = (ipp_uchar_t)(n >> 8);
		  *bufptr++ = (ipp_uchar_t)n;

                 /* Value */
		  if (n > 0)
		  {
		    memcpy(bufptr, value->unknown.data, (size_t)n);
		    bufptr += n;
		  }
		}
		break;
	  }

         /*
	  * Write the data out...
	  */

	  if (bufptr > buffer)
	  {
	    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
	    {
	      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
	      _cupsBufferRelease((char *)buffer);
	      return (IPP_STATE_ERROR);
	    }

	    DEBUG_printf(("2ippWriteIO: wrote %d bytes",
			  (int)(bufptr - buffer)));
	  }

	 /*
          * If blocking is disabled and we aren't at the end of the attribute
          * list, stop here...
	  */

          if (!blocking && ipp->current)
	    break;
	}

	if (ipp->current == NULL)
	{
         /*
	  * Done with all of the attributes; add the end-of-attributes
	  * tag or end-collection attribute...
	  */

          if (parent == NULL)
	  {
            buffer[0] = IPP_TAG_END;
	    n         = 1;
	  }
	  else
	  {
            buffer[0] = IPP_TAG_END_COLLECTION;
	    buffer[1] = 0; /* empty name */
	    buffer[2] = 0;
	    buffer[3] = 0; /* empty value */
	    buffer[4] = 0;
	    n         = 5;
	  }

	  if ((*cb)(dst, buffer, (size_t)n) < 0)
	  {
	    DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
	    _cupsBufferRelease((char *)buffer);
	    return (IPP_STATE_ERROR);
	  }

	  ipp->state = IPP_STATE_DATA;
	}
        break;

    case IPP_STATE_DATA :
        break;

    default :
        break; /* anti-compiler-warning-code */
  }

  _cupsBufferRelease((char *)buffer);

  return (ipp->state);
}