5 /* cleanup_out_recipient 3
7 /* envelope recipient output filter
9 /* #include "cleanup.h"
11 /* void cleanup_out_recipient(state, dsn_orig_recipient,
12 /* dsn_notify, orig_recipient,
14 /* CLEANUP_STATE *state;
15 /* const char *dsn_orig_recipient;
16 /* const char *dsn_notify;
17 /* const char *orig_recipient;
18 /* const char *recipient;
20 /* This module implements an envelope recipient output filter.
22 /* cleanup_out_recipient() performs virtual table expansion
23 /* and recipient duplicate filtering, and appends the
24 /* resulting recipients to the output stream. It also
25 /* generates DSN SUCCESS notifications.
29 /* Cleanup server state.
30 /* .IP dsn_orig_recipient
31 /* DSN original recipient information.
35 /* Envelope recipient as received by Postfix.
37 /* Envelope recipient as rewritten by Postfix.
41 /* .IP enable_original_recipient
42 /* Enable orig_recipient support.
43 /* .IP local_duplicate_filter_limit
44 /* Upper bound to the size of the recipient duplicate filter.
45 /* Zero means no limit; this may cause the mail system to
47 /* .IP virtual_alias_maps
48 /* list of virtual address lookup tables.
52 /* The Secure Mailer license must be distributed with this software.
55 /* IBM T.J. Watson Research
57 /* Yorktown Heights, NY 10598, USA
65 /* Utility library. */
72 #include <been_here.h>
73 #include <mail_params.h>
76 #include <cleanup_user.h>
78 #include <recipient_list.h>
81 #include <mail_queue.h> /* cleanup_trace_path */
82 #include <mail_proto.h>
83 #include <msg_stats.h>
85 /* Application-specific. */
89 /* cleanup_trace_append - update trace logfile */
91 static void cleanup_trace_append(CLEANUP_STATE
*state
, RECIPIENT
*rcpt
,
96 if (cleanup_trace_path
== 0) {
97 cleanup_trace_path
= vstring_alloc(10);
98 mail_queue_path(cleanup_trace_path
, MAIL_QUEUE_TRACE
,
101 if (trace_append(BOUNCE_FLAG_CLEAN
, state
->queue_id
,
102 CLEANUP_MSG_STATS(&stats
, state
),
103 rcpt
, "none", dsn
) != 0) {
104 msg_warn("%s: trace logfile update error", state
->queue_id
);
105 state
->errs
|= CLEANUP_STAT_WRITE
;
109 /* cleanup_out_recipient - envelope recipient output filter */
111 void cleanup_out_recipient(CLEANUP_STATE
*state
,
112 const char *dsn_orcpt
,
121 * XXX Not elegant, but eliminates complexity in the record reading loop.
123 if (!var_enable_orcpt
)
129 * Distinguish between different original recipient addresses that map
130 * onto the same mailbox. The recipient will use our original recipient
131 * message header to figure things out.
133 * Postfix 2.2 compatibility: when ignoring differences in Postfix original
134 * recipient information, also ignore differences in DSN attributes. We
135 * do, however, keep the DSN attributes of the recipient that survives
136 * duplicate elimination.
138 #define STREQ(x, y) (strcmp((x), (y)) == 0)
140 if ((state
->flags
& CLEANUP_FLAG_MAP_OK
) == 0
141 || cleanup_virt_alias_maps
== 0) {
142 if ((var_enable_orcpt
?
143 been_here(state
->dups
, "%s\n%d\n%s\n%s",
144 dsn_orcpt
, dsn_notify
, orcpt
, recip
) :
145 been_here_fixed(state
->dups
, recip
)) == 0) {
147 cleanup_out_format(state
, REC_TYPE_ATTR
, "%s=%d",
148 MAIL_ATTR_DSN_NOTIFY
, dsn_notify
);
150 cleanup_out_format(state
, REC_TYPE_ATTR
, "%s=%s",
151 MAIL_ATTR_DSN_ORCPT
, dsn_orcpt
);
152 cleanup_out_string(state
, REC_TYPE_ORCP
, orcpt
);
153 cleanup_out_string(state
, REC_TYPE_RCPT
, recip
);
159 * XXX DSN. RFC 3461 gives us three options for multi-recipient aliases
160 * (we're treating single recipient aliases as a special case of
161 * multi-recipient aliases, one argument being that it is none of the
162 * sender's business).
164 * (a) Don't propagate ENVID, NOTIFY, RET, or ORCPT. If NOTIFY specified
165 * SUCCESS, send a "relayed" DSN.
167 * (b) Propagate ENVID, (NOTIFY minus SUCCESS), RET, and ORCPT. If NOTIFY
168 * specified SUCCESS, send an "expanded" DSN.
170 * (c) Propagate ENVID, NOTIFY, RET, and ORCPT to one recipient only. Send
173 * In all three cases we are modifying at least one NOTIFY value. Either we
174 * have to record explicit dsn_notify records, or we must not allow the
175 * use of a per-message non-default NOTIFY value that applies to all
178 * Alternatives (a) and (c) require that we store explicit per-recipient RET
179 * and ENVID records, at least for the recipients that are excluded from
180 * RET and ENVID propagation. This means storing explicit ENVID records
181 * to indicate that the information does not exist. All this makes
182 * alternative (b) more and more attractive. It is no surprise that we
183 * use (b) here and in the local delivery agent.
185 * In order to generate a SUCCESS notification from the cleanup server we
186 * have to write the trace logfile record now. We're NOT going to flush
187 * the trace file from the cleanup server; if we need to write bounce
188 * logfile records, and the bounce service fails, we must be able to
189 * cancel the entire cleanup request including any success or failure
190 * notifications. The queue manager will flush the trace (and bounce)
191 * logfile, possibly after it has generated its own success or failure
192 * notification records.
194 * Postfix 2.2 compatibility: when ignoring differences in Postfix original
195 * recipient information, also ignore differences in DSN attributes. We
196 * do, however, keep the DSN attributes of the recipient that survives
197 * duplicate elimination.
203 argv
= cleanup_map1n_internal(state
, recip
, cleanup_virt_alias_maps
,
204 cleanup_ext_prop_mask
& EXT_PROP_VIRTUAL
);
205 if ((dsn_notify
& DSN_NOTIFY_SUCCESS
)
206 && (argv
->argc
> 1 || strcmp(recip
, argv
->argv
[0]) != 0)) {
207 (void) DSN_SIMPLE(&dsn
, "2.0.0", "alias expanded");
208 dsn
.action
= "expanded";
209 RECIPIENT_ASSIGN(&rcpt
, 0, dsn_orcpt
, dsn_notify
, orcpt
, recip
);
210 cleanup_trace_append(state
, &rcpt
, &dsn
);
211 dsn_notify
= (dsn_notify
== DSN_NOTIFY_SUCCESS
? DSN_NOTIFY_NEVER
:
212 dsn_notify
& ~DSN_NOTIFY_SUCCESS
);
214 for (cpp
= argv
->argv
; *cpp
; cpp
++) {
215 if ((var_enable_orcpt
?
216 been_here(state
->dups
, "%s\n%d\n%s\n%s",
217 dsn_orcpt
, dsn_notify
, orcpt
, *cpp
) :
218 been_here_fixed(state
->dups
, *cpp
)) == 0) {
220 cleanup_out_format(state
, REC_TYPE_ATTR
, "%s=%d",
221 MAIL_ATTR_DSN_NOTIFY
, dsn_notify
);
223 cleanup_out_format(state
, REC_TYPE_ATTR
, "%s=%s",
224 MAIL_ATTR_DSN_ORCPT
, dsn_orcpt
);
225 cleanup_out_string(state
, REC_TYPE_ORCP
, orcpt
);
226 cleanup_out_string(state
, REC_TYPE_RCPT
, *cpp
);