Postfix3.3.1
bounce_templates.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce_templates 3
4 /* SUMMARY
5 /* bounce template group support
6 /* SYNOPSIS
7 /* #include <bounce_template.h>
8 /*
9 /* typedef struct {
10 /* .in +4
11 /* BOUNCE_TEMPLATE *failure;
12 /* BOUNCE_TEMPLATE *delay;
13 /* BOUNCE_TEMPLATE *success;
14 /* BOUNCE_TEMPLATE *verify;
15 /* .in -4
16 /* } BOUNCE_TEMPLATES;
17 /*
18 /* BOUNCE_TEMPLATES *bounce_templates_create(void)
19 /*
20 /* void bounce_templates_free(templates)
21 /* BOUNCE_TEMPLATES *templates;
22 /*
23 /* void bounce_templates_load(stream, templates)
24 /* VSTREAM *stream;
25 /* BOUNCE_TEMPLATES *templates;
26 /*
27 /* void bounce_templates_expand(stream, templates)
28 /* VSTREAM *stream;
29 /* BOUNCE_TEMPLATES *templates;
30 /*
31 /* void bounce_templates_dump(stream, templates)
32 /* VSTREAM *stream;
33 /* BOUNCE_TEMPLATES *templates;
34 /* DESCRIPTION
35 /* This module implements support for bounce template groups
36 /* (i.e. groups that contain one template of each type).
37 /*
38 /* bounce_templates_create() creates a bounce template group,
39 /* with default settings.
40 /*
41 /* bounce_templates_free() destroys a bounce template group.
42 /*
43 /* bounce_templates_load() reads zero or more bounce templates
44 /* from the specified file to override built-in templates.
45 /*
46 /* bounce_templates_expand() expands $name macros and writes
47 /* the text portions of the specified bounce template group
48 /* to the specified stream.
49 /*
50 /* bounce_templates_dump() writes the complete content of the
51 /* specified bounce template group to the specified stream.
52 /* The format is compatible with bounce_templates_load().
53 /* DIAGNOSTICS
54 /* Fatal error: out of memory, undefined macro name in template.
55 /* SEE ALSO
56 /* bounce_template(3) bounce template support
57 /* LICENSE
58 /* .ad
59 /* .fi
60 /* The Secure Mailer license must be distributed with this software.
61 /* AUTHOR(S)
62 /* Wietse Venema
63 /* IBM T.J. Watson Research
64 /* P.O. Box 704
65 /* Yorktown Heights, NY 10598, USA
66 /*--*/
67 
68 /* System library. */
69 
70 #include <sys_defs.h>
71 #include <ctype.h>
72 #include <string.h>
73 
74 /* Utility library. */
75 
76 #include <msg.h>
77 #include <mymalloc.h>
78 #include <stringops.h>
79 #include <vstring.h>
80 #include <vstream.h>
81 #include <vstring_vstream.h>
82 
83 /* Global library. */
84 
85 #include <mail_addr.h>
86 #include <mail_proto.h>
87 
88 /* Application-specific. */
89 
90 #include <bounce_template.h>
91 
92  /*
93  * The fail template is for permanent failure.
94  */
95 static const char *def_bounce_failure_body[] = {
96  "This is the mail system at host $myhostname.",
97  "",
98  "I'm sorry to have to inform you that your message could not",
99  "be delivered to one or more recipients. It's attached below.",
100  "",
101  "For further assistance, please send mail to " MAIL_ADDR_POSTMASTER ".",
102  "",
103  "If you do so, please include this problem report. You can",
104  "delete your own text from the attached returned message.",
105  "",
106  " The mail system",
107  0,
108 };
109 
110 static const BOUNCE_TEMPLATE def_bounce_failure_template = {
111  0,
113  "[built-in]",
114  "us-ascii",
116  MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
117  "Undelivered Mail Returned to Sender",
118  "Postmaster Copy: Undelivered Mail",
119  def_bounce_failure_body,
120  &def_bounce_failure_template,
121 };
122 
123  /*
124  * The delay template is for delayed mail notifications.
125  */
126 static const char *def_bounce_delay_body[] = {
127  "This is the mail system at host $myhostname.",
128  "",
129  "####################################################################",
130  "# THIS IS A WARNING ONLY. YOU DO NOT NEED TO RESEND YOUR MESSAGE. #",
131  "####################################################################",
132  "",
133  "Your message could not be delivered for more than $delay_warning_time_hours hour(s)."
134  ,
135  "It will be retried until it is $maximal_queue_lifetime_days day(s) old.",
136  "",
137  "For further assistance, please send mail to " MAIL_ADDR_POSTMASTER ".",
138  "",
139  "If you do so, please include this problem report. You can",
140  "delete your own text from the attached returned message.",
141  "",
142  " The mail system",
143  0,
144 };
145 
146 static const BOUNCE_TEMPLATE def_bounce_delay_template = {
147  0,
149  "[built-in]",
150  "us-ascii",
152  MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
153  "Delayed Mail (still being retried)",
154  "Postmaster Warning: Delayed Mail",
155  def_bounce_delay_body,
156  &def_bounce_delay_template
157 };
158 
159  /*
160  * The success template is for "delivered", "expanded" and "relayed" success
161  * notifications.
162  */
163 static const char *def_bounce_success_body[] = {
164  "This is the mail system at host $myhostname.",
165  "",
166  "Your message was successfully delivered to the destination(s)",
167  "listed below. If the message was delivered to mailbox you will",
168  "receive no further notifications. Otherwise you may still receive",
169  "notifications of mail delivery errors from other systems.",
170  "",
171  " The mail system",
172  0,
173 };
174 
175 static const BOUNCE_TEMPLATE def_bounce_success_template = {
176  0,
178  "[built-in]",
179  "us-ascii",
181  MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
182  "Successful Mail Delivery Report",
183  0,
184  def_bounce_success_body,
185  &def_bounce_success_template,
186 };
187 
188  /*
189  * The "verify" template is for verbose delivery (sendmail -v) and for
190  * address verification (sendmail -bv).
191  */
192 static const char *def_bounce_verify_body[] = {
193  "This is the mail system at host $myhostname.",
194  "",
195  "Enclosed is the mail delivery report that you requested.",
196  "",
197  " The mail system",
198  0,
199 };
200 
201 static const BOUNCE_TEMPLATE def_bounce_verify_template = {
202  0,
204  "[built-in]",
205  "us-ascii",
207  MAIL_ADDR_MAIL_DAEMON " (Mail Delivery System)",
208  "Mail Delivery Status Report",
209  0,
210  def_bounce_verify_body,
211  &def_bounce_verify_template,
212 };
213 
214  /*
215  * SLMs.
216  */
217 #define STR(x) vstring_str(x)
218 
219 /* bounce_templates_create - create template group */
220 
222 {
223  BOUNCE_TEMPLATES *bs;
224 
225  bs = (BOUNCE_TEMPLATES *) mymalloc(sizeof(*bs));
226  bs->failure = bounce_template_create(&def_bounce_failure_template);
227  bs->delay = bounce_template_create(&def_bounce_delay_template);
228  bs->success = bounce_template_create(&def_bounce_success_template);
229  bs->verify = bounce_template_create(&def_bounce_verify_template);
230  return (bs);
231 }
232 
233 /* bounce_templates_free - destroy template group */
234 
236 {
241  myfree((void *) bs);
242 }
243 
244 /* bounce_templates_load - load template or group from stream */
245 
247 {
248  VSTRING *line_buf;
249  char *member_name;
250  VSTRING *multi_line_buf = 0;
251  VSTRING *saved_member_name = 0;
252  VSTRING *saved_end_marker = 0;
253  char *value;
254  int lineno;
255  const char *err;
256  char *cp;
257  int len; /* Grr... */
258 
259  /*
260  * XXX That's a lot of non-reusable code to parse a configuration file.
261  * Unfortunately, much of the "name = value" infrastructure is married to
262  * the dict(3) class which doesn't really help here.
263  */
264  line_buf = vstring_alloc(100);
265  lineno = 1;
266  while (vstring_get_nonl(line_buf, fp) > 0) {
267  lineno++;
268  cp = STR(line_buf) + strspn(STR(line_buf), " \t\n\v\f\r");
269  if (*cp == 0 || *cp == '#')
270  continue;
271  if ((err = split_nameval(STR(line_buf), &member_name, &value)) != 0)
272  msg_fatal("%s, line %d: %s: \"%s\"",
273  VSTREAM_PATH(fp), lineno, err, STR(line_buf));
274  if (value[0] == '<' && value[1] == '<') {
275  value += 2;
276  while (ISSPACE(*value))
277  value++;
278  if (*value == 0)
279  msg_fatal("%s, line %d: missing end marker after <<",
280  VSTREAM_PATH(fp), lineno);
281  if (!ISALNUM(*value))
282  msg_fatal("%s, line %d: malformed end marker after <<",
283  VSTREAM_PATH(fp), lineno);
284  if (multi_line_buf == 0) {
285  saved_member_name = vstring_alloc(100);
286  saved_end_marker = vstring_alloc(100);
287  multi_line_buf = vstring_alloc(100);
288  } else
289  VSTRING_RESET(multi_line_buf);
290  vstring_strcpy(saved_member_name, member_name);
291  vstring_strcpy(saved_end_marker, value);
292  while (vstring_get_nonl(line_buf, fp) > 0) {
293  lineno++;
294  if (strcmp(STR(line_buf), STR(saved_end_marker)) == 0)
295  break;
296  if (VSTRING_LEN(multi_line_buf) > 0)
297  vstring_strcat(multi_line_buf, "\n");
298  vstring_strcat(multi_line_buf, STR(line_buf));
299  }
300  if (vstream_feof(fp))
301  msg_warn("%s, line %d: missing \"%s\" end marker",
302  VSTREAM_PATH(fp), lineno, value);
303  member_name = STR(saved_member_name);
304  value = STR(multi_line_buf);
305  }
306 #define MATCH_TMPL_NAME(tname, tname_len, mname) \
307  (strncmp(tname, mname, tname_len = strlen(tname)) == 0 \
308  && strcmp(mname + tname_len, "_template") == 0)
309 
310  if (MATCH_TMPL_NAME(ts->failure->class, len, member_name))
311  bounce_template_load(ts->failure, VSTREAM_PATH(fp), value);
312  else if (MATCH_TMPL_NAME(ts->delay->class, len, member_name))
313  bounce_template_load(ts->delay, VSTREAM_PATH(fp), value);
314  else if (MATCH_TMPL_NAME(ts->success->class, len, member_name))
315  bounce_template_load(ts->success, VSTREAM_PATH(fp), value);
316  else if (MATCH_TMPL_NAME(ts->verify->class, len, member_name))
317  bounce_template_load(ts->verify, VSTREAM_PATH(fp), value);
318  else
319  msg_warn("%s, line %d: unknown template name: %s "
320  "-- ignoring this template",
321  VSTREAM_PATH(fp), lineno, member_name);
322  }
323  vstring_free(line_buf);
324  if (multi_line_buf) {
325  vstring_free(saved_member_name);
326  vstring_free(saved_end_marker);
327  vstring_free(multi_line_buf);
328  }
329 }
330 
331 /* bounce_plain_out - output line as plain text */
332 
333 static int bounce_plain_out(VSTREAM *fp, const char *text)
334 {
335  vstream_fprintf(fp, "%s\n", text);
336  return (0);
337 }
338 
339 /* bounce_templates_expand - dump expanded template group text to stream */
340 
342 {
343  BOUNCE_TEMPLATE *tp;
344 
345  tp = ts->failure;
346  vstream_fprintf(fp, "expanded_%s_text = <<EOF\n", tp->class);
347  bounce_template_expand(bounce_plain_out, fp, tp);
348  vstream_fprintf(fp, "EOF\n\n");
349 
350  tp = ts->delay;
351  vstream_fprintf(fp, "expanded_%s_text = <<EOF\n", tp->class);
352  bounce_template_expand(bounce_plain_out, fp, tp);
353  vstream_fprintf(fp, "EOF\n\n");
354 
355  tp = ts->success;
356  vstream_fprintf(fp, "expanded_%s_text = <<EOF\n", tp->class);
357  bounce_template_expand(bounce_plain_out, fp, tp);
358  vstream_fprintf(fp, "EOF\n\n");
359 
360  tp = ts->verify;
361  vstream_fprintf(fp, "expanded_%s_text = <<EOF\n", tp->class);
362  bounce_template_expand(bounce_plain_out, fp, tp);
363  vstream_fprintf(fp, "EOF\n");
364 }
365 
366 /* bounce_templates_dump - dump bounce template group to stream */
367 
369 {
370  BOUNCE_TEMPLATE *tp;
371 
372  tp = ts->failure;
373  vstream_fprintf(fp, "%s_template = <<EOF\n", tp->class);
374  bounce_template_dump(fp, tp);
375  vstream_fprintf(fp, "EOF\n\n");
376 
377  tp = ts->delay;
378  vstream_fprintf(fp, "%s_template = <<EOF\n", tp->class);
379  bounce_template_dump(fp, tp);
380  vstream_fprintf(fp, "EOF\n\n");
381 
382  tp = ts->success;
383  vstream_fprintf(fp, "%s_template = <<EOF\n", tp->class);
384  bounce_template_dump(fp, tp);
385  vstream_fprintf(fp, "EOF\n\n");
386 
387  tp = ts->verify;
388  vstream_fprintf(fp, "%s_template = <<EOF\n", tp->class);
389  bounce_template_dump(fp, tp);
390  vstream_fprintf(fp, "EOF\n");
391 }
#define STR(x)
BOUNCE_TEMPLATE * verify
void myfree(void *ptr)
Definition: mymalloc.c:207
#define MAIL_ADDR_POSTMASTER
Definition: mail_addr.h:17
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
#define BOUNCE_TMPL_CLASS_SUCCESS
const char * class
void bounce_templates_dump(VSTREAM *fp, BOUNCE_TEMPLATES *ts)
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
#define BOUNCE_TMPL_CLASS_DELAY
void bounce_template_free(BOUNCE_TEMPLATE *tp)
#define VSTRING_LEN(vp)
Definition: vstring.h:72
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
#define ISALNUM(c)
Definition: sys_defs.h:1745
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
Definition: vstream.c:1348
BOUNCE_TEMPLATES * bounce_templates_create(void)
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define MAIL_ADDR_MAIL_DAEMON
Definition: mail_addr.h:18
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define BOUNCE_TMPL_CLASS_FAILURE
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
BOUNCE_TEMPLATE * success
void bounce_template_expand(BOUNCE_XP_PUT_FN out_fn, VSTREAM *fp, BOUNCE_TEMPLATE *tp)
BOUNCE_TEMPLATE * bounce_template_create(const BOUNCE_TEMPLATE *prototype)
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
void bounce_templates_expand(VSTREAM *fp, BOUNCE_TEMPLATES *ts)
void bounce_templates_free(BOUNCE_TEMPLATES *bs)
void bounce_templates_load(VSTREAM *fp, BOUNCE_TEMPLATES *ts)
#define vstream_feof(vp)
Definition: vstream.h:121
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define BOUNCE_TMPL_CLASS_VERIFY
BOUNCE_TEMPLATE * failure
#define ISSPACE(c)
Definition: sys_defs.h:1753
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
void bounce_template_dump(VSTREAM *fp, BOUNCE_TEMPLATE *tp)
void bounce_template_load(BOUNCE_TEMPLATE *tp, const char *origin, const char *buffer)
#define MATCH_TMPL_NAME(tname, tname_len, mname)
#define MAIL_ATTR_ENC_7BIT
Definition: mail_proto.h:204
BOUNCE_TEMPLATE * delay
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150