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