/*
* 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: rcbopen.c,v 1.15 2005/06/02 19:00:36 ca Exp $")
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/memops.h"
#include "sm/rpool.h"
#include "sm/str-int.h"
#include "sm/rcb.h"
#include "sm/str2rcb.h"
#include "sm/reccom.h"
/*
** SM_RCB_OPEN_RCV -- Open rcb for receiving data from file.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-03-29 17:32:35
** Last code change:
*/
sm_ret_T
sm_rcb_open_rcv(sm_rcb_P rcb)
{
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE);
#endif
rcb->sm_rcb_len = 0;
rcb->sm_rcb_rw = -1;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_RCV;
#endif
return SM_SUCCESS;
}
/*
** SM_RCB_OPEN_DEC -- Open rcb for decoding data.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** SM_SUCCESS (unless SM_RCB_END_RCB is set)
**
** Last code review: 2005-03-29 05:21:31
** Last code change:
*/
sm_ret_T
sm_rcb_open_dec(sm_rcb_P rcb)
{
#if SM_RCB_END_RCB
uint32_t v, tl;
#endif
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE);
#endif
#if SM_RCB_END_RCB
if (rcb->sm_rcb_len < 12)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
if ((rcb->sm_rcb_len % 4) != 0)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw = rcb->sm_rcb_len - 12;
sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
if (v != 4)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw += sizeof(uint32_t);
sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
if (v != RT_END_OF_RCB)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw += sizeof(uint32_t);
sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
sm_buf2uint32(rcb->sm_rcb_base, &tl);
if (v != tl)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
#endif /* SM_RCB_END_RCB */
rcb->sm_rcb_rw = 0;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_DEC;
#endif
return SM_SUCCESS;
}
/*
** SM_RCB_OPEN_ENC -- Open rcb for encoding data into it.
**
** Parameters:
** rcb -- sm_rcb_P object.
** n -- 1. maximum size for encoded data, -1: no explicit limit
** (just implicit by max length sm_rcb_max)
** 2. minimum size requested for RCB.
** fixme: should these be two different parameters??
** Note: all applications use -1 (only test programs use
** different values).
**
** Returns:
** usual sm_error code; ENOMEM, SM_E_OVFLW_NS
**
** Side Effects: none on error.
**
** Last code review: 2005-03-22 17:44:11
** Last code change:
*/
sm_ret_T
sm_rcb_open_enc(sm_rcb_P rcb, int n)
{
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE);
#endif
rcb->sm_rcb_len = 0;
if (n > 0 && (uint)n > rcb->sm_rcb_size)
{
uint u;
u = (uint)n;
SM_STR_INCREASE_R(rcb, u);
}
rcb->sm_rcb_rw = n;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_ENC;
#endif
return SM_SUCCESS;
}
/*
** SM_RCB_OPEN_SND -- Open rcb for sending data from it.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-03-22 23:23:53
** Last code change:
*/
sm_ret_T
sm_rcb_open_snd(sm_rcb_P rcb)
{
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_NONE);
#endif
rcb->sm_rcb_rw = 0;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_SND;
#endif
return SM_SUCCESS;
}
/*
** SM_RCB_CLOSE_RCV -- Close rcb after receiving data from file.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** SM_SUCCESS (unless SM_RCB_END_RCB is set)
**
** Last code review: 2005-03-29 05:20:13
** Last code change:
*/
sm_ret_T
sm_rcb_close_rcv(sm_rcb_P rcb)
{
#if SM_RCB_END_RCB
uint32_t v, tl;
#endif
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_RCV);
SM_REQUIRE(rcb->sm_rcb_size >= rcb->sm_rcb_len);
SM_REQUIRE(rcb->sm_rcb_size <= rcb->sm_rcb_max);
#endif
#if SM_RCB_END_RCB
if (rcb->sm_rcb_len < 12)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
if ((rcb->sm_rcb_len % 4) != 0)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw = rcb->sm_rcb_len - 12;
sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
if (v != 4)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw += sizeof(uint32_t);
sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
if (v != RT_END_OF_RCB)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw += sizeof(uint32_t);
sm_buf2uint32(rcb->sm_rcb_base + rcb->sm_rcb_rw, &v);
sm_buf2uint32(rcb->sm_rcb_base, &tl);
if (v != tl)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
#endif /* SM_RCB_END_RCB */
rcb->sm_rcb_rw = 0;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_NONE;
#endif
return SM_SUCCESS;
}
/*
** SM_RCB_CLOSE_DEC -- Close rcb after decoding data.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-03-29 21:33:33
** Last code change:
*/
sm_ret_T
sm_rcb_close_dec(sm_rcb_P rcb)
{
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_DEC);
SM_REQUIRE(rcb->sm_rcb_size >= rcb->sm_rcb_len);
SM_REQUIRE(rcb->sm_rcb_size <= rcb->sm_rcb_max);
#endif
rcb->sm_rcb_rw = 0;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_NONE;
#endif
return SM_SUCCESS;
}
/*
** SM_RCB_CLOSE_ENC -- Close rcb after encoding data into it.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** usual sm_error code; EINVAL (SM_RCB_END_RCB: ENOMEM, etc)
** (fails only if rcb is improperly used)
**
** Side Effects: resets state even on error.
**
** Last code review: 2005-03-22 22:58:10
** Last code change:
*/
sm_ret_T
sm_rcb_close_enc(sm_rcb_P rcb)
{
uint32_t len;
#if SM_RCB_END_RCB
sm_ret_T ret;
#endif
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_ENC);
/* reset state even if an error occurs? */
rcb->sm_rcb_state = SM_RCB_NONE;
#endif /* SM_RCB_CHECK */
if (rcb->sm_rcb_len <= sizeof(int))
return sm_error_perm(SM_EM_RECCOM, EINVAL);
SM_ASSERT(rcb->sm_rcb_len < UINT32_MAX);
#if SM_RCB_END_RCB
ret = sm_rcb_put3uint32(rcb, 4, RT_END_OF_RCB, rcb->sm_rcb_len + 12);
if (sm_is_err(ret))
return ret;
#endif
len = (uint32_t) (rcb->sm_rcb_len);
sm_uint32_2buf(len, rcb->sm_rcb_base);
return SM_SUCCESS;
}
/*
** SM_RCB_CLOSE_SND -- Close rcb after sending data from it.
**
** Parameters:
** rcb -- sm_rcb_P object.
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-03-30 22:51:51
** Last code change:
*/
sm_ret_T
sm_rcb_close_snd(sm_rcb_P rcb)
{
SM_IS_RCB(rcb);
SM_REQUIRE(rcb->sm_rcb_base != NULL);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_SND);
#endif
rcb->sm_rcb_rw = 0;
#if SM_RCB_CHECK
rcb->sm_rcb_state = SM_RCB_NONE;
#endif
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1