/*
* 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