/*++
/* NAME
/* cleanup_out_recipient 3
/* SUMMARY
/* envelope recipient output filter
/* SYNOPSIS
/* #include "cleanup.h"
/*
/* void cleanup_out_recipient(state, dsn_orig_recipient,
/* dsn_notify, orig_recipient,
/* recipient)
/* CLEANUP_STATE *state;
/* const char *dsn_orig_recipient;
/* const char *dsn_notify;
/* const char *orig_recipient;
/* const char *recipient;
/* DESCRIPTION
/* This module implements an envelope recipient output filter.
/*
/* cleanup_out_recipient() performs virtual table expansion
/* and recipient duplicate filtering, and appends the
/* resulting recipients to the output stream. It also
/* generates DSN SUCCESS notifications.
/*
/* Arguments:
/* .IP state
/* Cleanup server state.
/* .IP dsn_orig_recipient
/* DSN original recipient information.
/* .IP dsn_notify
/* DSN notify flags.
/* .IP orig_recipient
/* Envelope recipient as received by Postfix.
/* .IP recipient
/* Envelope recipient as rewritten by Postfix.
/* CONFIGURATION
/* .ad
/* .fi
/* .IP enable_original_recipient
/* Enable orig_recipient support.
/* .IP local_duplicate_filter_limit
/* Upper bound to the size of the recipient duplicate filter.
/* Zero means no limit; this may cause the mail system to
/* become stuck.
/* .IP virtual_alias_maps
/* list of virtual address lookup tables.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
/* Utility library. */
#include <argv.h>
#include <msg.h>
/* Global library. */
#include <been_here.h>
#include <mail_params.h>
#include <rec_type.h>
#include <ext_prop.h>
#include <cleanup_user.h>
#include <dsn_mask.h>
#include <recipient_list.h>
#include <dsn.h>
#include <trace.h>
#include <verify.h>
#include <mail_queue.h> /* cleanup_trace_path */
#include <mail_proto.h>
#include <msg_stats.h>
/* Application-specific. */
#include "cleanup.h"
/* cleanup_trace_append - update trace logfile */
static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
DSN *dsn)
{
MSG_STATS stats;
if (cleanup_trace_path == 0 ) {
cleanup_trace_path = vstring_alloc(10 );
mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE,
state->queue_id);
}
if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id,
CLEANUP_MSG_STATS(&stats, state),
rcpt, "none" , NO_TLS_STATS, dsn) != 0 ) {
msg_warn("%s: trace logfile update error" , state->queue_id);
state->errs |= CLEANUP_STAT_WRITE;
}
}
/* cleanup_verify_append - update verify daemon */
static void cleanup_verify_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
DSN *dsn, int verify_status)
{
MSG_STATS stats;
if (verify_append(state->queue_id, CLEANUP_MSG_STATS(&stats, state),
rcpt, "none" , NO_TLS_STATS, dsn, verify_status) != 0 ) {
msg_warn("%s: verify service update error" , state->queue_id);
state->errs |= CLEANUP_STAT_WRITE;
}
}
/* cleanup_out_recipient - envelope recipient output filter */
void cleanup_out_recipient(CLEANUP_STATE *state,
const char *dsn_orcpt,
int dsn_notify,
const char *orcpt,
const char *recip)
{
ARGV *argv;
char **cpp;
/*
* XXX Not elegant , but eliminates complexity in the record reading loop .
*/
if (dsn_orcpt == 0 )
dsn_orcpt = "" ;
/*
* Distinguish between different original recipient addresses that map
* onto the same mailbox . The recipient will use our original recipient
* message header to figure things out .
*
* Postfix 2 . 2 compatibility : when ignoring differences in Postfix original
* recipient information , also ignore differences in DSN attributes . We
* do , however , keep the DSN attributes of the recipient that survives
* duplicate elimination .
*/
#define STREQ(x, y) (strcmp((x), (y)) == 0 )
if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0
|| cleanup_virt_alias_maps == 0 ) {
/* Matches been_here_drop{,_fixed}() calls cleanup_del_rcpt(). */
if ((var_enable_orcpt ?
been_here(state->dups, "%s\n%d\n%s\n%s" ,
dsn_orcpt, dsn_notify, orcpt, recip) :
been_here_fixed(state->dups, recip)) == 0 ) {
if (dsn_notify)
cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d" ,
MAIL_ATTR_DSN_NOTIFY, dsn_notify);
if (*dsn_orcpt)
cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s" ,
MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
cleanup_out_string(state, REC_TYPE_RCPT, recip);
state->rcpt_count++;
}
}
/*
* XXX DSN . RFC 3461 gives us three options for multi - recipient aliases
* ( we ' re treating single recipient aliases as a special case of
* multi - recipient aliases , one argument being that it is none of the
* sender ' s business ) .
*
* ( a ) Don ' t propagate ENVID , NOTIFY , RET , or ORCPT . If NOTIFY specified
* SUCCESS , send a " relayed " DSN .
*
* ( b ) Propagate ENVID , ( NOTIFY minus SUCCESS ) , RET , and ORCPT . If NOTIFY
* specified SUCCESS , send an " expanded " DSN .
*
* ( c ) Propagate ENVID , NOTIFY , RET , and ORCPT to one recipient only . Send
* no DSN .
*
* In all three cases we are modifying at least one NOTIFY value . Either we
* have to record explicit dsn_notify records , or we must not allow the
* use of a per - message non - default NOTIFY value that applies to all
* recipient records .
*
* Alternatives ( a ) and ( c ) require that we store explicit per - recipient RET
* and ENVID records , at least for the recipients that are excluded from
* RET and ENVID propagation . This means storing explicit ENVID records
* to indicate that the information does not exist . All this makes
* alternative ( b ) more and more attractive . It is no surprise that we
* use ( b ) here and in the local delivery agent .
*
* In order to generate a SUCCESS notification from the cleanup server we
* have to write the trace logfile record now . We ' re NOT going to flush
* the trace file from the cleanup server ; if we need to write bounce
* logfile records , and the bounce service fails , we must be able to
* cancel the entire cleanup request including any success or failure
* notifications . The queue manager will flush the trace ( and bounce )
* logfile , possibly after it has generated its own success or failure
* notification records .
*
* Postfix 2 . 2 compatibility : when ignoring differences in Postfix original
* recipient information , also ignore differences in DSN attributes . We
* do , however , keep the DSN attributes of the recipient that survives
* duplicate elimination .
*
* In the case of a verify ( 8 ) request for a one - to - many alias , declare the
* alias address as " deliverable " . Do not verify the individual addresses
* in the expansion because that results in multiple verify ( 8 ) updates
* for one verify ( 8 ) request .
*
* Multiple verify ( 8 ) updates for one verify ( 8 ) request would overwrite each
* other ' s status , and if the last status update is " undeliverable " , then
* the whole alias is flagged as undeliverable .
*/
else {
RECIPIENT rcpt;
DSN dsn;
argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
if (argv->argc > 1 && (state->tflags & DEL_REQ_FLAG_MTA_VRFY)) {
(void ) DSN_SIMPLE(&dsn, "2.0.0" , "aliased to multiple recipients" );
dsn.action = "deliverable" ;
RECIPIENT_ASSIGN(&rcpt, 0 , dsn_orcpt, dsn_notify, orcpt, recip);
cleanup_verify_append(state, &rcpt, &dsn, DEL_RCPT_STAT_OK);
argv_free(argv);
return ;
}
if ((dsn_notify & DSN_NOTIFY_SUCCESS)
&& (argv->argc > 1 || strcmp(recip, argv->argv[0 ]) != 0 )) {
(void ) DSN_SIMPLE(&dsn, "2.0.0" , "alias expanded" );
dsn.action = "expanded" ;
RECIPIENT_ASSIGN(&rcpt, 0 , dsn_orcpt, dsn_notify, orcpt, recip);
cleanup_trace_append(state, &rcpt, &dsn);
dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER :
dsn_notify & ~DSN_NOTIFY_SUCCESS);
}
for (cpp = argv->argv; *cpp; cpp++) {
if ((var_enable_orcpt ?
been_here(state->dups, "%s\n%d\n%s\n%s" ,
dsn_orcpt, dsn_notify, orcpt, *cpp) :
been_here_fixed(state->dups, *cpp)) == 0 ) {
if (dsn_notify)
cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d" ,
MAIL_ATTR_DSN_NOTIFY, dsn_notify);
if (*dsn_orcpt)
cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s" ,
MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
state->rcpt_count++;
}
}
argv_free(argv);
}
}
Messung V0.5 in Prozent C=76 H=94 G=85
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland