/*
 * Copyright (c) 2007 Claus Assmann
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the license/LICENSE.3C file which can be found at the
 * top level of this source code distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: pmilter_setreplies.c,v 1.4 2007/02/13 03:58:18 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/ctype.h"
#include "pmilter.h"
#include "sm/pmfdef.h"
#include "sm/pmfapi.h"

#if MTA_USE_PMILTER && MTA_USE_RSAD

/*
**  SM_PM_CLRREPLIES -- Clear replies in session context
**
**	Parameters:
**		pmse_ctx -- pmilter/SMTP server session context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
pm_clrreplies(pmse_ctx_P pmse_ctx)
{
	sm_ret_T ret;

	SM_IS_PMSE_CTX(pmse_ctx);
	ret = SM_SUCCESS;
	if (pmse_ctx->pmse_nreplies > 0 && pmse_ctx->pmse_rcodes != NULL)
		SM_FREE(pmse_ctx->pmse_rcodes);

	if (pmse_ctx->pmse_nreplies > 0 && pmse_ctx->pmse_replies != NULL) {
		uint u;
		sm_str_P reply;

		for (u = 0; u < pmse_ctx->pmse_nreplies; u++) {
			reply = pmse_ctx->pmse_replies[u];
			SM_STR_FREE(reply);
		}
		SM_FREE(pmse_ctx->pmse_replies);
	}
	pmse_ctx->pmse_nreplies = 0;

	return ret;
}

/*
**  SM_PMFI_SETREPLIES -- Set replies for several commands
**
**	Parameters:
**		pmse_ctx -- pmilter/SMTP server session context
**		nreplies -- number of entries in replies array
**		rcodes -- array of reply codes
**		rtexts -- array of reply texts including error codes (can be NULL)
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
sm_pmfi_setreplies(pmse_ctx_P pmse_ctx, uint nreplies, int *rcodes, const char **rtexts)
{
	sm_ret_T ret;
	uint u;
	int i;
	const char *rtext;

	SM_IS_PMSE_CTX(pmse_ctx);
	ret = SM_SUCCESS;
	if (NULL == rcodes || 0 == nreplies)
		return sm_err_perm(EINVAL);

	(void) pm_clrreplies(pmse_ctx);

	/* check codes */
	for (u = 0; u < nreplies; u++) {
		i = rcodes[u] / 100;
		if (i < 2 || i > 5)
			return sm_err_perm(EINVAL);
	}

	pmse_ctx->pmse_nreplies = nreplies;
	u = nreplies * sizeof(*pmse_ctx->pmse_rcodes);
	if (u <= nreplies || u < sizeof(*pmse_ctx->pmse_rcodes))
		return sm_err_perm(SM_E_OVFLW_SC);
	pmse_ctx->pmse_rcodes = (int *) sm_zalloc(u);
	if (NULL == pmse_ctx->pmse_rcodes)
		return sm_err_temp(ENOMEM);

	/* copy codes */
	for (u = 0; u < nreplies; u++)
		pmse_ctx->pmse_rcodes[u] = rcodes[u];

	if (NULL == rtexts)
		return SM_SUCCESS;

	/* check rtexts */
	ret = sm_err_perm(EINVAL);
	for (u = 0; u < nreplies; u++) {
		size_t len;
		char c;

		rtext = rtexts[u];
		if (NULL == rtext)
			goto error;
		len = strlen(rtext);
		if (len < 5)
			goto error;
		c = rtext[0];
		if (c != '2' && c != '3' && c != '4' && c != '5')
			goto error;
		if (!ISDIGIT(rtext[1]) || !ISDIGIT(rtext[2]))
			goto error;
		if (rtext[len - 2] != '\r' || rtext[len - 1] != '\n')
			goto error;
	}

	pmse_ctx->pmse_nreplies = nreplies;
	u = nreplies * sizeof(*pmse_ctx->pmse_replies);
	if (u <= nreplies || u < sizeof(*pmse_ctx->pmse_replies)) {
		ret = sm_err_perm(SM_E_OVFLW_SC);
		goto error;
	}
	pmse_ctx->pmse_replies = (sm_str_P *) sm_zalloc(u);
	if (NULL == pmse_ctx->pmse_replies)
		goto enomem;

	/* next: copy */
	for (u = 0; u < nreplies; u++) {
		rtext = rtexts[u];
		pmse_ctx->pmse_replies[u] = sm_str_scpy(NULL, rtext, strlen(rtext));
		if (NULL == pmse_ctx->pmse_replies[u])
			goto enomem;
	}
	return SM_SUCCESS;

  enomem:
	ret = sm_err_temp(ENOMEM);
  error:
	(void) pm_clrreplies(pmse_ctx);
	return ret;
}
#endif /* MTA_USE_PMILTER && MTA_USE_RSAD */


syntax highlighted by Code2HTML, v. 0.9.1