xref: /onnv-gate/usr/src/lib/print/libipp-core/common/read.c (revision 4030:8649b543e698)
12264Sjacobs /*
22264Sjacobs  * CDDL HEADER START
32264Sjacobs  *
42264Sjacobs  * The contents of this file are subject to the terms of the
52264Sjacobs  * Common Development and Distribution License (the "License").
62264Sjacobs  * You may not use this file except in compliance with the License.
72264Sjacobs  *
82264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92264Sjacobs  * or http://www.opensolaris.org/os/licensing.
102264Sjacobs  * See the License for the specific language governing permissions
112264Sjacobs  * and limitations under the License.
122264Sjacobs  *
132264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
142264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
162264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
172264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
182264Sjacobs  *
192264Sjacobs  * CDDL HEADER END
202264Sjacobs  */
212264Sjacobs 
222264Sjacobs /*
23*4030Sjacobs  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
242264Sjacobs  * Use is subject to license terms.
252264Sjacobs  *
262264Sjacobs  */
272264Sjacobs 
282264Sjacobs /* $Id: read.c 146 2006-03-24 00:26:54Z njacobs $ */
292264Sjacobs 
302264Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
312264Sjacobs 
322264Sjacobs #include <stdio.h>
332264Sjacobs #include <stdlib.h>
342264Sjacobs #include <alloca.h>
352264Sjacobs #include <string.h>
362264Sjacobs #include <stdarg.h>
372264Sjacobs #include <sys/types.h>
382264Sjacobs #include <netinet/in.h>
392264Sjacobs #include <inttypes.h>
402264Sjacobs 
412264Sjacobs #include <papi.h>
422264Sjacobs #include <ipp.h>
432264Sjacobs 
442264Sjacobs 
452264Sjacobs #define	_ipp_tag_string(id) ipp_tag_string((id), buf, sizeof (buf))
462264Sjacobs 
472264Sjacobs static papi_status_t
read_name_with_language(ipp_reader_t iread,void * fd,papi_attribute_t *** message)482264Sjacobs read_name_with_language(ipp_reader_t iread, void *fd,
492264Sjacobs 			papi_attribute_t ***message)
502264Sjacobs {
512264Sjacobs 	char *string;
522264Sjacobs 	uint16_t size;
532264Sjacobs 
542264Sjacobs 	/* read the language */
552264Sjacobs 	if (iread(fd, &size, 2) != 2) {
562264Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
572264Sjacobs 				"read failed: lang len\n");
582264Sjacobs 		return (PAPI_BAD_REQUEST);
592264Sjacobs 	}
602264Sjacobs 	size = (uint16_t)ntohs(size);
612264Sjacobs 
622264Sjacobs 	if ((string = alloca(size + 1)) == NULL) {
632264Sjacobs 		ipp_set_status(message, PAPI_TEMPORARY_ERROR,
642264Sjacobs 				"Memory allocation failed");
652264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
662264Sjacobs 	}
672264Sjacobs 	if (iread(fd, string, size) != size) {
682264Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
692264Sjacobs 				"read failed: lang\n");
702264Sjacobs 		return (PAPI_BAD_REQUEST);
712264Sjacobs 	}
722264Sjacobs 
732264Sjacobs 	/* read the text */
742264Sjacobs 	if (iread(fd, &size, 2) != 2) {
752264Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
762264Sjacobs 				"read failed: text len\n");
772264Sjacobs 		return (PAPI_BAD_REQUEST);
782264Sjacobs 	}
792264Sjacobs 	size = (uint16_t)ntohs(size);
802264Sjacobs 
812264Sjacobs 	if ((string = alloca(size + 1)) == NULL) {
822264Sjacobs 		ipp_set_status(message, PAPI_TEMPORARY_ERROR,
832264Sjacobs 				"Memory allocation failed");
842264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
852264Sjacobs 	}
862264Sjacobs 	if (iread(fd, string, size) != size) {
872264Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
882264Sjacobs 				"read failed: text\n");
892264Sjacobs 		return (PAPI_BAD_REQUEST);
902264Sjacobs 	}
912264Sjacobs 
922264Sjacobs 	return (PAPI_OK);
932264Sjacobs }
942264Sjacobs 
952264Sjacobs 
962264Sjacobs static struct {
972264Sjacobs 	int8_t	ipp_type;
982264Sjacobs 	int8_t	size;
992264Sjacobs } type_info[] = {
1002264Sjacobs 	{ VTAG_INTEGER,			4 },
1012264Sjacobs 	{ VTAG_ENUM,			4 },
1022264Sjacobs 	{ VTAG_BOOLEAN,			1 },
1032264Sjacobs 	{ VTAG_RANGE_OF_INTEGER,	8 },
1042264Sjacobs 	{ VTAG_RESOLUTION,		9 },
1052264Sjacobs 	{ VTAG_DATE_TIME,		11 },
1062264Sjacobs 	{ DTAG_MIN,			0 }
1072264Sjacobs };
1082264Sjacobs 
1092264Sjacobs /* verify that the IPP type and size are compatible */
1102264Sjacobs static int
validate_length(int8_t type,int8_t size)1112264Sjacobs validate_length(int8_t type, int8_t size)
1122264Sjacobs {
1132264Sjacobs 	int i;
1142264Sjacobs 
1152264Sjacobs 	for (i = 0; type_info[i].ipp_type != DTAG_MIN; i++)
1162264Sjacobs 		if (type_info[i].ipp_type == type)
1172264Sjacobs 			return ((type_info[i].size == size) ? 0 : -1);
1182264Sjacobs 	return (0);
1192264Sjacobs }
1202264Sjacobs 
1212264Sjacobs /* convert tyep IPP type to a type that is marginally compatible */
1222264Sjacobs static int8_t
base_type(int8_t i)1232264Sjacobs base_type(int8_t i)
1242264Sjacobs {
1252264Sjacobs 	switch (i) {
1262264Sjacobs 	case VTAG_ENUM:
1272264Sjacobs 	case VTAG_INTEGER:
1282264Sjacobs 		return (VTAG_INTEGER);
1292264Sjacobs 	case VTAG_URI:
1302264Sjacobs 	case VTAG_OCTET_STRING:
1312264Sjacobs 	case VTAG_TEXT_WITHOUT_LANGUAGE:
1322264Sjacobs 	case VTAG_URI_SCHEME:
1332264Sjacobs 	case VTAG_CHARSET:
1342264Sjacobs 	case VTAG_NATURAL_LANGUAGE:
1352264Sjacobs 	case VTAG_MIME_MEDIA_TYPE:
1362264Sjacobs 	case VTAG_NAME_WITHOUT_LANGUAGE:
1372264Sjacobs 	case VTAG_KEYWORD:
1382264Sjacobs 		return (VTAG_TEXT_WITHOUT_LANGUAGE);
1392264Sjacobs 	case VTAG_BOOLEAN:
1402264Sjacobs 	case VTAG_RANGE_OF_INTEGER:
1412264Sjacobs 	case VTAG_DATE_TIME:
1422264Sjacobs 	case VTAG_RESOLUTION:
1432264Sjacobs 	default:
1442264Sjacobs 		return (i);
1452264Sjacobs 	}
1462264Sjacobs }
1472264Sjacobs 
1482264Sjacobs /* verify that the IPP type is correct for the named attribute */
1492264Sjacobs static papi_status_t
validate_type(char * name,int8_t type)1502264Sjacobs validate_type(char *name, int8_t type)
1512264Sjacobs {
1522264Sjacobs 	int8_t t = name_to_ipp_type(name);
1532264Sjacobs 
1542264Sjacobs 	if (t == 0)		/* The attribute is not defined in the RFC */
1552264Sjacobs 		return (PAPI_NOT_FOUND);
1562264Sjacobs 	else if (t == type)	/* The supplied type matched the RFC type */
1572264Sjacobs 		return (PAPI_OK);
1582264Sjacobs 	else {			/* The supplied type doesn't match the RFC */
1592264Sjacobs 		if (base_type(t) == base_type(type))
1602264Sjacobs 			return (PAPI_OK);
1612264Sjacobs 
1622264Sjacobs 		return (PAPI_CONFLICT);
1632264Sjacobs 	}
1642264Sjacobs }
1652264Sjacobs 
1662264Sjacobs /* verify that the IPP value is within specification for the named attribute */
1672264Sjacobs static int
validate_value(papi_attribute_t *** message,char * name,int8_t type,...)1682264Sjacobs validate_value(papi_attribute_t ***message, char *name, int8_t type, ...)
1692264Sjacobs {
1702264Sjacobs #define	within(a, b, c)	((b >= a) && (b <= c))
1712264Sjacobs 	va_list ap;
1722264Sjacobs 	int rc = -1;
1732264Sjacobs 	int min = min_val_len(type, name),
1742264Sjacobs 	    max = max_val_len(type, name);
1752264Sjacobs 	char buf[64];	/* For _ipp_<...>_string() */
1762264Sjacobs 
1772264Sjacobs 	va_start(ap, type);
1782264Sjacobs 	switch (type) {
1792264Sjacobs 	case VTAG_ENUM:
1802264Sjacobs 	case VTAG_INTEGER: {
1812264Sjacobs 		int32_t i = (int32_t)va_arg(ap, int32_t);
1822264Sjacobs 
1832264Sjacobs 		if (within(min, i, max))
1842264Sjacobs 			rc = 0;
1852264Sjacobs 		else
1862264Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
1872264Sjacobs 				"%s(%s): %d: out of range (%d - %d)", name,
1882264Sjacobs 				_ipp_tag_string(type), i, min, max);
1892264Sjacobs 		}
1902264Sjacobs 		break;
1912264Sjacobs 	case VTAG_BOOLEAN: {
1922264Sjacobs 		int8_t v = (int8_t)va_arg(ap, int);
1932264Sjacobs 
1942264Sjacobs 		if (within(0, v, 1))
1952264Sjacobs 			rc = 0;
1962264Sjacobs 		else
1972264Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
1982264Sjacobs 				"%s(%s): %d: out of range (0 - 1)", name,
1992264Sjacobs 				_ipp_tag_string(type), v);
2002264Sjacobs 		}
2012264Sjacobs 		break;
2022264Sjacobs 	case VTAG_RANGE_OF_INTEGER: {
2032264Sjacobs 		int32_t lower = (int32_t)va_arg(ap, int32_t);
2042264Sjacobs 		int32_t upper = (int32_t)va_arg(ap, int32_t);
2052264Sjacobs 
2062264Sjacobs 		if (within(min, lower, max) &&
2072264Sjacobs 		    within(min, upper, max))
2082264Sjacobs 			rc = 0;
2092264Sjacobs 		else
2102264Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
2112264Sjacobs 				"%s(%s): %d - %d: out of range (%d - %d)", name,
2122264Sjacobs 				_ipp_tag_string(type), lower, upper, min, max);
2132264Sjacobs 		}
2142264Sjacobs 		break;
2152264Sjacobs 	case VTAG_URI:
2162264Sjacobs 	case VTAG_OCTET_STRING:
2172264Sjacobs 	case VTAG_TEXT_WITHOUT_LANGUAGE:
2182264Sjacobs 	case VTAG_URI_SCHEME:
2192264Sjacobs 	case VTAG_CHARSET:
2202264Sjacobs 	case VTAG_NATURAL_LANGUAGE:
2212264Sjacobs 	case VTAG_MIME_MEDIA_TYPE:
2222264Sjacobs 	case VTAG_NAME_WITHOUT_LANGUAGE: {
2232264Sjacobs 		char *v = (char *)va_arg(ap, char *);
2242264Sjacobs 
2252264Sjacobs 		if (strlen(v) < max)
2262264Sjacobs 			rc = 0;
2272264Sjacobs 		else
2282264Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
2292264Sjacobs 				"%s(%s): %s: too long (max length: %d)", name,
2302264Sjacobs 				_ipp_tag_string(type), v, max);
2312264Sjacobs 		}
2322264Sjacobs 		break;
2332264Sjacobs 	case VTAG_KEYWORD: {
2342264Sjacobs 		char *v = (char *)va_arg(ap, char *);
2352264Sjacobs 
2362264Sjacobs 		if (strlen(v) >= max)
2372264Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
2382264Sjacobs 				"%s(%s): %s: too long (max length: %d)", name,
2392264Sjacobs 				_ipp_tag_string(type), v, max);
2402264Sjacobs 		else if (is_keyword(v) == 0)
2412264Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
2422264Sjacobs 				"%s(%s): %s: invalid keyword", name,
2432264Sjacobs 				_ipp_tag_string(type), v);
2442264Sjacobs 		else
2452264Sjacobs 			rc = 0;
2462264Sjacobs 		}
2472264Sjacobs 		break;
2482264Sjacobs 	case VTAG_DATE_TIME:
2492264Sjacobs 	case VTAG_RESOLUTION:
2502264Sjacobs 	default:
2512264Sjacobs 		rc = 0;
2522264Sjacobs 	}
2532264Sjacobs 	va_end(ap);
2542264Sjacobs 
2552264Sjacobs 	return (rc);
2562264Sjacobs #undef within
2572264Sjacobs }
2582264Sjacobs 
2592264Sjacobs /*
2602264Sjacobs  * read_attr_group() reads in enough of the message data to parse an entire
2612264Sjacobs  * attribute group.  Since to determine that the group is finished you have to
2622264Sjacobs  * read the character that determines the type of the next group, this function
2632264Sjacobs  * must return that character, in order that our caller knows how to call us for
2642264Sjacobs  * the next group.  Thus type is used both as an input parameter (the type of
2652264Sjacobs  * attribute group to read in) and an output parameter (the type of the next
2662264Sjacobs  * attribute group).
2672264Sjacobs  */
2682264Sjacobs 
2692264Sjacobs static papi_status_t
ipp_read_attribute_group(ipp_reader_t iread,void * fd,int8_t * type,papi_attribute_t *** message)2702264Sjacobs ipp_read_attribute_group(ipp_reader_t iread, void *fd, int8_t *type,
2712264Sjacobs 			papi_attribute_t ***message)
2722264Sjacobs {
2732264Sjacobs 	int8_t value_tag;
2742264Sjacobs 	uint16_t name_length, value_length;
2752264Sjacobs 	papi_attribute_t **attributes = NULL;
2762264Sjacobs 	char *name = NULL;
2772264Sjacobs 	int i;
2782264Sjacobs 	char buf[64];	/* For _ipp_<...>_string() */
2792264Sjacobs 
2802264Sjacobs 	/*
2812264Sjacobs 	 * RFC2910 3.3 says we need to handle `An expected but missing
2822264Sjacobs 	 * "begin-attribute-group-tag" field.  How?
2832264Sjacobs 	 */
2842264Sjacobs 	if (*type > DTAG_MAX)  {
2852264Sjacobs 		/* Scream bloody murder, or assign a new type? */
2862264Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
2872264Sjacobs 			"Bad attribute group tag 0x%.2hx (%s)",
2882264Sjacobs 			*type, _ipp_tag_string(*type));
2892264Sjacobs 		return (PAPI_BAD_REQUEST);
2902264Sjacobs 	}
2912264Sjacobs 
2922264Sjacobs 	/* This loops through *values* not *attributes*! */
2932264Sjacobs 	for (i = 0; ; i++) {
2942264Sjacobs 		papi_status_t valid = PAPI_OK;
2952264Sjacobs 		if (iread(fd, &value_tag, 1) != 1) {
2962264Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
2972264Sjacobs 				"bad read: value tag\n");
2982264Sjacobs 			return (PAPI_BAD_REQUEST);
2992264Sjacobs 		}
3002264Sjacobs 		/* are we done with this group ? */
3012264Sjacobs 		if (value_tag <= DTAG_MAX)
3022264Sjacobs 			break;
3032264Sjacobs 
3042264Sjacobs 		if (iread(fd, &name_length, 2) != 2) {
3052264Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
3062264Sjacobs 				"bad read: name length\n");
3072264Sjacobs 			return (PAPI_BAD_REQUEST);
3082264Sjacobs 		}
3092264Sjacobs 		name_length = (uint16_t)ntohs(name_length);
3102264Sjacobs 
3112264Sjacobs 		/* Not just another value for the previous attribute */
3122264Sjacobs 		if (name_length != 0) {
3132264Sjacobs 			if ((name = alloca(name_length + 1)) == NULL) {
3142264Sjacobs 				ipp_set_status(message, PAPI_TEMPORARY_ERROR,
3152264Sjacobs 					"alloca(): failed\n");
3162264Sjacobs 				return (PAPI_TEMPORARY_ERROR);
3172264Sjacobs 			}
3182264Sjacobs 			(void) memset(name, 0, name_length + 1);
3192264Sjacobs 
3202264Sjacobs 			if (iread(fd, name, name_length) != name_length) {
3212264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
3222264Sjacobs 					"bad read: name\n");
3232264Sjacobs 				return (PAPI_BAD_REQUEST);
3242264Sjacobs 			}
3252264Sjacobs 		}
3262264Sjacobs 
3272264Sjacobs 		valid = validate_type(name, value_tag);
3282264Sjacobs 		if ((valid != PAPI_OK) && (valid != PAPI_NOT_FOUND))
3292264Sjacobs 			ipp_set_status(message, valid, "%s(%s): %s", name,
3302264Sjacobs 				_ipp_tag_string(value_tag),
3312264Sjacobs 				papiStatusString(valid));
3322264Sjacobs 
3332264Sjacobs 		if (iread(fd, &value_length, 2) != 2) {
3342264Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
3352264Sjacobs 				"bad read: value length\n");
3362264Sjacobs 			return (PAPI_BAD_REQUEST);
3372264Sjacobs 		}
3382264Sjacobs 		value_length = (uint16_t)ntohs(value_length);
3392264Sjacobs 
3402264Sjacobs 		if (validate_length(value_tag, value_length) < 0) {
3412264Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
3422264Sjacobs 				"Bad value length (%d) for type %s",
3432264Sjacobs 				value_length, _ipp_tag_string(value_tag));
3442264Sjacobs 			return (PAPI_BAD_REQUEST);
3452264Sjacobs 		}
3462264Sjacobs 
3472264Sjacobs 		switch (value_tag) {
3482264Sjacobs 		case VTAG_INTEGER:
3492264Sjacobs 		case VTAG_ENUM: {
3502264Sjacobs 			int32_t v;
3512264Sjacobs 
3522264Sjacobs 			if (iread(fd, &v, value_length) != value_length) {
3532264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
3542264Sjacobs 					"bad read: int/enum\n");
3552264Sjacobs 				return (PAPI_BAD_REQUEST);
3562264Sjacobs 			}
3572264Sjacobs 			v = (int32_t)ntohl(v);
3582264Sjacobs 			(void) validate_value(message, name, value_tag, v);
3592264Sjacobs 			papiAttributeListAddInteger(&attributes,
3602264Sjacobs 						PAPI_ATTR_APPEND, name, v);
3612264Sjacobs 
3622264Sjacobs 			}
3632264Sjacobs 			break;
3642264Sjacobs 		case VTAG_BOOLEAN: {
3652264Sjacobs 			int8_t v;
3662264Sjacobs 
3672264Sjacobs 			if (iread(fd, &v, value_length) != value_length) {
3682264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
3692264Sjacobs 					"bad read: boolean\n");
3702264Sjacobs 				return (PAPI_BAD_REQUEST);
3712264Sjacobs 			}
3722264Sjacobs 			(void) validate_value(message, name, value_tag, v);
3732264Sjacobs 			papiAttributeListAddBoolean(&attributes,
3742264Sjacobs 						PAPI_ATTR_APPEND, name, v);
3752264Sjacobs 			}
3762264Sjacobs 			break;
3772264Sjacobs 		case VTAG_RANGE_OF_INTEGER: {
3782264Sjacobs 			int32_t min, max;
3792264Sjacobs 
3802264Sjacobs 			if (iread(fd, &min, 4) != 4) {
3812264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
3822264Sjacobs 					"bad read: min\n");
3832264Sjacobs 				return (PAPI_BAD_REQUEST);
3842264Sjacobs 			}
3852264Sjacobs 			if (iread(fd, &max, 4) != 4) {
3862264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
3872264Sjacobs 					"bad read: max\n");
3882264Sjacobs 				return (PAPI_BAD_REQUEST);
3892264Sjacobs 			}
3902264Sjacobs 			min = (int32_t)ntohl(min);
3912264Sjacobs 			max = (int32_t)ntohl(max);
3922264Sjacobs 			(void) validate_value(message, name, value_tag,
3932264Sjacobs 					min, max);
3942264Sjacobs 			papiAttributeListAddRange(&attributes, PAPI_ATTR_APPEND,
3952264Sjacobs 						name, min, max);
3962264Sjacobs 			}
3972264Sjacobs 			break;
3982264Sjacobs 		case VTAG_RESOLUTION: {
3992264Sjacobs 			int32_t x, y;
4002264Sjacobs 			int8_t units;
4012264Sjacobs 
4022264Sjacobs 			if (iread(fd, &x, 4) != 4) {
4032264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4042264Sjacobs 					"bad read: x\n");
4052264Sjacobs 				return (PAPI_BAD_REQUEST);
4062264Sjacobs 			}
4072264Sjacobs 			if (iread(fd, &y, 4) != 4) {
4082264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4092264Sjacobs 					"bad read: y\n");
4102264Sjacobs 				return (PAPI_BAD_REQUEST);
4112264Sjacobs 			}
4122264Sjacobs 			if (iread(fd, &units, 1) != 1) {
4132264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4142264Sjacobs 					"bad read: units\n");
4152264Sjacobs 				return (PAPI_BAD_REQUEST);
4162264Sjacobs 			}
4172264Sjacobs 			x = (int32_t)ntohl(x);
4182264Sjacobs 			y = (int32_t)ntohl(y);
4192264Sjacobs 			papiAttributeListAddResolution(&attributes,
4202264Sjacobs 						PAPI_ATTR_APPEND, name, x, y,
4212264Sjacobs 						(papi_resolution_unit_t)units);
4222264Sjacobs 			}
4232264Sjacobs 			break;
4242264Sjacobs 		case VTAG_DATE_TIME: {
4252264Sjacobs 			struct tm tm;
4262264Sjacobs 			time_t v;
4272264Sjacobs 			int8_t c;
4282264Sjacobs 			uint16_t s;
4292264Sjacobs 
4302264Sjacobs 			(void) memset(&tm, 0, sizeof (tm));
4312264Sjacobs 			if (iread(fd, &s, 2) != 2) {
4322264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4332264Sjacobs 					"bad read: year\n");
4342264Sjacobs 				return (PAPI_BAD_REQUEST);
4352264Sjacobs 			}
4362264Sjacobs 			tm.tm_year = (uint16_t)ntohs(s) - 1900;
4372264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4382264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4392264Sjacobs 					"bad read: month\n");
4402264Sjacobs 				return (PAPI_BAD_REQUEST);
4412264Sjacobs 			}
4422264Sjacobs 			tm.tm_mon = c - 1;
4432264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4442264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4452264Sjacobs 					"bad read: day\n");
4462264Sjacobs 				return (PAPI_BAD_REQUEST);
4472264Sjacobs 			}
4482264Sjacobs 			tm.tm_mday = c;
4492264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4502264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4512264Sjacobs 					"bad read: hour\n");
4522264Sjacobs 				return (PAPI_BAD_REQUEST);
4532264Sjacobs 			}
4542264Sjacobs 			tm.tm_hour = c;
4552264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4562264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4572264Sjacobs 					"bad read: minutes\n");
4582264Sjacobs 				return (PAPI_BAD_REQUEST);
4592264Sjacobs 			}
4602264Sjacobs 			tm.tm_min = c;
4612264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4622264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4632264Sjacobs 					"bad read: seconds\n");
4642264Sjacobs 				return (PAPI_BAD_REQUEST);
4652264Sjacobs 			}
4662264Sjacobs 			tm.tm_sec = c;
4672264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4682264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4692264Sjacobs 					"bad read: decisec\n");
4702264Sjacobs 				return (PAPI_BAD_REQUEST);
4712264Sjacobs 			}
4722264Sjacobs 			/* tm.deciseconds = c; */
4732264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4742264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4752264Sjacobs 					"bad read: utc_dir\n");
4762264Sjacobs 				return (PAPI_BAD_REQUEST);
4772264Sjacobs 			}
4782264Sjacobs 			/* tm.utc_dir = c; */
4792264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4802264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4812264Sjacobs 					"bad read: utc_hour\n");
4822264Sjacobs 				return (PAPI_BAD_REQUEST);
4832264Sjacobs 			}
4842264Sjacobs 			/* tm.utc_hours = c; */
4852264Sjacobs 			if (iread(fd, &c, 1) != 1) {
4862264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
4872264Sjacobs 					"bad read: utc_min\n");
4882264Sjacobs 				return (PAPI_BAD_REQUEST);
4892264Sjacobs 			}
4902264Sjacobs 			/* tm.utc_minutes = c; */
4912264Sjacobs 
4922264Sjacobs 			v = mktime(&tm);
4932264Sjacobs 
4942264Sjacobs 			(void) validate_value(message, name, value_tag, v);
4952264Sjacobs 			papiAttributeListAddDatetime(&attributes,
4962264Sjacobs 						PAPI_ATTR_APPEND, name, v);
4972264Sjacobs 			}
4982264Sjacobs 			break;
4992264Sjacobs 		case VTAG_NAME_WITH_LANGUAGE:
5002264Sjacobs 		case VTAG_TEXT_WITH_LANGUAGE:
5012264Sjacobs 			/*
5022264Sjacobs 			 * we are dropping this because we don't support
5032264Sjacobs 			 * name with language at this time.
5042264Sjacobs 			 */
5052264Sjacobs 			(void) read_name_with_language(iread, fd, message);
5062264Sjacobs 			break;
5072264Sjacobs 		case VTAG_NAME_WITHOUT_LANGUAGE:
5082264Sjacobs 		case VTAG_TEXT_WITHOUT_LANGUAGE:
5092264Sjacobs 		case VTAG_URI:
5102264Sjacobs 		case VTAG_KEYWORD:
5112264Sjacobs 		case VTAG_CHARSET: {
5122264Sjacobs 			char *v;
5132264Sjacobs 
5142264Sjacobs 			if ((v = calloc(1, value_length + 1)) == NULL) {
5152264Sjacobs 				ipp_set_status(message, PAPI_TEMPORARY_ERROR,
5162264Sjacobs 					"calloc(): failed\n");
5172264Sjacobs 				return (PAPI_TEMPORARY_ERROR);
5182264Sjacobs 			}
5192264Sjacobs #ifdef NOTDEF
5202264Sjacobs 			if (iread(fd, v, value_length) != value_length) {
5212264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
5222264Sjacobs 					"bad read: stringy\n");
5232264Sjacobs 				return (PAPI_BAD_REQUEST);
5242264Sjacobs 			}
5252264Sjacobs #else
5262264Sjacobs 			{
5272264Sjacobs 			int rc, i = value_length;
5282264Sjacobs 			char *p = v;
5292264Sjacobs 
5302264Sjacobs 			while ((rc = iread(fd, p, i)) != i) {
5312264Sjacobs 				if (rc <= 0) {
5322264Sjacobs 					ipp_set_status(message,
5332264Sjacobs 						PAPI_BAD_REQUEST,
5342264Sjacobs 						"bad read: stringy\n");
5352264Sjacobs 					return (PAPI_BAD_REQUEST);
5362264Sjacobs 				}
5372264Sjacobs 				i -= rc;
5382264Sjacobs 				p += rc;
5392264Sjacobs 			}
5402264Sjacobs 			}
5412264Sjacobs #endif
5422264Sjacobs 			(void) validate_value(message, name, value_tag, v);
5432264Sjacobs 			papiAttributeListAddString(&attributes,
5442264Sjacobs 						PAPI_ATTR_APPEND, name, v);
5452264Sjacobs 			}
5462264Sjacobs 			break;
5472264Sjacobs 		case VTAG_UNKNOWN:
5482264Sjacobs 		case VTAG_NOVALUE:
5492264Sjacobs 		case VTAG_UNSUPPORTED:
5502264Sjacobs 			papiAttributeListAddValue(&attributes, PAPI_ATTR_EXCL,
5512264Sjacobs 					name, PAPI_COLLECTION, NULL);
5522264Sjacobs 			break;
5532264Sjacobs 		default: {
5542264Sjacobs 			char *v;
5552264Sjacobs 
5562264Sjacobs 			if ((v = calloc(1, value_length + 1)) == NULL) {
5572264Sjacobs 				ipp_set_status(message, PAPI_TEMPORARY_ERROR,
5582264Sjacobs 					"calloc(): failed\n");
5592264Sjacobs 				return (PAPI_TEMPORARY_ERROR);
5602264Sjacobs 			}
5612264Sjacobs 			if (iread(fd, v, value_length) != value_length) {
5622264Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
5632264Sjacobs 					"bad read: other\n");
5642264Sjacobs 				return (PAPI_BAD_REQUEST);
5652264Sjacobs 			}
5662264Sjacobs 			papiAttributeListAddString(&attributes,
5672264Sjacobs 						PAPI_ATTR_APPEND, name, v);
5682264Sjacobs 			}
5692264Sjacobs 			break;
5702264Sjacobs 		}
5712264Sjacobs 	}
5722264Sjacobs 
5732264Sjacobs 	if (attributes != NULL) {
5742264Sjacobs 		char name[32];
5752264Sjacobs 
5762264Sjacobs 		(void) ipp_tag_string(*type, name, sizeof (name));
5772264Sjacobs 		papiAttributeListAddCollection(message, PAPI_ATTR_APPEND, name,
5782264Sjacobs 					attributes);
5792264Sjacobs 	}
5802264Sjacobs 
5812264Sjacobs 	*type = value_tag;
5822264Sjacobs 
5832264Sjacobs 	return (PAPI_OK);
5842264Sjacobs }
5852264Sjacobs 
5862264Sjacobs 
5872264Sjacobs static papi_status_t
ipp_read_header(ipp_reader_t iread,void * fd,papi_attribute_t *** message,char type)5882264Sjacobs ipp_read_header(ipp_reader_t iread, void *fd, papi_attribute_t ***message,
5892264Sjacobs 		char type)
5902264Sjacobs {
5912264Sjacobs 	char *attr_name = "status-code";	/* default to a response */
5922264Sjacobs 	char buf[8];
5932264Sjacobs 	int8_t c;
5942264Sjacobs 	uint16_t s;
5952264Sjacobs 	int32_t i;
5962264Sjacobs 
5972264Sjacobs 	if ((iread == NULL) || (fd == NULL) || (message == NULL))
5982264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5992264Sjacobs 
6002264Sjacobs 	/*
6012264Sjacobs 	 * Apache 1.X uses the buffer supplied to it's read call to read in
6022264Sjacobs 	 * the chunk size when chunking is used.  This causes problems
6032264Sjacobs 	 * reading the header a piece at a time, because we don't have
6042264Sjacobs 	 * enough room to read in the chunk size prior to reading the
6052264Sjacobs 	 * chunk.
6062264Sjacobs 	 */
6072264Sjacobs 
6082264Sjacobs 	if (iread(fd, buf, 8) != 8)
6092264Sjacobs 		return (PAPI_BAD_REQUEST);
6102264Sjacobs 
6112264Sjacobs 	c = buf[0];
6122264Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
6132264Sjacobs 				"version-major", c);
6142264Sjacobs 
6152264Sjacobs 	c = buf[1];
6162264Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
6172264Sjacobs 				"version-minor", c);
6182264Sjacobs 
6192264Sjacobs 	memcpy(&s, &buf[2], 2);
6202264Sjacobs 	s = (uint16_t)ntohs(s);
6212264Sjacobs 	if (type == IPP_TYPE_REQUEST)
6222264Sjacobs 		attr_name = "operation-id";
6232264Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
6242264Sjacobs 				attr_name, s);
6252264Sjacobs 
626*4030Sjacobs 	memcpy(&i, &buf[4], 4);
6272264Sjacobs 	i = (uint32_t)ntohl(i);
6282264Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
6292264Sjacobs 				"request-id", i);
6302264Sjacobs 
6312264Sjacobs 	return (PAPI_OK);
6322264Sjacobs }
6332264Sjacobs 
6342264Sjacobs static papi_status_t
ipp_read_attribute_groups(ipp_reader_t iread,void * fd,papi_attribute_t *** message)6352264Sjacobs ipp_read_attribute_groups(ipp_reader_t iread, void *fd,
6362264Sjacobs 			papi_attribute_t ***message)
6372264Sjacobs {
6382264Sjacobs 	papi_status_t result = PAPI_OK;
6392264Sjacobs 	int8_t tag;
6402264Sjacobs 
6412264Sjacobs 	/* start reading the attribute groups */
6422264Sjacobs 	if (iread(fd, &tag, 1) != 1)	/* prime the pump */
6432264Sjacobs 		return (PAPI_BAD_REQUEST);
6442264Sjacobs 
6452264Sjacobs 	while ((tag != DTAG_END_OF_ATTRIBUTES) && (result == PAPI_OK)) {
6462264Sjacobs 		result = ipp_read_attribute_group(iread, fd, &tag, message);
6472264Sjacobs 	}
6482264Sjacobs 
6492264Sjacobs 	return (result);
6502264Sjacobs }
6512264Sjacobs 
6522264Sjacobs papi_status_t
ipp_read_message(ipp_reader_t iread,void * fd,papi_attribute_t *** message,char type)6532264Sjacobs ipp_read_message(ipp_reader_t iread, void *fd, papi_attribute_t ***message,
6542264Sjacobs 		char type)
6552264Sjacobs {
6562264Sjacobs 	papi_status_t result = PAPI_OK;
6572264Sjacobs 
6582264Sjacobs 	if ((iread == NULL) || (fd == NULL) || (message == NULL))
6592264Sjacobs 		return (PAPI_BAD_ARGUMENT);
6602264Sjacobs 
6612264Sjacobs 	result = ipp_read_header(iread, fd, message, type);
6622264Sjacobs 	if (result == PAPI_OK)
6632264Sjacobs 		result = ipp_read_attribute_groups(iread, fd, message);
6642264Sjacobs 
6652264Sjacobs 	return (result);
6662264Sjacobs }
667