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 */ 95static 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 110static const BOUNCE_TEMPLATE def_bounce_failure_template = { 111 0, 112 BOUNCE_TMPL_CLASS_FAILURE, 113 "[built-in]", 114 "us-ascii", 115 MAIL_ATTR_ENC_7BIT, 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 */ 126static 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 146static const BOUNCE_TEMPLATE def_bounce_delay_template = { 147 0, 148 BOUNCE_TMPL_CLASS_DELAY, 149 "[built-in]", 150 "us-ascii", 151 MAIL_ATTR_ENC_7BIT, 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 */ 163static 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 175static const BOUNCE_TEMPLATE def_bounce_success_template = { 176 0, 177 BOUNCE_TMPL_CLASS_SUCCESS, 178 "[built-in]", 179 "us-ascii", 180 MAIL_ATTR_ENC_7BIT, 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 */ 192static 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 201static const BOUNCE_TEMPLATE def_bounce_verify_template = { 202 0, 203 BOUNCE_TMPL_CLASS_VERIFY, 204 "[built-in]", 205 "us-ascii", 206 MAIL_ATTR_ENC_7BIT, 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 221BOUNCE_TEMPLATES *bounce_templates_create(void) 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 235void bounce_templates_free(BOUNCE_TEMPLATES *bs) 236{ 237 bounce_template_free(bs->failure); 238 bounce_template_free(bs->delay); 239 bounce_template_free(bs->success); 240 bounce_template_free(bs->verify); 241 myfree((char *) bs); 242} 243 244/* bounce_templates_load - load template or group from stream */ 245 246void bounce_templates_load(VSTREAM *fp, BOUNCE_TEMPLATES *ts) 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 333static 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 341void bounce_templates_expand(VSTREAM *fp, BOUNCE_TEMPLATES *ts) 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 368void bounce_templates_dump(VSTREAM *fp, BOUNCE_TEMPLATES *ts) 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} 392