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