Postfix3.3.1
cleanup_out.c
[詳解]
1 /*++
2 /* NAME
3 /* cleanup_out 3
4 /* SUMMARY
5 /* record output support
6 /* SYNOPSIS
7 /* #include "cleanup.h"
8 /*
9 /* int CLEANUP_OUT_OK(state)
10 /* CLEANUP_STATE *state;
11 /*
12 /* void cleanup_out(state, type, data, len)
13 /* CLEANUP_STATE *state;
14 /* int type;
15 /* const char *data;
16 /* ssize_t len;
17 /*
18 /* void cleanup_out_string(state, type, str)
19 /* CLEANUP_STATE *state;
20 /* int type;
21 /* const char *str;
22 /*
23 /* void CLEANUP_OUT_BUF(state, type, buf)
24 /* CLEANUP_STATE *state;
25 /* int type;
26 /* VSTRING *buf;
27 /*
28 /* void cleanup_out_format(state, type, format, ...)
29 /* CLEANUP_STATE *state;
30 /* int type;
31 /* const char *format;
32 /*
33 /* void cleanup_out_header(state, buf)
34 /* CLEANUP_STATE *state;
35 /* VSTRING *buf;
36 /* DESCRIPTION
37 /* This module writes records to the output stream.
38 /*
39 /* CLEANUP_OUT_OK() is a macro that evaluates to non-zero
40 /* as long as it makes sense to produce output. All output
41 /* routines below check for this condition.
42 /*
43 /* cleanup_out() is the main record output routine. It writes
44 /* one record of the specified type, with the specified data
45 /* and length to the output stream.
46 /*
47 /* cleanup_out_string() outputs one string as a record.
48 /*
49 /* CLEANUP_OUT_BUF() is an unsafe macro that outputs
50 /* one string buffer as a record.
51 /*
52 /* cleanup_out_format() formats its arguments and writes
53 /* the result as a record.
54 /*
55 /* cleanup_out_header() outputs a multi-line header as records
56 /* of the specified type. The input is expected to be newline
57 /* separated (not newline terminated), and is modified.
58 /* LICENSE
59 /* .ad
60 /* .fi
61 /* The Secure Mailer license must be distributed with this software.
62 /* AUTHOR(S)
63 /* Wietse Venema
64 /* IBM T.J. Watson Research
65 /* P.O. Box 704
66 /* Yorktown Heights, NY 10598, USA
67 /*--*/
68 
69 /* System library. */
70 
71 #include <sys_defs.h>
72 #include <errno.h>
73 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */
74 #include <stdarg.h>
75 #include <string.h>
76 
77 /* Utility library. */
78 
79 #include <msg.h>
80 #include <vstring.h>
81 #include <vstream.h>
82 #include <split_at.h>
83 #include <stringops.h>
84 
85 /* Global library. */
86 
87 #include <record.h>
88 #include <rec_type.h>
89 #include <cleanup_user.h>
90 #include <mail_params.h>
91 #include <lex_822.h>
92 #include <smtputf8.h>
93 
94 /* Application-specific. */
95 
96 #include "cleanup.h"
97 
98 #define STR vstring_str
99 
100 /* cleanup_out - output one single record */
101 
102 void cleanup_out(CLEANUP_STATE *state, int type, const char *string, ssize_t len)
103 {
104  int err = 0;
105 
106  /*
107  * Long message header lines have to be read and written as multiple
108  * records. Other header/body content, and envelope data, is copied one
109  * record at a time. Be sure to not skip a zero-length request.
110  *
111  * XXX We don't know if we're writing a message header or not, but that is
112  * not a problem. A REC_TYPE_NORM or REC_TYPE_CONT record can always be
113  * chopped up into an equivalent set of REC_TYPE_CONT plus REC_TYPE_NORM
114  * records.
115  */
116  if (CLEANUP_OUT_OK(state) == 0)
117  return;
118 
119 #define TEXT_RECORD(t) ((t) == REC_TYPE_NORM || (t) == REC_TYPE_CONT)
120 
121  if (var_line_limit <= 0)
122  msg_panic("cleanup_out: bad line length limit: %d", var_line_limit);
123  do {
124  if (len > var_line_limit && TEXT_RECORD(type)) {
125  err = rec_put(state->dst, REC_TYPE_CONT, string, var_line_limit);
126  string += var_line_limit;
127  len -= var_line_limit;
128  } else {
129  err = rec_put(state->dst, type, string, len);
130  break;
131  }
132  } while (len > 0 && err >= 0);
133 
134  if (err < 0) {
135  if (errno == EFBIG) {
136  msg_warn("%s: queue file size limit exceeded",
137  state->queue_id);
138  state->errs |= CLEANUP_STAT_SIZE;
139  } else {
140  msg_warn("%s: write queue file: %m", state->queue_id);
141  state->errs |= CLEANUP_STAT_WRITE;
142  }
143  }
144 }
145 
146 /* cleanup_out_string - output string to one single record */
147 
148 void cleanup_out_string(CLEANUP_STATE *state, int type, const char *string)
149 {
150  cleanup_out(state, type, string, strlen(string));
151 }
152 
153 /* cleanup_out_format - output one formatted record */
154 
155 void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
156 {
157  static VSTRING *vp;
158  va_list ap;
159 
160  if (vp == 0)
161  vp = vstring_alloc(100);
162  va_start(ap, fmt);
163  vstring_vsprintf(vp, fmt, ap);
164  va_end(ap);
165  CLEANUP_OUT_BUF(state, type, vp);
166 }
167 
168 /* cleanup_out_header - output one multi-line header as a bunch of records */
169 
170 void cleanup_out_header(CLEANUP_STATE *state, VSTRING *header_buf)
171 {
172  char *start = vstring_str(header_buf);
173  char *line;
174  char *next_line;
175  ssize_t line_len;
176 
177  /*
178  * Fix 20140711: Auto-detect the presence of a non-ASCII header.
179  */
180  if (var_smtputf8_enable && *STR(header_buf) && !allascii(STR(header_buf))) {
181  state->smtputf8 |= SMTPUTF8_FLAG_HEADER;
182  /* Fix 20140713: request SMTPUTF8 support selectively. */
183  if (state->flags & CLEANUP_FLAG_AUTOUTF8)
185  }
186 
187  /*
188  * Prepend a tab to continued header lines that went through the address
189  * rewriting machinery. See cleanup_fold_header(state) below for the form
190  * of such header lines. NB: This code destroys the header. We could try
191  * to avoid clobbering it, but we're not going to use the data any
192  * further.
193  *
194  * XXX We prefer to truncate a header at the last line boundary before the
195  * header size limit. If this would undershoot the limit by more than
196  * 10%, we truncate between line boundaries to avoid losing too much
197  * text. This "unkind cut" may result in syntax errors and may trigger
198  * warnings from down-stream MTAs.
199  *
200  * If Milter is enabled, pad a short header record with a dummy record so
201  * that a header record can safely be overwritten by a pointer record.
202  * This simplifies header modification enormously.
203  */
204  for (line = start; line; line = next_line) {
205  next_line = split_at(line, '\n');
206  line_len = next_line ? next_line - 1 - line : strlen(line);
207  if (line + line_len > start + var_header_limit) {
208  if (line - start > 0.9 * var_header_limit) /* nice cut */
209  break;
210  start[var_header_limit] = 0; /* unkind cut */
211  next_line = 0;
212  }
213  if (line == start) {
214  cleanup_out_string(state, REC_TYPE_NORM, line);
215  if ((state->milters || cleanup_milters)
216  && line_len < REC_TYPE_PTR_PAYL_SIZE)
217  rec_pad(state->dst, REC_TYPE_DTXT,
218  REC_TYPE_PTR_PAYL_SIZE - line_len);
219  } else if (IS_SPACE_TAB(*line)) {
220  cleanup_out_string(state, REC_TYPE_NORM, line);
221  } else {
222  cleanup_out_format(state, REC_TYPE_NORM, "\t%s", line);
223  }
224  }
225 }
void cleanup_out_string(CLEANUP_STATE *state, int type, const char *string)
Definition: cleanup_out.c:148
#define IS_SPACE_TAB(ch)
Definition: lex_822.h:17
int smtputf8
Definition: cleanup.h:134
void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
Definition: cleanup_out.c:155
#define CLEANUP_STAT_SIZE
Definition: cleanup_user.h:59
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define REC_TYPE_PTR_PAYL_SIZE
Definition: rec_type.h:180
#define STR
Definition: cleanup_out.c:98
#define SMTPUTF8_FLAG_HEADER
Definition: smtputf8.h:98
MILTERS * milters
Definition: cleanup.h:109
#define CLEANUP_OUT_BUF(s, t, b)
Definition: cleanup.h:236
int var_smtputf8_enable
Definition: mail_params.c:343
int const char * fmt
#define SMTPUTF8_FLAG_REQUESTED
Definition: smtputf8.h:97
VSTRING * vstring_vsprintf(VSTRING *vp, const char *format, va_list ap)
Definition: vstring.c:614
#define REC_TYPE_CONT
Definition: rec_type.h:58
void cleanup_out(CLEANUP_STATE *state, int type, const char *string, ssize_t len)
Definition: cleanup_out.c:102
int rec_pad(VSTREAM *stream, int type, ssize_t len)
Definition: record.c:411
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define CLEANUP_FLAG_AUTOUTF8
Definition: cleanup_user.h:27
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define TEXT_RECORD(t)
char * queue_id
Definition: cleanup.h:56
int rec_put(VSTREAM *stream, int type, const char *data, ssize_t len)
Definition: record.c:194
#define allascii(s)
Definition: stringops.h:66
int var_line_limit
Definition: mail_params.c:263
VSTREAM * dst
Definition: cleanup.h:53
#define CLEANUP_OUT_OK(s)
Definition: cleanup.h:239
int var_header_limit
Definition: mail_params.c:320
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
#define REC_TYPE_NORM
Definition: rec_type.h:59
#define CLEANUP_STAT_WRITE
Definition: cleanup_user.h:58
MILTERS * cleanup_milters
Definition: cleanup_init.c:279
#define REC_TYPE_DTXT
Definition: rec_type.h:60
void cleanup_out_header(CLEANUP_STATE *state, VSTRING *header_buf)
Definition: cleanup_out.c:170