/*
 * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: rcbputv.c,v 1.30 2007/01/31 04:16:53 ca Exp $")

#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/rpool.h"
#include "sm/varargs.h"
#include "sm/limits.h"
#include "sm/strrcb.h"
#include "sm/rcb.h"
#include "sm/reccom.h"
#include "sm/str-int.h"
#if !SM_NO_CSTR
# include "sm/cstr.h"
#endif

/*
**  SM_RCB_PUTV -- Append a copy of items to an RCB
**
**	Parameters:
**		rcb -- RCB to append onto.
**		flags -- open_enc, put initial size, close_enc?
**		... -- data
**
**	Returns:
**		usual sm_error code; ENOMEM, SM_E_OVFLW_SC, SM_E_OVFLW_NS,
**			EINVAL, etc?
**
**	Side Effects: does not clean up rcb in case of an error.
**
**	Last code review: 2005-03-23 02:26:45
**	Last code change:
*/

sm_ret_T
sm_rcb_putv(sm_rcb_P rcb, uint flags, ...)
{
	int k;
	uint32_t rt, v;
	sm_str_P str;
#if !SM_NO_CSTR
	sm_cstr_P cstr;
#endif
	uchar *buf;
	uint len;
	sm_ret_T ret;
	va_list ap;

	SM_IS_RCB(rcb);
#if 0
//	if (SM_IS_FLAG(flags, RCB_PUTV_OPEN))
//	{
//		ret = sm_rcb_open_enc(rcb, n);
//		if (sm_is_err(ret))
//			return ret;
//	}
#endif /* 0 */
#if SM_RCB_CHECK
	SM_REQUIRE(SM_RCB_ENC == rcb->sm_rcb_state);
#endif

	if (SM_IS_FLAG(flags, RCB_PUTV_FIRST)) {
		/* encode rcb: placeholder for size */
		ret = sm_rcb_putuint32(rcb, 0);
		if (sm_is_err(ret))
			goto err2;
	}

	va_start(ap, flags);
	for (;;) {
		k = va_arg(ap, int);
		if (SM_RCBV_END == k)
			break;
		rt = va_arg(ap, uint32_t);
		switch (k) {
		  case SM_RCBV_INT:
			v = va_arg(ap, uint32_t);
			if (RT_NOSEND == rt)
				break;
			ret = sm_rcb_put3uint32(rcb, 4, rt, v);
			if (sm_is_err(ret))
				goto err1;
			break;
		  case SM_RCBV_INT64:
			{
				uint64_t u;

				u = va_arg(ap, uint64_t);
				if (RT_NOSEND == rt)
					break;
				ret = sm_rcb_put3uint64(rcb, 8, rt, u);
				if (sm_is_err(ret))
					goto err1;
			}
			break;
#if MTA_USE_RCBV_INT2
		  case SM_RCBV_INT2:
			{
				uint32_t v2;

				v = va_arg(ap, uint32_t);
				v2 = va_arg(ap, uint32_t);
				if (RT_NOSEND == rt)
					break;
				ret = sm_rcb_put4uint32(rcb, 8, rt, v, v2);
				if (sm_is_err(ret))
					goto err1;
			}
			break;
#endif /* MTA_USE_RCBV_INT2 */
		  case SM_RCBV_STR:
			str = va_arg(ap, sm_str_P);
			if (RT_NOSEND == rt)
				break;
			if (NULL == str) {
				ret = sm_rcb_put2uint32(rcb, 0, rt);
				if (sm_is_err(ret))
					goto err1;
				break;
			}
			SM_IS_BUF(str);
			ret = sm_rcb_put2uint32(rcb, sm_str_getlen(str), rt);
			if (sm_is_err(ret))
				goto err1;
			ret = sm_rcb_putn(rcb, sm_str_data(str), sm_str_getlen(str));
			if (sm_is_err(ret))
				goto err1;
			break;

#if MTA_USE_RCBV_STRN
		  case SM_RCBV_STRA:
			{
				uint nv;
				sm_str_P *strv;

				nv = va_arg(ap, uint);
				strv = va_arg(ap, sm_str_P *);
				if (RT_NOSEND == rt)
					break;
				ret = sm_rcb_putastr(rcb, rt, nv, strv);
				if (sm_is_err(ret))
					goto err1;
			}
			break;
#endif /* MTA_USE_RCBV_STRN */

#if !SM_NO_CSTR
		  case SM_RCBV_CSTR:
			cstr = va_arg(ap, sm_cstr_P);
			if (RT_NOSEND == rt)
				break;
			if (NULL == cstr) {
				ret = sm_rcb_put2uint32(rcb, 0, rt);
				if (sm_is_err(ret))
					goto err1;
				break;
			}
			SM_IS_CSTR(cstr);
			ret = sm_rcb_put2uint32(rcb, sm_cstr_getlen(cstr), rt);
			if (sm_is_err(ret))
				goto err1;
			ret = sm_rcb_putn(rcb, sm_cstr_data(cstr), sm_cstr_getlen(cstr));
			if (sm_is_err(ret))
				goto err1;
			break;
#endif /* !SM_NO_CSTR */
		  case SM_RCBV_BUF:
			buf = va_arg(ap, uchar *);
			len = va_arg(ap, uint);
			if (RT_NOSEND == rt)
				break;
			if (NULL == buf) {
				/* len should be 0 */
				ret = sm_rcb_put2uint32(rcb, 0, rt);
				if (sm_is_err(ret))
					goto err1;
				break;
			}
			ret = sm_rcb_put2uint32(rcb, len, rt);
			if (sm_is_err(ret))
				goto err1;
			ret = sm_rcb_putn(rcb, buf, len);
			if (sm_is_err(ret))
				goto err1;
			break;
#if MTA_USE_RCBV_INTN
		  case SM_RCBV_INTA:
			{
				uint32_t *av;
				uint nv;

				nv = va_arg(ap, uint);
				av = va_arg(ap, uint32_t *);
				if (RT_NOSEND == rt)
					break;
				ret = sm_rcb_putauint32(rcb, rt, nv, av);
				if (sm_is_err(ret))
					goto err1;
			}
			break;
#endif /* MTA_USE_RCBV_INTN */
		  default:
			ret = sm_error_perm(SM_EM_RECCOM, EINVAL);
			goto err1;
		}
	}
	va_end(ap);

#if 0
//	if (SM_IS_FLAG(flags, RCB_PUTV_CLOSE))
//	{
//		ret = sm_rcb_close_enc(rcb);
//		if (sm_is_err(ret))
//			goto error;
//	}
#endif /* 0 */

	return SM_SUCCESS;

  err1:
	va_end(ap);

  err2:
#if 0
//	if (SM_IS_FLAG(flags, RCB_PUTV_CLOSE))
//		(void) sm_rcb_close_encn(rcb);
#endif
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1