/*
 * 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: qss_rcptid.c,v 1.79 2007/03/26 03:20:24 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/io.h"
#include "sm/rcb.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "sm/reccom.h"
#include "sm/rfc2821.h"
#include "qmgr.h"
#include "log.h"

/*
**  QM_SS_RCPTID -- check recipient, add to IQDB, write rcpt IBDB record
**
**	Parameters:
**		qss_ctx -- QMGR/SMTPS context
**		qss_ta -- transaction
**		tsk -- evthr task
**		qss_rcpt -- recipient ("consumed" by this function, caller
**				must not access it afterwards)
**
**	Returns:
**		<0: usual sm_error code
**		>=0: acceptance/rejection code
*/

sm_ret_T
qm_ss_rcptid(qss_ctx_P qss_ctx, qss_ta_P qss_ta, sm_evthr_task_P tsk, qss_rcpt_P qss_rcpt)
{
	int flags;
	ibdb_rcpt_T ibdb_rcpt;
	sm_a2821_T addr;
	qss_rcpt_P *rrcpt;
	sm_ret_T ret, rv;

	SM_IS_QS_RCPT(qss_rcpt);
	ret = SM_SUCCESS;
	rrcpt = NULL;
	rv = SMTP_R_REJECT;

	/* do some checks here: is it ok to accept this rcpt?? */

	/* check recipient address */
	A2821_INIT_RP(&addr, NULL);
	ret = t2821_scan((sm_rdstr_P) qss_rcpt->qsr_pa, &addr, 0);
	QM_LEV_DPRINTFC(QDC_S2Q, 5, (QM_DEBFP, "func=qm_ss_rcptid, rcpt=%@S, t2821_scan=%r\n", qss_rcpt->qsr_pa, ret));
	if (sm_is_err(ret))
		goto errortemp;
	flags = R2821_CORRECT & ~R2821_AT;
	ret = t2821_parse(&addr, flags);
	QM_LEV_DPRINTFC(QDC_S2Q, 5, (QM_DEBFP, "func=qm_ss_rcptid, rcpt=%@S, t2821_parse=%r\n", qss_rcpt->qsr_pa, ret));

	/* addr isn't used anymore... */
	(void) a2821_free(&addr);
	if (sm_is_err(ret))
		goto errortemp;

	/* add rcpt to iqdb */
	ret = iqdb_rcpt_add(qss_ctx->qss_qmgr_ctx->qmgr_iqdb, qss_rcpt->qsr_id,
			SMTP_RCPTID_SIZE, qss_rcpt, (void **) &rrcpt,
			THR_LOCK_UNLOCK);
	if (sm_is_err(ret))
		goto errortemp;
	QSRCPT_SET_FLAG(qss_rcpt, QSRCPT_FL_IQDB);

	/*
	**  XXX call address resolver
	**  XXX anti-spam/relay checks? (done in SMTPS)
	**  split here: this function can be "asynchronous"
	**  hence we need to store the "state" in rcpt and
	**  add it to some worklist; we can use rcpt_id as id.
	**  the state is:
	**	qss_ta (-> qss_ctx -> tsk)
	**	some state about the rcpt (what is currently happening to it,
	**	e.g., processed by AR, anti-spam, ...) so it "knows" what to
	**	do next (-> qsr_flags)
	**  should we store this in qss_rcpt_T itself or put some struct
	**  "around" it? The former is simpler, but it "enlarges" qss_rcpt_T
	**  a bit.
	*/

	/* write rcpt to ibd if everything is ok so far */
	ibdb_rcpt.ibr_ta_id = qss_ta->qssta_id;
	ibdb_rcpt.ibr_pa = qss_rcpt->qsr_pa;
	ibdb_rcpt.ibr_idx = qss_rcpt->qsr_idx;
	ret = ibdb_rcpt_status(qss_ctx->qss_qmgr_ctx->qmgr_ibdb, &ibdb_rcpt,
			IBDB_RCPT_NEW, IBDB_FL_NONE, THR_LOCK_UNLOCK);
	if (sm_is_err(ret))
		goto tempfail;
	QSRCPT_SET_FLAG(qss_rcpt, QSRCPT_FL_IBDB);

	/* ok so far */
	rv = SMTP_R_OK;

  errortemp:
	if (sm_is_err(ret))
	{
		if (sm_is_temp_err(ret))
		{
  tempfail:
			rv = SMTP_R_TEMP;
		}

		/* XXX Other errors that trigger this? */
		if (sm_error_value(ret) == SM_E_FULL
		    || sm_error_value(ret) == ENOMEM)
			(void) qss_control(qss_ctx, QMGR_THROTTLE, 100,
					QMGR_RFL_IQD_I, THR_LOCK_UNLOCK);
	/* else necessary? */
	}

#if 0
	sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
		QM_LCAT_SMTPS,
		QM_LMOD_FROM_SMTPS,
		SM_LOG_INFO, 12,
		"func=qm_ss_rcptid, rcpt=%@S, ret=%d", qss_rcpt->qsr_pa, rv);
#endif /* 0 */

	/* did we accept the recipient? */
	if (rv != SMTP_R_OK)
	{
		qss_rcpt_free(qss_ta, qss_rcpt,
				(QSRCPT_IS_FLAG(qss_rcpt, QSRCPT_FL_IQDB)
				? QSS_RMFIQDB : 0)|QSS_DECR_RCPTS_TOT);
	}

	/*
	**  This might have been freed already, but it's ok to call the
	**  function again.  Alternatively we could use a pointer and set
	**  it to NULL after freeing the address.
	*/

	(void) a2821_free(&addr);
	return rv;
}


syntax highlighted by Code2HTML, v. 0.9.1