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