Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / cleanup / cleanup_extracted.c
blobc8b0d9a8123c427521006fdb9ba14dc0519d9cd7
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* cleanup_extracted 3
6 /* SUMMARY
7 /* process extracted segment
8 /* SYNOPSIS
9 /* #include "cleanup.h"
11 /* void cleanup_extracted(state, type, buf, len)
12 /* CLEANUP_STATE *state;
13 /* int type;
14 /* const char *buf;
15 /* ssize_t len;
16 /* DESCRIPTION
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.
25 /* Arguments:
26 /* .IP state
27 /* Queue file and message processing state. This state is updated
28 /* as records are processed and as errors happen.
29 /* .IP type
30 /* Record type.
31 /* .IP buf
32 /* Record content.
33 /* .IP len
34 /* Record content length.
35 /* LICENSE
36 /* .ad
37 /* .fi
38 /* The Secure Mailer license must be distributed with this software.
39 /* AUTHOR(S)
40 /* Wietse Venema
41 /* IBM T.J. Watson Research
42 /* P.O. Box 704
43 /* Yorktown Heights, NY 10598, USA
44 /*--*/
46 /* System library. */
48 #include <sys_defs.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <stdlib.h>
54 /* Utility library. */
56 #include <msg.h>
57 #include <vstring.h>
58 #include <vstream.h>
59 #include <mymalloc.h>
60 #include <nvtable.h>
61 #include <stringops.h>
63 /* Global library. */
65 #include <cleanup_user.h>
66 #include <qmgr_user.h>
67 #include <record.h>
68 #include <rec_type.h>
69 #include <mail_params.h>
70 #include <mail_proto.h>
71 #include <dsn_mask.h>
72 #include <rec_attr_map.h>
74 /* Application-specific. */
76 #include "cleanup.h"
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;
108 char *attr_name;
109 char *attr_value;
110 const char *error_text;
111 int extra_opts;
112 int junk;
114 #ifdef DELAY_ACTION
115 int defer_delay;
117 #endif
119 if (msg_verbose)
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);
128 else
129 state->flags |= extra_opts;
130 return;
132 #ifdef DELAY_ACTION
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);
138 else
139 state->defer_delay = defer_delay;
140 return;
142 #endif
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;
149 return;
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;
165 return;
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);
171 return;
173 if ((junk = rec_attr_map(attr_name)) != 0) {
174 buf = attr_value;
175 type = junk;
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",
201 state->queue_id);
202 state->errs |= CLEANUP_STAT_BAD;
203 return;
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;
219 return;
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;
231 return;
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);
240 return;
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);
251 else
252 state->qmgr_opts |=
253 QMGR_READ_FLAG_FROM_DSN(state->dsn_notify = junk);
254 return;
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);
263 return;
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);
278 return;
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);
288 return;
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, "");