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