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