/*
* Copyright (c) 2005, 2006 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: t-msgmod-0.c,v 1.24 2006/04/02 06:34:21 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/string.h"
#include "sm/str.h"
#include "sm/cstr.h"
#include "sm/io.h"
#include "sm/ctype.h"
#include "sm/mta.h"
#include "sm/da.h"
#include "smtpc.h"
#define SMTPC_LOG_DEFINES 1
#include "log.h"
#include "sm/test.h"
#include "sm/sysexits.h"
#define SC_PHASE_NOREPLY 0
/*
** SC_COMMAND -- send one SMTP command (dummy)
**
** Parameters:
** sc_t_ctx -- SMTPC thread context
** phase -- phase of SMTP dialogue
**
** Returns:
** SMTP reply code (2xy -> SMTP_OK) or error code
*/
static sm_ret_T
sc_command(sc_t_ctx_P sc_t_ctx, int phase)
{
sm_ret_T ret;
ssize_t b;
size_t l;
sc_sess_P sc_sess;
SM_REQUIRE(sc_t_ctx != NULL);
sc_sess = sc_t_ctx->sct_sess;
l = sm_str_getlen(sc_sess->scse_wr);
ret = sm_io_write(smioout, sm_str_data(sc_sess->scse_wr), l, &b);
return ret;
}
/* ----- BEGIN COPY FROM smtpc/smclt.c ----- */
/*
** SC_WRTBUF -- write buffer
**
** Parameters:
** sc_t_ctx -- SMTPC thread context
** buf -- buffer to write
** wrt -- number of bytes to write
** cfp -- output file
** ptotal_size -- (pointer to) total size (in/out)
**
** Returns:
** usual error code
*/
static sm_ret_T
sc_wrtbuf(sc_t_ctx_P sc_t_ctx, uchar *buf, size_t wrt, sm_file_T *cfp, off_t *ptotal_size)
{
size_t offset;
ssize_t byteswritten;
sm_ret_T ret;
off_t total_size;
ret = SM_SUCCESS;
if (wrt == 0)
return ret;
offset = 0;
total_size = *ptotal_size;
do
{
ret = sm_io_write(cfp, buf + offset, wrt, &byteswritten);
if (sm_is_err(ret))
return ret;
if (byteswritten > 0)
{
total_size += byteswritten;
offset += byteswritten;
}
/* paranoia... should this be just an if ()? */
SM_ASSERT(wrt >= byteswritten);
if (wrt > byteswritten)
sm_log_write(sc_t_ctx->sct_sc_ctx->scc_lctx,
SC_LCAT_CLIENT, SC_LMOD_CLIENT,
SM_LOG_INFO, 8,
"sev=INFO, func=sc_data, wrt=%d, written=%d, ret=%m",
wrt, byteswritten, ret);
wrt -= byteswritten;
} while (wrt > 0);
*ptotal_size = total_size;
return ret;
}
/*
** SC_MSGDSN -- send msg (with modifications for DSN)
**
** Parameters:
** sc_t_ctx -- SMTPC thread context
** ptotal_size -- (pointer to) total size (in/out)
**
** Returns:
** usual error code
*/
static sm_ret_T
sc_msgdsn(sc_t_ctx_P sc_t_ctx, off_t *ptotal_size)
{
int c;
size_t wrt, idx;
sm_ret_T ret;
uint eoh_state;
off_t total_size, cdb_rd;
sc_ta_P sc_ta;
sc_sess_P sc_sess;
sm_file_T *cfp;
static SM_DECL_EOH;
sc_sess = sc_t_ctx->sct_sess;
SM_REQUIRE(sc_sess != NULL);
sc_ta = sc_sess->scse_ta;
SM_IS_SC_TA(sc_ta);
cfp = sc_sess->scse_fp;
eoh_state = 0;
cdb_rd = 0;
total_size = *ptotal_size;
ret = SM_SUCCESS;
do
{
/* get new buffer */
c = sm_rget(sc_ta->scta_cdb_fp);
if (SM_IO_EOF == c)
break;
/* +1 because we got the first char already */
wrt = f_r(*(sc_ta->scta_cdb_fp)) + 1;
cdb_rd += wrt;
/* check whether eoh is in this block */
if (SCTA_IS_FLAG(sc_ta, SCTA_FL_HDR_ONLY)
&& eoh_state < SM_EOH_LEN)
{
uchar *p;
p = f_bfbase(*sc_ta->scta_cdb_fp);
idx = 0;
do
{
if (c == eoh[eoh_state])
++eoh_state;
else
{
eoh_state = 0;
if (c == eoh[eoh_state])
++eoh_state;
}
++idx;
if (idx < wrt)
c = p[idx];
} while (eoh_state < SM_EOH_LEN && idx < wrt);
/*
** Found end of header? If yes: set the
** number of bytes to write; the buffer
** MUST end with \r\n such that the final
** dot is properly recognized (see below).
*/
if (eoh_state >= SM_EOH_LEN)
{
SCTA_SET_FLAG(sc_ta, SCTA_FL_CUT_HDR);
wrt = idx;
}
}
/*
** For a MIME DSN the last 3 bytes (.\r\n)
** of cdb must not be sent.
*/
if (SCTA_IS_FLAG(sc_ta, SCTA_FL_DSN_MIME) &&
!SCTA_IS_FLAG(sc_ta, SCTA_FL_CDB_CUT) &&
cdb_rd + 3 >= sc_ta->scta_msg_sz_b
)
{
size_t cutoff;
SM_ASSERT(sc_ta->scta_msg_sz_b >= SM_EOT_LEN);
SM_ASSERT(cdb_rd <= sc_ta->scta_msg_sz_b);
cutoff = sc_ta->scta_msg_sz_b - cdb_rd + 3;
if (wrt > cutoff)
wrt -= cutoff;
else
wrt = 0;
SCTA_SET_FLAG(sc_ta, SCTA_FL_CUT_DOT);
}
ret = sc_wrtbuf(sc_t_ctx,
f_bfbase(*sc_ta->scta_cdb_fp), wrt, cfp, &total_size);
if (sm_is_err(ret))
goto error;
if (SCTA_IS_FLAG(sc_ta, SCTA_FL_CUT_HDR) ||
SCTA_IS_FLAG(sc_ta, SCTA_FL_CUT_DOT))
{
/* the data above ended with \r\n (eoh) */
if (SCTA_IS_FLAG(sc_ta, SCTA_FL_DSN_MIME))
{
if (sm_is_err(ret =
sm_str_scopy(sc_sess->scse_wr,
"\r\n--"))
|| sm_is_err(ret =
sm_str_cat(sc_sess->scse_wr,
sc_sess->scse_str))
|| sm_is_err(ret =
sm_str_scat(sc_sess->scse_wr,
"--\r\n.\r\n")))
goto error;
}
else
{
ret = sm_str_scopy(sc_sess->scse_wr,
".\r\n");
}
if (sm_is_err(ret))
goto error;
ret = sc_command(sc_t_ctx, SC_PHASE_NOREPLY);
if (sm_is_err(ret))
goto error;
c = SM_IO_EOF; /* force end of loop */
}
} while (c != SM_IO_EOF);
*ptotal_size = total_size;
return ret;
error:
*ptotal_size = total_size;
return ret;
}
/*
** SC_HDRS_APP -- append headers
**
** Parameters:
** sc_t_ctx -- SMTPC thread context
** sm_hdrmod -- current header to append
** ptotal_size -- (pointer to) total size (in/out)
**
** Returns:
** usual error code
*/
static sm_ret_T
sc_hdrs_app(sc_t_ctx_P sc_t_ctx, sm_hdrmod_P sm_hdrmod, off_t *ptotal_size)
{
sm_ret_T ret;
sc_ta_P sc_ta;
sc_sess_P sc_sess;
sm_file_T *cfp;
sm_cstr_P hdr;
sc_sess = sc_t_ctx->sct_sess;
SM_REQUIRE(sc_sess != NULL);
sc_ta = sc_sess->scse_ta;
SM_IS_SC_TA(sc_ta);
cfp = sc_sess->scse_fp;
ret = SM_SUCCESS;
while (sm_hdrmod != NULL &&
SM_HM_TYPE_APPEND == sm_hdrmod->sm_hm_type
&& (hdr = sm_hdrmod->sm_hm_hdr) != NULL)
{
ret = sc_wrtbuf(sc_t_ctx, sm_cstr_data(hdr),
sm_cstr_getlen(hdr),
cfp, ptotal_size);
sm_hdrmod_rm(&sc_ta->scta_hdrmodhd);
sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd);
}
return ret;
}
/*
** SC_HDRS_INS -- perform header insertions at a given position
**
** Parameters:
** sc_t_ctx -- SMTPC thread context
** hdr_count -- current header number
** writeit -- are we writing or skipping headers?
** idx -- current (read) index in file buffer
** poffset -- (ptr) current (write) offset in file buffer (in/out)
** ptotal_size -- (pointer to) total size (in/out)
**
** Returns:
** >0: number of header insertions
** <=0: usual error code
*/
static sm_ret_T
sc_hdrs_ins(sc_t_ctx_P sc_t_ctx, uint hdr_count, bool writeit, size_t idx, size_t *poffset, off_t *ptotal_size)
{
sm_ret_T ret;
uint mods;
sm_hdrmod_P sm_hdrmod;
sm_cstr_P hdr;
sc_ta_P sc_ta;
sc_sess_P sc_sess;
sm_file_T *cfp;
sc_sess = sc_t_ctx->sct_sess;
SM_REQUIRE(sc_sess != NULL);
sc_ta = sc_sess->scse_ta;
SM_IS_SC_TA(sc_ta);
mods = 0;
cfp = sc_sess->scse_fp;
if (writeit &&
(sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd)) != NULL &&
(SM_HM_TYPE_INSERT == sm_hdrmod->sm_hm_type ||
SM_HM_TYPE_REPLACE == sm_hdrmod->sm_hm_type) &&
hdr_count == sm_hdrmod->sm_hm_pos &&
(hdr = sm_hdrmod->sm_hm_hdr) != NULL)
{
size_t offset;
SM_ASSERT(poffset != NULL);
offset = *poffset;
SM_ASSERT(idx >= offset);
ret = sc_wrtbuf(sc_t_ctx,
f_bfbase(*sc_ta->scta_cdb_fp) + offset,
idx - offset, cfp, ptotal_size);
if (sm_is_err(ret))
return ret;
*poffset = idx;
}
while ((sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd)) != NULL &&
(SM_HM_TYPE_INSERT == sm_hdrmod->sm_hm_type ||
SM_HM_TYPE_REPLACE == sm_hdrmod->sm_hm_type) &&
hdr_count == sm_hdrmod->sm_hm_pos &&
(hdr = sm_hdrmod->sm_hm_hdr) != NULL)
{
++mods;
ret = sc_wrtbuf(sc_t_ctx, sm_cstr_data(hdr),
sm_cstr_getlen(hdr), cfp, ptotal_size);
if (sm_is_err(ret))
return ret;
sm_hdrmod_rm(&sc_ta->scta_hdrmodhd);
sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd);
}
return (mods > 0) ? mods : SM_SUCCESS;
}
/*
** SC_MSGMOD -- send msg (possibly with modifications)
**
** Parameters:
** sc_t_ctx -- SMTPC thread context
** ptotal_size -- (pointer to) total size (in/out)
**
** Returns:
** usual error code
*/
static sm_ret_T
sc_msgmod(sc_t_ctx_P sc_t_ctx, off_t *ptotal_size)
{
int c;
size_t wrt, idx;
sm_ret_T ret;
uint eoh_state;
uint hdr_count, eol_state;
bool writeit;
off_t total_size, cdb_rd;
sc_ta_P sc_ta;
sc_sess_P sc_sess;
sm_file_T *cfp;
sm_hdrmod_P sm_hdrmod;
sm_cstr_P hdr;
static SM_DECL_EOH;
static SM_DECL_EOL;
sc_sess = sc_t_ctx->sct_sess;
SM_REQUIRE(sc_sess != NULL);
sc_ta = sc_sess->scse_ta;
SM_IS_SC_TA(sc_ta);
cfp = sc_sess->scse_fp;
eoh_state = 0;
cdb_rd = 0;
total_size = *ptotal_size;
ret = SM_SUCCESS;
hdr_count = 0;
eol_state = 0;
writeit = true;
sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd);
while (sm_hdrmod != NULL &&
SM_HM_TYPE_PREPEND == sm_hdrmod->sm_hm_type &&
(hdr = sm_hdrmod->sm_hm_hdr) != NULL)
{
ret = sc_wrtbuf(sc_t_ctx, sm_cstr_data(hdr),
sm_cstr_getlen(hdr), cfp, &total_size);
if (sm_is_err(ret))
goto error;
sm_hdrmod_rm(&sc_ta->scta_hdrmodhd);
sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd);
}
if (sm_hdrmod != NULL &&
(SM_HM_TYPE_REMOVE == sm_hdrmod->sm_hm_type ||
SM_HM_TYPE_REPLACE == sm_hdrmod->sm_hm_type) &&
hdr_count == sm_hdrmod->sm_hm_pos)
writeit = false;
ret = sc_hdrs_ins(sc_t_ctx, hdr_count, false, 0, NULL, &total_size);
if (sm_is_err(ret))
goto error;
do
{
size_t offset;
offset = 0;
/* get new buffer */
c = sm_rget(sc_ta->scta_cdb_fp);
if (SM_IO_EOF == c)
break;
/* +1 because we got the first char already */
wrt = f_r(*(sc_ta->scta_cdb_fp)) + 1;
cdb_rd += wrt;
/* analyse current buffer (if it contains headers) */
if (SCTA_IS_FLAG(sc_ta, SCTA_FL_HDR_ONLY|SCTA_FL_HDR_SCAN)
&& eoh_state < SM_EOH_LEN)
{
uchar *p;
p = f_bfbase(*sc_ta->scta_cdb_fp);
idx = 0;
do
{
if (c == eoh[eoh_state])
++eoh_state;
else
{
eoh_state = 0;
if (c == eoh[eoh_state])
++eoh_state;
}
if (eol_state >= SM_EOL_LEN &&
c != ' ' && c != '\t')
{
bool hdr_rm;
++hdr_count;
hdr_rm = (sm_hdrmod != NULL &&
(SM_HM_TYPE_REMOVE ==
sm_hdrmod->sm_hm_type ||
SM_HM_TYPE_REPLACE ==
sm_hdrmod->sm_hm_type)
&& hdr_count ==
sm_hdrmod->sm_hm_pos);
if (hdr_rm &&
SM_HM_TYPE_REMOVE ==
sm_hdrmod->sm_hm_type)
{
sm_hdrmod_rm(&sc_ta->scta_hdrmodhd);
sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd);
}
if (writeit && hdr_rm)
{
SM_ASSERT(idx >= offset);
ret = sc_wrtbuf(sc_t_ctx,
f_bfbase(*sc_ta->scta_cdb_fp)
+ offset,
idx - offset,
cfp,
&total_size);
if (sm_is_err(ret))
goto error;
offset = idx;
if (c != '\r')
writeit = false;
}
else if (!writeit && !hdr_rm)
{
writeit = true;
offset = idx;
}
ret = sc_hdrs_ins(sc_t_ctx, hdr_count,
writeit, idx, &offset,
&total_size);
if (ret > 0)
sm_hdrmod = HDRMODL_FIRST(sc_ta->scta_hdrmodhd);
}
/*
** End of headers reached? This is not
** entirely correct as it just checks for CR
** not CR LF, but we have to "insert" these
** headers before the second CRLF
*/
if (eol_state >= SM_EOL_LEN && c == '\r' &&
sm_hdrmod != NULL &&
SM_HM_TYPE_APPEND == sm_hdrmod->sm_hm_type
&& sm_hdrmod->sm_hm_hdr != NULL)
{
ret = sc_wrtbuf(sc_t_ctx,
f_bfbase(*sc_ta->scta_cdb_fp)
+ offset,
idx - offset, cfp,
&total_size);
if (sm_is_err(ret))
goto error;
ret = sc_hdrs_app(sc_t_ctx, sm_hdrmod,
&total_size);
offset = idx;
}
if (c == eol[eol_state])
++eol_state;
else
{
eol_state = 0;
if (c == eol[eol_state])
++eol_state;
}
++idx;
if (idx < wrt)
c = p[idx];
} while (eoh_state < SM_EOH_LEN && idx < wrt);
}
if (writeit)
{
ret = sc_wrtbuf(sc_t_ctx,
f_bfbase(*sc_ta->scta_cdb_fp) + offset,
wrt - offset, cfp, &total_size);
if (sm_is_err(ret))
goto error;
}
} while (c != SM_IO_EOF);
*ptotal_size = total_size;
return ret;
error:
*ptotal_size = total_size;
return ret;
}
/* ----- END COPY FROM smtpc/smclt.c ----- */
static void
usage(const char *prg)
{
sm_io_fprintf(smioerr,
"usage: %s [options]\n"
"Test message modifications for delivery\n"
"options:\n"
"-b n set I/O buffer size to n\n"
"-d n delete header n\n"
"-f n set flags\n"
"-i pos=header insert header at pos\n"
"-M type=header prepend or append header\n"
" type=a or p\n"
"-r pos=header replace header at pos\n"
, prg);
}
int
main(int argc, char **argv)
{
int c;
unsigned long l;
sm_ret_T ret;
off_t total_size;
size_t size;
sc_ta_P sc_ta;
sc_sess_P sc_sess;
sc_t_ctx_P sc_t_ctx;
sc_ctx_P sc_ctx;
sm_hdrmod_P sm_hdrmod;
char hdr[256], *str;
sc_ta = NULL;
sc_ta = sm_zalloc(sizeof(*sc_ta));
if (NULL == sc_ta)
return(EX_OSERR);
sc_sess = sm_zalloc(sizeof(*sc_sess));
if (NULL == sc_sess)
return(EX_OSERR);
sc_t_ctx = sm_zalloc(sizeof(*sc_t_ctx));
if (NULL == sc_t_ctx)
return(EX_OSERR);
sc_ctx = sm_zalloc(sizeof(*sc_ctx));
if (NULL == sc_ctx)
return(EX_OSERR);
sc_t_ctx->sm_magic = SM_SC_T_CTX_MAGIC;
sc_sess->sm_magic = SM_SC_SESS_MAGIC;
sc_ta->sm_magic = SM_SC_TA_MAGIC;
sc_t_ctx->sct_sc_ctx = sc_ctx;
sc_sess->scse_sct_ctx = sc_t_ctx;
sc_t_ctx->sct_sess = sc_sess;
sc_sess->scse_fp = smioout;
sc_sess->scse_ta = sc_ta;
while ((c = getopt(argc, argv, "b:d:f:i:M:r:")) != -1)
{
switch (c)
{
case 'b':
size = strtoul(optarg, NULL, 0);
ret = sm_io_setvbuf(smioin, NULL, SM_IO_FBF, size);
break;
case 'd':
sm_hdrmod = NULL;
ret = sm_hdrmod_new(&sc_ta->scta_hdrmodhd, false,
&sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
SM_TEST(sm_hdrmod != NULL);
if (NULL == sm_hdrmod)
return(EX_OSERR);
sm_hdrmod->sm_hm_type = SM_HM_TYPE_REMOVE;
sm_hdrmod->sm_hm_pos = strtoul(optarg, NULL, 0);
ret = sm_hdrmod_insert(sc_ta->scta_hdrmodhd, sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
SCTA_SET_FLAG(sc_ta, SCTA_FL_HDR_SCAN);
break;
case 'f':
sc_ta->scta_flags = strtol(optarg, NULL, 0);
break;
case 'i':
l = strtoul(optarg, &str, 0);
if (ULONG_MAX == l || l > UINT_MAX)
usage(argv[0]);
if (NULL == str || *str != '=')
usage(argv[0]);
sm_hdrmod = NULL;
strlcpy(hdr, str + 1, sizeof(hdr));
strlcat(hdr, "\r\n", sizeof(hdr));
ret = sm_hdrmod_new(&sc_ta->scta_hdrmodhd, false,
&sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
SM_TEST(sm_hdrmod != NULL);
if (NULL == sm_hdrmod)
return(EX_OSERR);
sm_hdrmod->sm_hm_hdr = sm_cstr_scpyn0((const uchar *)hdr
, strlen(hdr));
sm_hdrmod->sm_hm_pos = l;
sm_hdrmod->sm_hm_type = SM_HM_TYPE_INSERT;
SCTA_SET_FLAG(sc_ta, SCTA_FL_HDR_SCAN);
ret = sm_hdrmod_insert(sc_ta->scta_hdrmodhd, sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
break;
case 'M':
if (optarg == NULL ||
(optarg[0] != 'p' && optarg[0] != 'a')
|| optarg[1] != '=')
{
usage(argv[0]);
break;
}
sm_hdrmod = NULL;
strlcpy(hdr, optarg + 2, sizeof(hdr));
strlcat(hdr, "\r\n", sizeof(hdr));
ret = sm_hdrmod_new(&sc_ta->scta_hdrmodhd, false,
&sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
SM_TEST(sm_hdrmod != NULL);
if (NULL == sm_hdrmod)
return(EX_OSERR);
sm_hdrmod->sm_hm_hdr = sm_cstr_scpyn0((const uchar *)hdr
, strlen(hdr));
if (optarg[0] == 'p')
sm_hdrmod->sm_hm_type = SM_HM_TYPE_PREPEND;
else
{
sm_hdrmod->sm_hm_type = SM_HM_TYPE_APPEND;
SCTA_SET_FLAG(sc_ta, SCTA_FL_HDR_SCAN);
}
ret = sm_hdrmod_insert(sc_ta->scta_hdrmodhd, sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
break;
case 'r':
l = strtoul(optarg, &str, 0);
if (ULONG_MAX == l || l > UINT_MAX)
usage(argv[0]);
if (NULL == str || *str != '=')
usage(argv[0]);
sm_hdrmod = NULL;
strlcpy(hdr, str + 1, sizeof(hdr));
strlcat(hdr, "\r\n", sizeof(hdr));
ret = sm_hdrmod_new(&sc_ta->scta_hdrmodhd, false,
&sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
SM_TEST(sm_hdrmod != NULL);
if (NULL == sm_hdrmod)
return(EX_OSERR);
sm_hdrmod->sm_hm_hdr = sm_cstr_scpyn0((const uchar *)hdr
, strlen(hdr));
sm_hdrmod->sm_hm_pos = l;
sm_hdrmod->sm_hm_type = SM_HM_TYPE_REPLACE;
SCTA_SET_FLAG(sc_ta, SCTA_FL_HDR_SCAN);
ret = sm_hdrmod_insert(sc_ta->scta_hdrmodhd, sm_hdrmod);
SM_TEST(SM_SUCCESS == ret);
if (SM_SUCCESS != ret)
return(EX_OSERR);
break;
default:
usage(argv[0]);
return(EX_USAGE);
}
}
sm_test_begin(argc, argv, "message modification test 0");
argc -= optind;
argv += optind;
sc_ta->scta_cdb_fp = smioin;
sc_sess->scse_wr = sm_str_new(NULL, 256, 1024);
SM_TEST(sc_sess->scse_wr != NULL);
sc_sess->scse_str = sm_str_new(NULL, 256, 1024);
SM_TEST(sc_sess->scse_str != NULL);
total_size = 0;
if (!HDRMODL_EMPTY(sc_ta->scta_hdrmodhd))
ret = sc_msgmod(sc_t_ctx, &total_size);
else
ret = sc_msgdsn(sc_t_ctx, &total_size);
SM_TEST(SM_SUCCESS == ret);
sm_io_flush(smioout);
SM_STR_FREE(sc_sess->scse_wr);
SM_STR_FREE(sc_sess->scse_str);
if (sc_ta != NULL)
sm_free(sc_ta);
return sm_test_end();
}
syntax highlighted by Code2HTML, v. 0.9.1