/*
* 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: updcnts.c,v 1.3 2005/03/30 22:18:30 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/qmgrdbg.h"
#include "sm/actdb-int.h"
#define ACTDB_LOG_DEFINES 1
#include "log.h"
/*
** AQ_UPD_TA_RCPT_CNTS -- update recipient counters in a transaction
**
** Parameters:
** aq_ta -- AQ transaction
** oldstatus -- old recipient status
** newstatus -- new recipient status
** lctx -- logging context
**
** Returns:
** SM_SUCCESS
**
** Called by: q_upd_rcpt_stat(), qar_alias()
**
** Side Effects:
** may set AQ_TA_FL_EDB_UPD_C in aq_ta.
** increases aqt_rcpts_tried,
** changes aqt_rcpts_left,aqt_rcpts_perm, aqt_rcpts_temp
** Note: for "reversibility" the counters should be saved by the caller.
** However, that doesn't work if another task updates the counters
** too. Hence the "change" must be saved, but even then it
** could cause a problem if some function acts if a counter
** reaches 0 (before it is "restored"). Therefore the only
** way to do this reliably is to lock aq_ta until the entire
** update "transaction" is done.
**
** Locking: aq_ta must be locked by caller
**
** Last code review: 2005-03-30 00:37:46
** Last code change:
*/
sm_ret_T
aq_upd_ta_rcpt_cnts(aq_ta_P aq_ta, smtp_status_T oldstatus, smtp_status_T newstatus, sm_log_ctx_P lctx)
{
SM_IS_AQ_TA(aq_ta);
if (aqr_is_smtp_reply(oldstatus) && aqr_is_smtp_reply(newstatus)
&& smtp_reply_type(oldstatus) == smtp_reply_type(newstatus))
{
/* No change */
return SM_SUCCESS;
}
QM_LEV_DPRINTFC(QDC_UPDRCPT, 6, (QM_DEBFP, "sev=DBG, func=aq_upd_ta_rcpt_cnts, aq_ta=%p, old=%d, new=%d, tried=%u, left=%u, temp=%u, perm=%u, flags=%#x\n", aq_ta, oldstatus, newstatus, aq_ta->aqt_rcpts_tried, aq_ta->aqt_rcpts_left, aq_ta->aqt_rcpts_temp, aq_ta->aqt_rcpts_perm, aq_ta->aqt_flags));
/* New entry? Then it has been tried now... */
if (oldstatus == AQR_ST_NEW)
++aq_ta->aqt_rcpts_tried;
if (newstatus == SM_SUCCESS)
newstatus = AQR_ST_DONE;
if (oldstatus == SM_SUCCESS)
oldstatus = AQR_ST_DONE;
switch (smtp_reply_type(oldstatus))
{
case SMTP_RTYPE_OK:
/* Can't be... rcpt has been delivered before; abort?? */
sm_log_write(lctx, ACTDB_LCAT_ACTDB, ACTDB_LMOD_ACTDB,
SM_LOG_ERR, 1,
"sev=ERROR, func=aq_upd_ta_rcpt_cnts, status=inconsistent_state, aq_ta=%p, old=%d, new=%d, tried=%u, left=%u, temp=%u, perm=%u, flags=%#x"
, aq_ta, oldstatus, newstatus, aq_ta->aqt_rcpts_tried
, aq_ta->aqt_rcpts_left, aq_ta->aqt_rcpts_temp
, aq_ta->aqt_rcpts_perm, aq_ta->aqt_flags);
QM_LEV_DPRINTFC(QDC_UPDRCPT, 0, (QM_DEBFP, "sev=ERROR, func=aq_upd_ta_rcpt_cnts, aq_ta=%p, old=%d, new=%d, tried=%u, left=%u, temp=%u, perm=%u, flags=%#x\n", aq_ta, oldstatus, newstatus, aq_ta->aqt_rcpts_tried, aq_ta->aqt_rcpts_left, aq_ta->aqt_rcpts_temp, aq_ta->aqt_rcpts_perm, aq_ta->aqt_flags));
break;
case SMTP_RTYPE_TEMP:
AQ_TA_SET_FLAG(aq_ta, AQ_TA_FL_EDB_UPD_C);
SM_ASSERT(aq_ta->aqt_rcpts_temp > 0);
--aq_ta->aqt_rcpts_temp;
switch (smtp_reply_type(newstatus))
{
case SMTP_RTYPE_OK:
SM_ASSERT(aq_ta->aqt_rcpts_left > 0);
--aq_ta->aqt_rcpts_left;
break;
case SMTP_RTYPE_TEMP:
/* Should have been caught above; COMPLAIN XXX */
sm_log_write(lctx, ACTDB_LCAT_ACTDB, ACTDB_LMOD_ACTDB,
SM_LOG_ERR, 1,
"sev=ERROR, func=aq_upd_ta_rcpt_cnts, status=inconsistent_state, aq_ta=%p, old=%d, new=%d, tried=%u, left=%u, temp=%u, perm=%u, flags=%#x"
, aq_ta, oldstatus, newstatus
, aq_ta->aqt_rcpts_tried
, aq_ta->aqt_rcpts_left, aq_ta->aqt_rcpts_temp
, aq_ta->aqt_rcpts_perm, aq_ta->aqt_flags);
break;
case SMTP_RTYPE_PERM:
++aq_ta->aqt_rcpts_perm;
break;
default:
/* Nothing happened this time */
break;
}
break;
case SMTP_RTYPE_PERM:
AQ_TA_SET_FLAG(aq_ta, AQ_TA_FL_EDB_UPD_C);
SM_ASSERT(aq_ta->aqt_rcpts_perm > 0);
--aq_ta->aqt_rcpts_perm;
switch (smtp_reply_type(newstatus))
{
case SMTP_RTYPE_OK:
SM_ASSERT(aq_ta->aqt_rcpts_left > 0);
--aq_ta->aqt_rcpts_left;
break;
case SMTP_RTYPE_TEMP:
++aq_ta->aqt_rcpts_temp;
break;
case SMTP_RTYPE_PERM:
/* Should have been caught above; COMPLAIN XXX */
sm_log_write(lctx, ACTDB_LCAT_ACTDB, ACTDB_LMOD_ACTDB,
SM_LOG_ERR, 1,
"sev=ERROR, func=aq_upd_ta_rcpt_cnts, status=inconsistent_state, aq_ta=%p, old=%d, new=%d, tried=%u, left=%u, temp=%u, perm=%u, flags=%#x"
, aq_ta, oldstatus, newstatus
, aq_ta->aqt_rcpts_tried
, aq_ta->aqt_rcpts_left, aq_ta->aqt_rcpts_temp
, aq_ta->aqt_rcpts_perm, aq_ta->aqt_flags);
break;
default:
/* Nothing happened this time */
break;
}
break;
default:
/* Nothing happened before */
switch (smtp_reply_type(newstatus))
{
case SMTP_RTYPE_OK:
SM_ASSERT(aq_ta->aqt_rcpts_left > 0);
AQ_TA_SET_FLAG(aq_ta, AQ_TA_FL_EDB_UPD_C);
--aq_ta->aqt_rcpts_left;
break;
case SMTP_RTYPE_TEMP:
AQ_TA_SET_FLAG(aq_ta, AQ_TA_FL_EDB_UPD_C);
++aq_ta->aqt_rcpts_temp;
break;
case SMTP_RTYPE_PERM:
AQ_TA_SET_FLAG(aq_ta, AQ_TA_FL_EDB_UPD_C);
++aq_ta->aqt_rcpts_perm;
break;
default:
/*
** Nothing happened this time either.
** This case is possible since the check above is
** restricted to SMTP reply codes.
*/
/* XXX Really? */
#if 0
AQ_TA_SET_FLAG(aq_ta, AQ_TA_FL_EDB_UPD_C);
#endif
break;
}
break;
}
QM_LEV_DPRINTFC(QDC_UPDRCPT, 6, (QM_DEBFP, "sev=DBG, func=aq_upd_ta_rcpt_cnts, aq_ta=%p, old=%d, new=%d, tried=%u, left=%u, temp=%u, perm=%u, flags=%#x\n", aq_ta, oldstatus, newstatus, aq_ta->aqt_rcpts_tried, aq_ta->aqt_rcpts_left, aq_ta->aqt_rcpts_temp, aq_ta->aqt_rcpts_perm, aq_ta->aqt_flags));
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1