/*
 * Copyright (c) 2003-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: adbupd.c,v 1.26 2006/12/11 01:22:06 ca Exp $")
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/str.h"
#include "sm/time.h"
#include "sm/mta.h"
#include "sm/memops.h"
#include "sm/qmgr.h"
#include "sm/actdb-int.h"
#include "sm/qmgr-int.h"
#include "adb.h"

/*
**  AQ_RSND_CTX_FREE -- Free aq_rsnd_ctx
**
**	Parameters:
**		aq_rsnd_ctx -- aq recipient send RCB to SMTPC context
**
**	Returns:
**		SM_SUCCESS
**
**	Last code review: 2005-04-14 20:31:18
**	Last code change:
*/

sm_ret_T
aq_rsnd_ctx_free(aq_rsnd_ctx_P aq_rsnd_ctx)
{
	if (aq_rsnd_ctx != NULL)
		sm_free_size(aq_rsnd_ctx, sizeof(*aq_rsnd_ctx));
	return SM_SUCCESS;
}

/*
**  AQ_RSND_CTX_NEW -- Create new aq_rsnd_ctx
**
**	Parameters:
**		aq_ctx -- AQ context
**		aq_rcpt -- AQ rcpt
**		paq_rsnd_ctx -- (ptr to) rcpt send RCB to SMTPC context (output)
**
**	Returns:
**		usual sm_error code; ENOMEM
**
**	Last code review: 2005-04-14 20:31:00
**	Last code change:
*/

sm_ret_T
aq_rsnd_ctx_new(aq_ctx_P aq_ctx, aq_rcpt_P aq_rcpt, aq_rsnd_ctx_P *paq_rsnd_ctx)
{
	aq_rsnd_ctx_P aq_rsnd_ctx;

	SM_IS_AQ(aq_ctx);
	SM_REQUIRE(paq_rsnd_ctx != NULL);
	aq_rsnd_ctx = (aq_rsnd_ctx_P)sm_zalloc(sizeof(*aq_rsnd_ctx));
	if (aq_rsnd_ctx == NULL)
		return sm_error_temp(SM_EM_AQ, ENOMEM);
	aq_rsnd_ctx->aqrsc_aq_ctx = aq_ctx;
	aq_rsnd_ctx->aqrsc_rcpt = aq_rcpt;
	*paq_rsnd_ctx = aq_rsnd_ctx;
	return SM_SUCCESS;
}

/*
**  AQ_RCPTSENT2DA -- change status flags for recipients sent to a DA.
**	This is a callback that is invoked after an RCB has been sent.
**	See qm_to_sc() for a discussion.
**
**	Parameters:
**		ctx -- aq recipient send RCB to SMTPC context
**
**	Returns:
**		usual sm_error code
**
**	Locking: locks entire aq_ctx.
**
**	Last code review: 2005-04-15 20:13:50
**	Last code change:
*/

sm_ret_T
aq_rcptsent2da(void *ctx)
{
	int r;
	sm_ret_T ret;
	time_T tm;
	aq_ctx_P aq_ctx;
	thr_lock_T locktype;
	aq_rcpt_P aq_rcpt, aq_rcpt_nxt;
	aq_rsnd_ctx_P aq_rsnd_ctx;
	qmgr_ctx_P qmgr_ctx;

	SM_REQUIRE(ctx != NULL);
	aq_rsnd_ctx = (aq_rsnd_ctx_P)ctx;
	aq_ctx = aq_rsnd_ctx->aqrsc_aq_ctx;
	aq_rcpt = aq_rsnd_ctx->aqrsc_rcpt;
	qmgr_ctx = aq_ctx->aq_qmgr_ctx;
	SM_IS_AQ(aq_ctx);
	SM_IS_AQ_RCPT(aq_rcpt);
	SM_IS_QMGR_CTX(qmgr_ctx);
	locktype = THR_LOCK_UNLOCK;
	if (thr_lock_it(locktype))
	{
		r = pthread_mutex_lock(&aq_ctx->aq_mutex);
		SM_LOCK_OK(r);
		if (r != 0)
			return sm_error_perm(SM_EM_AQ, r);
	}
	ret = SM_SUCCESS;
	tm = evthr_time(qmgr_ctx->qmgr_ev_ctx);

	/* go through the list of entries in the DA transaction */
	aq_rcpt_nxt = aq_rcpt;
	do
	{
#if QMGR_DEBUG > 1
		QM_LEV_DPRINTF(3, (QM_DEBFP, "sev=DBG, func=aq_rcptsent2da, aq_rcpt=%p, aq_rcpt_nxt=%p\n", aq_rcpt, aq_rcpt_nxt));
aq_rcpt_print(aq_rcpt);
#endif /* QMGR_DEBUG > 1 */

		ret = aq_waitq_add(aq_ctx, aq_rcpt_nxt, tm, AQWQ_DA, false);
		/* AQR_SET_FLAG(aq_rcpt_nxt, AQR_FL_WAIT4UPD); */
		QM_LEV_DPRINTF(3, (QM_DEBFP, "sev=DBG, func=aq_rcptsent2da, aq_rcpt_nxt=%p, aq_waitq_add=%x\n", aq_rcpt_nxt, ret));
		aq_rcpt_nxt = AQR_DA_SUCC(aq_rcpt_nxt);
	} while (aq_rcpt_nxt != aq_rcpt);

	tm = aq_waitq_first_tmo(aq_ctx, AQWQ_DA, false);
	if (tm > 0)
		ret = qmgr_set_aq_cleanup(aq_ctx->aq_qmgr_ctx->qmgr_cleanup_ctx, tm, true);
	else
		QM_LEV_DPRINTF(3, (QM_DEBFP, "sev=DBG, func=aq_rcptsent2da, expt=%7ld\n", (long) tm));

	if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
	    || (sm_is_err(ret) && thr_unl_if_err(locktype)))
	{
		r = pthread_mutex_unlock(&aq_ctx->aq_mutex);
		SM_ASSERT(r == 0);
		if (r != 0 && sm_is_success(ret))
			ret = sm_error_perm(SM_EM_AQ, r);
	}
	aq_rsnd_ctx_free(aq_rsnd_ctx);
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1