/*
* 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: rcbputrec.c,v 1.22 2007/01/22 17:42:23 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_PUTREC -- Encode an entire record into an sm_rcb_P.
**
** Parameters:
** rcb -- sm_rcb_P object to append onto.
** flags -- flags
** sz -- size of record
** n -- size of for sm_rcb_open_enc(); see comments there!
** ... -- data
**
** Returns:
** usual sm_error code; ENOMEM, SM_E_OVFLW_SC, SM_E_OVFLW_NS,
** EINVAL, etc?
*/
sm_ret_T
sm_rcb_putrec(sm_rcb_P rcb, uint flags, uint32_t sz, int n, ...)
{
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 (SM_IS_FLAG(flags, RCB_PUTR_OPEN)) {
ret = sm_rcb_open_enc(rcb, n);
if (sm_is_err(ret))
goto error;
}
if (SM_IS_FLAG(flags, RCB_PUTR_FIRST)) {
/* encode rcb: placeholder for size */
ret = sm_rcb_putuint32(rcb, sz);
if (sm_is_err(ret))
goto err2;
}
/* we could call sm_rcb_putv() here, that avoids double code */
va_start(ap, n);
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;
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 !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;
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 (SM_IS_FLAG(flags, RCB_PUTR_CLOSE))
ret = sm_rcb_close_enc(rcb);
return SM_SUCCESS;
err1:
va_end(ap);
err2:
if (SM_IS_FLAG(flags, RCB_PUTR_CLOSE))
(void) sm_rcb_close_enc(rcb);
error:
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1