7 /* process extracted segment
9 /* #include "cleanup.h"
11 /* void cleanup_extracted(state, type, buf, len)
12 /* CLEANUP_STATE *state;
17 /* This module processes message records with information extracted
18 /* from message content, or with recipients that are stored after the
19 /* message content. It updates recipient records, writes extracted
20 /* information records to the output, and writes the queue
21 /* file end marker. The queue file is left in a state that
22 /* is suitable for Milter inspection, but the size record still
23 /* contains dummy values.
27 /* Queue file and message processing state. This state is updated
28 /* as records are processed and as errors happen.
34 /* Record content length.
38 /* The Secure Mailer license must be distributed with this software.
41 /* IBM T.J. Watson Research
43 /* Yorktown Heights, NY 10598, USA
54 /* Utility library. */
61 #include <stringops.h>
65 #include <cleanup_user.h>
66 #include <qmgr_user.h>
69 #include <mail_params.h>
70 #include <mail_proto.h>
72 #include <rec_attr_map.h>
74 /* Application-specific. */
78 #define STR(x) vstring_str(x)
80 static void cleanup_extracted_process(CLEANUP_STATE
*, int, const char *, ssize_t
);
81 static void cleanup_extracted_finish(CLEANUP_STATE
*);
83 /* cleanup_extracted - initialize extracted segment */
85 void cleanup_extracted(CLEANUP_STATE
*state
, int type
,
86 const char *buf
, ssize_t len
)
90 * Start the extracted segment.
92 cleanup_out_string(state
, REC_TYPE_XTRA
, "");
95 * Pass control to the actual envelope processing routine.
97 state
->action
= cleanup_extracted_process
;
98 cleanup_extracted_process(state
, type
, buf
, len
);
101 /* cleanup_extracted_process - process one extracted envelope record */
103 void cleanup_extracted_process(CLEANUP_STATE
*state
, int type
,
104 const char *buf
, ssize_t len
)
106 const char *myname
= "cleanup_extracted_process";
107 const char *encoding
;
110 const char *error_text
;
120 msg_info("extracted envelope %c %.*s", type
, (int) len
, buf
);
122 if (type
== REC_TYPE_FLGS
) {
123 /* Not part of queue file format. */
124 extra_opts
= atoi(buf
);
125 if (extra_opts
& ~CLEANUP_FLAG_MASK_EXTRA
)
126 msg_warn("%s: ignoring bad extra flags: 0x%x",
127 state
->queue_id
, extra_opts
);
129 state
->flags
|= extra_opts
;
133 if (type
== REC_TYPE_DELAY
) {
134 /* Not part of queue file format. */
135 defer_delay
= atoi(buf
);
136 if (defer_delay
<= 0)
137 msg_warn("%s: ignoring bad delay time: %s", state
->queue_id
, buf
);
139 state
->defer_delay
= defer_delay
;
144 if (strchr(REC_TYPE_EXTRACT
, type
) == 0) {
145 msg_warn("%s: message rejected: "
146 "unexpected record type %d in extracted envelope",
147 state
->queue_id
, type
);
148 state
->errs
|= CLEANUP_STAT_BAD
;
153 * Map DSN attribute name to pseudo record type so that we don't have to
154 * pollute the queue file with records that are incompatible with past
155 * Postfix versions. Preferably, people should be able to back out from
156 * an upgrade without losing mail.
158 if (type
== REC_TYPE_ATTR
) {
159 vstring_strcpy(state
->attr_buf
, buf
);
160 error_text
= split_nameval(STR(state
->attr_buf
), &attr_name
, &attr_value
);
161 if (error_text
!= 0) {
162 msg_warn("%s: message rejected: malformed attribute: %s: %.100s",
163 state
->queue_id
, error_text
, buf
);
164 state
->errs
|= CLEANUP_STAT_BAD
;
167 /* Zero-length values are place holders for unavailable values. */
168 if (*attr_value
== 0) {
169 msg_warn("%s: spurious null attribute value for \"%s\" -- ignored",
170 state
->queue_id
, attr_name
);
173 if ((junk
= rec_attr_map(attr_name
)) != 0) {
180 * On the transition from non-recipient records to recipient records,
181 * emit optional information from header/body content.
183 if ((state
->flags
& CLEANUP_FLAG_INRCPT
) == 0
184 && strchr(REC_TYPE_EXT_RECIPIENT
, type
) != 0) {
185 if (state
->filter
!= 0)
186 cleanup_out_string(state
, REC_TYPE_FILT
, state
->filter
);
187 if (state
->redirect
!= 0)
188 cleanup_out_string(state
, REC_TYPE_RDR
, state
->redirect
);
189 if ((encoding
= nvtable_find(state
->attr
, MAIL_ATTR_ENCODING
)) != 0)
190 cleanup_out_format(state
, REC_TYPE_ATTR
, "%s=%s",
191 MAIL_ATTR_ENCODING
, encoding
);
192 state
->flags
|= CLEANUP_FLAG_INRCPT
;
196 * Extracted envelope recipient record processing.
198 if (type
== REC_TYPE_RCPT
) {
199 if (state
->sender
== 0) { /* protect showq */
200 msg_warn("%s: message rejected: envelope recipient precedes sender",
202 state
->errs
|= CLEANUP_STAT_BAD
;
205 if (state
->orig_rcpt
== 0)
206 state
->orig_rcpt
= mystrdup(buf
);
207 cleanup_addr_recipient(state
, buf
);
208 if (cleanup_milters
!= 0
209 && state
->milters
== 0
210 && CLEANUP_MILTER_OK(state
))
211 cleanup_milter_emul_rcpt(state
, cleanup_milters
, state
->recip
);
212 myfree(state
->orig_rcpt
);
213 state
->orig_rcpt
= 0;
214 if (state
->dsn_orcpt
!= 0) {
215 myfree(state
->dsn_orcpt
);
216 state
->dsn_orcpt
= 0;
218 state
->dsn_notify
= 0;
221 if (type
== REC_TYPE_DONE
|| type
== REC_TYPE_DRCP
) {
222 if (state
->orig_rcpt
!= 0) {
223 myfree(state
->orig_rcpt
);
224 state
->orig_rcpt
= 0;
226 if (state
->dsn_orcpt
!= 0) {
227 myfree(state
->dsn_orcpt
);
228 state
->dsn_orcpt
= 0;
230 state
->dsn_notify
= 0;
233 if (type
== REC_TYPE_DSN_ORCPT
) {
234 if (state
->dsn_orcpt
) {
235 msg_warn("%s: ignoring out-of-order DSN original recipient record <%.200s>",
236 state
->queue_id
, state
->dsn_orcpt
);
237 myfree(state
->dsn_orcpt
);
239 state
->dsn_orcpt
= mystrdup(buf
);
242 if (type
== REC_TYPE_DSN_NOTIFY
) {
243 if (state
->dsn_notify
) {
244 msg_warn("%s: ignoring out-of-order DSN notify record <%d>",
245 state
->queue_id
, state
->dsn_notify
);
246 state
->dsn_notify
= 0;
248 if (!alldig(buf
) || (junk
= atoi(buf
)) == 0 || DSN_NOTIFY_OK(junk
) == 0)
249 msg_warn("%s: ignoring malformed dsn notify record <%.200s>",
250 state
->queue_id
, buf
);
253 QMGR_READ_FLAG_FROM_DSN(state
->dsn_notify
= junk
);
256 if (type
== REC_TYPE_ORCP
) {
257 if (state
->orig_rcpt
!= 0) {
258 msg_warn("%s: ignoring out-of-order original recipient record <%.200s>",
259 state
->queue_id
, buf
);
260 myfree(state
->orig_rcpt
);
262 state
->orig_rcpt
= mystrdup(buf
);
265 if (type
== REC_TYPE_END
) {
266 /* Make room to append recipient. */
267 if ((state
->milters
|| cleanup_milters
)
268 && state
->append_rcpt_pt_offset
< 0) {
269 if ((state
->append_rcpt_pt_offset
= vstream_ftell(state
->dst
)) < 0)
270 msg_fatal("%s: vstream_ftell %s: %m:", myname
, cleanup_path
);
271 cleanup_out_format(state
, REC_TYPE_PTR
, REC_TYPE_PTR_FORMAT
, 0L);
272 if ((state
->append_rcpt_pt_target
= vstream_ftell(state
->dst
)) < 0)
273 msg_fatal("%s: vstream_ftell %s: %m:", myname
, cleanup_path
);
275 state
->flags
&= ~CLEANUP_FLAG_INRCPT
;
276 state
->flags
|= CLEANUP_FLAG_END_SEEN
;
277 cleanup_extracted_finish(state
);
282 * Extracted envelope non-recipient record processing.
284 if (state
->flags
& CLEANUP_FLAG_INRCPT
)
285 /* Tell qmgr that recipient records are mixed with other information. */
286 state
->qmgr_opts
|= QMGR_READ_FLAG_MIXED_RCPT_OTHER
;
287 cleanup_out(state
, type
, buf
, len
);
291 /* cleanup_extracted_finish - complete the third message segment */
293 void cleanup_extracted_finish(CLEANUP_STATE
*state
)
297 * On the way out, add the optional automatic BCC recipient.
299 if ((state
->flags
& CLEANUP_FLAG_BCC_OK
)
300 && state
->recip
!= 0 && *var_always_bcc
)
301 cleanup_addr_bcc(state
, var_always_bcc
);
304 * Terminate the extracted segment.
306 cleanup_out_string(state
, REC_TYPE_END
, "");