Home | History | Annotate | Line # | Download | only in global
      1 /*	$NetBSD: bounce.c,v 1.5 2026/05/09 18:49:15 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	bounce 3
      6 /* SUMMARY
      7 /*	bounce service client
      8 /* SYNOPSIS
      9 /*	#include <bounce.h>
     10 /*
     11 /*	int	bounce_append(flags, id, stats, recipient, relay, tstats, dsn)
     12 /*	int	flags;
     13 /*	const char *id;
     14 /*	MSG_STATS *stats;
     15 /*	RECIPIENT *rcpt;
     16 /*	const char *relay;
     17 /*	const POL_STATS *tstats;
     18 /*	DSN	*dsn;
     19 /*
     20 /*	int	bounce_flush(flags, queue, id, encoding, sendopts, sender,
     21 /*				dsn_envid, dsn_ret)
     22 /*	int	flags;
     23 /*	const char *queue;
     24 /*	const char *id;
     25 /*	const char *encoding;
     26 /*	int	sendopts;
     27 /*	const char *sender;
     28 /*	const char *dsn_envid;
     29 /*	int	dsn_ret;
     30 /*
     31 /*	int	bounce_flush_verp(flags, queue, id, encoding, sendopts,
     32 /*				sender, dsn_envid, dsn_ret, verp_delims)
     33 /*	int	flags;
     34 /*	const char *queue;
     35 /*	const char *id;
     36 /*	const char *encoding;
     37 /*	int	sendopts;
     38 /*	const char *sender;
     39 /*	const char *dsn_envid;
     40 /*	int	dsn_ret;
     41 /*	const char *verp_delims;
     42 /*
     43 /*	int	bounce_one(flags, queue, id, encoding, sendopts, sender,
     44 /*				dsn_envid, ret, stats, recipient, relay,
     45 /*				tstats, dsn)
     46 /*	int	flags;
     47 /*	const char *queue;
     48 /*	const char *id;
     49 /*	const char *encoding;
     50 /*	int	sendopts;
     51 /*	const char *sender;
     52 /*	const char *dsn_envid;
     53 /*	int	dsn_ret;
     54 /*	MSG_STATS *stats;
     55 /*	RECIPIENT *rcpt;
     56 /*	const char *relay;
     57 /*	const POL_STATS *tstats;
     58 /*	DSN	*dsn;
     59 /*
     60 /*	void	bounce_client_init(title, maps)
     61 /*	const char *title;
     62 /*	const char *maps;
     63 /* INTERNAL API
     64 /*	DSN_FILTER *delivery_status_filter;
     65 /*
     66 /*	int	bounce_append_intern(flags, id, stats, recipient, relay, tstats, dsn)
     67 /*	int	flags;
     68 /*	const char *id;
     69 /*	MSG_STATS *stats;
     70 /*	RECIPIENT *rcpt;
     71 /*	const char *relay;
     72 /*	const POL_STATS *tstats;
     73 /*	DSN	*dsn;
     74 /*
     75 /*	int	bounce_one_intern(flags, queue, id, encoding, sendopts, sender,
     76 /*			dsn_envid, ret, stats, recipient, relay, tstats, dsn)
     77 /*	int	flags;
     78 /*	const char *queue;
     79 /*	const char *id;
     80 /*	const char *encoding;
     81 /*	int	sendopts;
     82 /*	const char *sender;
     83 /*	const char *dsn_envid;
     84 /*	int	dsn_ret;
     85 /*	MSG_STATS *stats;
     86 /*	RECIPIENT *rcpt;
     87 /*	const char *relay;
     88 /*	const POL_STATS *tstats;
     89 /*	DSN	*dsn;
     90 /* DESCRIPTION
     91 /*	This module implements the client interface to the message
     92 /*	bounce service, which maintains a per-message log of status
     93 /*	records with recipients that were bounced, and the dsn_text why.
     94 /*
     95 /*	bounce_append() appends a dsn_text for non-delivery to the
     96 /*	bounce log for the named recipient, updates the address
     97 /*	verification service, or updates a message delivery record
     98 /*	on request by the sender. The flags argument determines
     99 /*	the action.
    100 /*
    101 /*	bounce_flush() actually bounces the specified message to
    102 /*	the specified sender, including the bounce log that was
    103 /*	built with bounce_append(). The bounce logfile is removed
    104 /*	upon successful completion.
    105 /*
    106 /*	bounce_flush_verp() is like bounce_flush(), but sends one
    107 /*	notification per recipient, with the failed recipient encoded
    108 /*	into the sender address.
    109 /*
    110 /*	bounce_one() bounces one recipient and immediately sends a
    111 /*	notification to the sender. This procedure does not append
    112 /*	the recipient and dsn_text to the per-message bounce log, and
    113 /*	should be used when a delivery agent changes the error
    114 /*	return address in a manner that depends on the recipient
    115 /*	address.
    116 /*
    117 /*	bounce_client_init() initializes an optional DSN filter.
    118 /*
    119 /*	bounce_append_intern() and bounce_one_intern() are for use
    120 /*	after the DSN filter.
    121 /*
    122 /*	Arguments:
    123 /* .IP flags
    124 /*	The bitwise OR of zero or more of the following (specify
    125 /*	BOUNCE_FLAG_NONE to request no special processing):
    126 /* .RS
    127 /* .IP BOUNCE_FLAG_CLEAN
    128 /*	Delete the bounce log in case of an error (as in: pretend
    129 /*	that we never even tried to bounce this message).
    130 /* .IP BOUNCE_FLAG_DELRCPT
    131 /*	When specified with a flush request, request that
    132 /*	recipients be deleted from the queue file.
    133 /*
    134 /*	Note: the bounce daemon ignores this request when the
    135 /*	recipient queue file offset is <= 0.
    136 /* .IP DEL_REQ_FLAG_MTA_VRFY
    137 /*	The message is an MTA-requested address verification probe.
    138 /*	Update the address verification database instead of bouncing
    139 /*	mail.
    140 /* .IP DEL_REQ_FLAG_USR_VRFY
    141 /*	The message is a user-requested address expansion probe.
    142 /*	Update the message delivery record instead of bouncing mail.
    143 /* .IP DEL_REQ_FLAG_RECORD
    144 /*	This is a normal message with logged delivery. Update the
    145 /*	message delivery record and bounce the mail.
    146 /* .RE
    147 /* .IP queue
    148 /*	The message queue name of the original message file.
    149 /* .IP id
    150 /*	The message queue id if the original message file. The bounce log
    151 /*	file has the same name as the original message file.
    152 /* .IP stats
    153 /*	Time stamps from different message delivery stages
    154 /*	and session reuse count.
    155 /* .IP rcpt
    156 /*	Recipient information. See recipient_list(3).
    157 /* .IP relay
    158 /*	Name of the host that the message could not be delivered to.
    159 /*	This information is used for syslogging only.
    160 /* .IP encoding
    161 /*	The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
    162 /* .IP sendopts
    163 /*	Sender-requested SMTPUTF8 or RequireTLS support.
    164 /* .IP sender
    165 /*	The sender envelope address.
    166 /* .IP tstats
    167 /*	TLS per-feature status.
    168 /* .IP dsn_envid
    169 /*	Optional DSN envelope ID.
    170 /* .IP dsn_ret
    171 /*	Optional DSN return full/headers option.
    172 /* .IP dsn
    173 /*	Delivery status. See dsn(3). The specified action is ignored.
    174 /* .IP verp_delims
    175 /*	VERP delimiter characters, used when encoding the failed
    176 /*	sender into the envelope sender address.
    177 /* DIAGNOSTICS
    178 /*	In case of success, these functions log the action, and return a
    179 /*	zero value. Otherwise, the functions return a non-zero result,
    180 /*	and when BOUNCE_FLAG_CLEAN is disabled, log that message
    181 /*	delivery is deferred.
    182 /* .IP title
    183 /*	The origin of the optional DSN filter lookup table names.
    184 /* .IP maps
    185 /*	The optional "type:table" DSN filter lookup table names,
    186 /*	separated by comma or whitespace.
    187 /* BUGS
    188 /*	Should be replaced by routines with an attribute-value based
    189 /*	interface instead of an interface that uses a rigid argument list.
    190 /* LICENSE
    191 /* .ad
    192 /* .fi
    193 /*	The Secure Mailer license must be distributed with this software.
    194 /* AUTHOR(S)
    195 /*	Wietse Venema
    196 /*	IBM T.J. Watson Research
    197 /*	P.O. Box 704
    198 /*	Yorktown Heights, NY 10598, USA
    199 /*
    200 /*	Wietse Venema
    201 /*	Google, Inc.
    202 /*	111 8th Avenue
    203 /*	New York, NY 10011, USA
    204 /*
    205 /*	Wietse Venema
    206 /*	porcupine.org
    207 /*--*/
    208 
    209 /* System library. */
    210 
    211 #include <sys_defs.h>
    212 #include <string.h>
    213 
    214 /* Utility library. */
    215 
    216 #include <msg.h>
    217 #include <vstring.h>
    218 #include <mymalloc.h>
    219 
    220 /* Global library. */
    221 
    222 #define DSN_INTERN
    223 #include <mail_params.h>
    224 #include <mail_proto.h>
    225 #include <log_adhoc.h>
    226 #include <dsn_util.h>
    227 #include <rcpt_print.h>
    228 #include <dsn_print.h>
    229 #include <verify.h>
    230 #include <defer.h>
    231 #include <trace.h>
    232 #include <bounce.h>
    233 
    234 /* Shared internally, between bounce and defer clients. */
    235 
    236 DSN_FILTER *delivery_status_filter;
    237 
    238 /* bounce_append - append delivery status to per-message bounce log */
    239 
    240 int     bounce_append(int flags, const char *id, MSG_STATS *stats,
    241 		              RECIPIENT *rcpt, const char *relay,
    242 		              const POL_STATS *tstats, DSN *dsn)
    243 {
    244     DSN     my_dsn = *dsn;
    245     DSN    *dsn_res;
    246 
    247     /*
    248      * Sanity check. If we're really confident, change this into msg_panic
    249      * (remember, this information may be under control by a hostile server).
    250      */
    251     if (my_dsn.status[0] != '5' || !dsn_valid(my_dsn.status)) {
    252 	msg_warn("bounce_append: ignoring dsn code \"%s\"", my_dsn.status);
    253 	my_dsn.status = "5.0.0";
    254     }
    255 
    256     /*
    257      * DSN filter (Postfix 3.0).
    258      */
    259     if (delivery_status_filter != 0
    260     && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) {
    261 	if (dsn_res->status[0] == '4')
    262 	    return (defer_append_intern(flags, id, stats, rcpt, relay, tstats,
    263 					dsn_res));
    264 	my_dsn = *dsn_res;
    265     }
    266     return (bounce_append_intern(flags, id, stats, rcpt, relay, tstats,
    267 				 &my_dsn));
    268 }
    269 
    270 /* bounce_append_intern - append delivery status to per-message bounce log */
    271 
    272 int     bounce_append_intern(int flags, const char *id, MSG_STATS *stats,
    273 			             RECIPIENT *rcpt, const char *relay,
    274 			             const POL_STATS *tstats, DSN *dsn)
    275 {
    276     DSN     my_dsn = *dsn;
    277     int     status;
    278 
    279     /*
    280      * MTA-requested address verification information is stored in the verify
    281      * service database.
    282      */
    283     if (flags & DEL_REQ_FLAG_MTA_VRFY) {
    284 	my_dsn.action = "undeliverable";
    285 	status = verify_append(id, stats, rcpt, relay, tstats, &my_dsn,
    286 			       DEL_RCPT_STAT_BOUNCE);
    287 	return (status);
    288     }
    289 
    290     /*
    291      * User-requested address verification information is logged and mailed
    292      * to the requesting user.
    293      */
    294     if (flags & DEL_REQ_FLAG_USR_VRFY) {
    295 	my_dsn.action = "undeliverable";
    296 	status = trace_append(flags, id, stats, rcpt, relay, tstats, &my_dsn);
    297 	return (status);
    298     }
    299 
    300     /*
    301      * Normal (well almost) delivery. When we're pretending that we can't
    302      * bounce, don't create a defer log file when we wouldn't keep the bounce
    303      * log file. That's a lot of negatives in one sentence.
    304      */
    305     else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) {
    306 	return (-1);
    307     }
    308 
    309     /*
    310      * Normal mail delivery. May also send a delivery record to the user.
    311      *
    312      * XXX DSN We write all recipients to the bounce logfile regardless of DSN
    313      * NOTIFY options, because those options don't apply to postmaster
    314      * notifications.
    315      */
    316     else {
    317 	char   *my_status = mystrdup(my_dsn.status);
    318 	const char *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced";
    319 
    320 	/*
    321 	 * Supply default action.
    322 	 */
    323 	my_dsn.status = my_status;
    324 	if (var_soft_bounce) {
    325 	    my_status[0] = '4';
    326 	    my_dsn.action = "delayed";
    327 	} else {
    328 	    my_dsn.action = "failed";
    329 	}
    330 
    331 	if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
    332 				var_defer_service : var_bounce_service,
    333 				MAIL_ATTR_PROTO_BOUNCE,
    334 			   SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND),
    335 				SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags),
    336 				SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id),
    337 			    SEND_ATTR_FUNC(rcpt_print, (const void *) rcpt),
    338 			  SEND_ATTR_FUNC(dsn_print, (const void *) &my_dsn),
    339 				ATTR_TYPE_END) == 0
    340 	    && ((flags & DEL_REQ_FLAG_RECORD) == 0
    341 		|| trace_append(flags, id, stats, rcpt, relay, tstats,
    342 				&my_dsn) == 0)) {
    343 	    log_adhoc(id, stats, rcpt, relay, tstats, &my_dsn, log_status);
    344 	    status = (var_soft_bounce ? -1 : 0);
    345 	} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
    346 	    VSTRING *junk = vstring_alloc(100);
    347 
    348 	    my_dsn.status = "4.3.0";
    349 	    vstring_sprintf(junk, "%s or %s service failure",
    350 			    var_bounce_service, var_trace_service);
    351 	    my_dsn.reason = vstring_str(junk);
    352 	    status = defer_append_intern(flags, id, stats, rcpt, relay, tstats,
    353 					 &my_dsn);
    354 	    vstring_free(junk);
    355 	} else {
    356 	    status = -1;
    357 	}
    358 	myfree(my_status);
    359 	return (status);
    360     }
    361 }
    362 
    363 /* bounce_flush - flush the bounce log and deliver to the sender */
    364 
    365 int     bounce_flush(int flags, const char *queue, const char *id,
    366 		             const char *encoding, int sendopts,
    367 		             const char *sender, const char *dsn_envid,
    368 		             int dsn_ret)
    369 {
    370 
    371     /*
    372      * When we're pretending that we can't bounce, don't send a bounce
    373      * message.
    374      */
    375     if (var_soft_bounce)
    376 	return (-1);
    377     if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
    378 			    MAIL_ATTR_PROTO_BOUNCE,
    379 			    SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH),
    380 			    SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags),
    381 			    SEND_ATTR_STR(MAIL_ATTR_QUEUE, queue),
    382 			    SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id),
    383 			    SEND_ATTR_STR(MAIL_ATTR_ENCODING, encoding),
    384 			    SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, sendopts),
    385 			    SEND_ATTR_STR(MAIL_ATTR_SENDER, sender),
    386 			    SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid),
    387 			    SEND_ATTR_INT(MAIL_ATTR_DSN_RET, dsn_ret),
    388 			    ATTR_TYPE_END) == 0) {
    389 	return (0);
    390     } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
    391 	msg_info("%s: status=deferred (bounce failed)", id);
    392 	return (-1);
    393     } else {
    394 	return (-1);
    395     }
    396 }
    397 
    398 /* bounce_flush_verp - verpified notification */
    399 
    400 int     bounce_flush_verp(int flags, const char *queue, const char *id,
    401 			          const char *encoding, int sendopts,
    402 			          const char *sender, const char *dsn_envid,
    403 			          int dsn_ret, const char *verp_delims)
    404 {
    405 
    406     /*
    407      * When we're pretending that we can't bounce, don't send a bounce
    408      * message.
    409      */
    410     if (var_soft_bounce)
    411 	return (-1);
    412     if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
    413 			    MAIL_ATTR_PROTO_BOUNCE,
    414 			    SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_VERP),
    415 			    SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags),
    416 			    SEND_ATTR_STR(MAIL_ATTR_QUEUE, queue),
    417 			    SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id),
    418 			    SEND_ATTR_STR(MAIL_ATTR_ENCODING, encoding),
    419 			    SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, sendopts),
    420 			    SEND_ATTR_STR(MAIL_ATTR_SENDER, sender),
    421 			    SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid),
    422 			    SEND_ATTR_INT(MAIL_ATTR_DSN_RET, dsn_ret),
    423 			    SEND_ATTR_STR(MAIL_ATTR_VERPDL, verp_delims),
    424 			    ATTR_TYPE_END) == 0) {
    425 	return (0);
    426     } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
    427 	msg_info("%s: status=deferred (bounce failed)", id);
    428 	return (-1);
    429     } else {
    430 	return (-1);
    431     }
    432 }
    433 
    434 /* bounce_one - send notice for one recipient */
    435 
    436 int     bounce_one(int flags, const char *queue, const char *id,
    437 		           const char *encoding, int sendopts,
    438 		           const char *sender, const char *dsn_envid,
    439 		           int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt,
    440 	               const char *relay, const POL_STATS *tstats, DSN *dsn)
    441 {
    442     DSN     my_dsn = *dsn;
    443     DSN    *dsn_res;
    444 
    445     /*
    446      * Sanity check.
    447      */
    448     if (my_dsn.status[0] != '5' || !dsn_valid(my_dsn.status)) {
    449 	msg_warn("bounce_one: ignoring dsn code \"%s\"", my_dsn.status);
    450 	my_dsn.status = "5.0.0";
    451     }
    452 
    453     /*
    454      * DSN filter (Postfix 3.0).
    455      */
    456     if (delivery_status_filter != 0
    457     && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) {
    458 	if (dsn_res->status[0] == '4')
    459 	    return (defer_append_intern(flags, id, stats, rcpt, relay, tstats,
    460 					dsn_res));
    461 	my_dsn = *dsn_res;
    462     }
    463     return (bounce_one_intern(flags, queue, id, encoding, sendopts, sender,
    464 			      dsn_envid, dsn_ret, stats, rcpt, relay, tstats,
    465 			      &my_dsn));
    466 }
    467 
    468 /* bounce_one_intern - send notice for one recipient */
    469 
    470 int     bounce_one_intern(int flags, const char *queue, const char *id,
    471 			          const char *encoding, int sendopts,
    472 			          const char *sender, const char *dsn_envid,
    473 			          int dsn_ret, MSG_STATS *stats,
    474 			          RECIPIENT *rcpt, const char *relay,
    475 			          const POL_STATS *tstats, DSN *dsn)
    476 {
    477     DSN     my_dsn = *dsn;
    478     int     status;
    479 
    480     /*
    481      * MTA-requested address verification information is stored in the verify
    482      * service database.
    483      */
    484     if (flags & DEL_REQ_FLAG_MTA_VRFY) {
    485 	my_dsn.action = "undeliverable";
    486 	status = verify_append(id, stats, rcpt, relay, tstats, &my_dsn,
    487 			       DEL_RCPT_STAT_BOUNCE);
    488 	return (status);
    489     }
    490 
    491     /*
    492      * User-requested address verification information is logged and mailed
    493      * to the requesting user.
    494      */
    495     if (flags & DEL_REQ_FLAG_USR_VRFY) {
    496 	my_dsn.action = "undeliverable";
    497 	status = trace_append(flags, id, stats, rcpt, relay, tstats, &my_dsn);
    498 	return (status);
    499     }
    500 
    501     /*
    502      * When we're not bouncing, then use the standard multi-recipient logfile
    503      * based procedure.
    504      */
    505     else if (var_soft_bounce) {
    506 	return (bounce_append_intern(flags, id, stats, rcpt, relay, tstats,
    507 				     &my_dsn));
    508     }
    509 
    510     /*
    511      * Normal mail delivery. May also send a delivery record to the user.
    512      *
    513      * XXX DSN We send all recipients regardless of DSN NOTIFY options, because
    514      * those options don't apply to postmaster notifications.
    515      */
    516     else {
    517 
    518 	/*
    519 	 * Supply default action.
    520 	 */
    521 	my_dsn.action = "failed";
    522 
    523 	if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
    524 				MAIL_ATTR_PROTO_BOUNCE,
    525 			      SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_ONE),
    526 				SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags),
    527 				SEND_ATTR_STR(MAIL_ATTR_QUEUE, queue),
    528 				SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id),
    529 				SEND_ATTR_STR(MAIL_ATTR_ENCODING, encoding),
    530 				SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, sendopts),
    531 				SEND_ATTR_STR(MAIL_ATTR_SENDER, sender),
    532 			      SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid),
    533 				SEND_ATTR_INT(MAIL_ATTR_DSN_RET, dsn_ret),
    534 			    SEND_ATTR_FUNC(rcpt_print, (const void *) rcpt),
    535 			  SEND_ATTR_FUNC(dsn_print, (const void *) &my_dsn),
    536 				ATTR_TYPE_END) == 0
    537 	    && ((flags & DEL_REQ_FLAG_RECORD) == 0
    538 		|| trace_append(flags, id, stats, rcpt, relay, tstats,
    539 				&my_dsn) == 0)) {
    540 	    log_adhoc(id, stats, rcpt, relay, tstats, &my_dsn, "bounced");
    541 	    status = 0;
    542 	} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
    543 	    VSTRING *junk = vstring_alloc(100);
    544 
    545 	    my_dsn.status = "4.3.0";
    546 	    vstring_sprintf(junk, "%s or %s service failure",
    547 			    var_bounce_service, var_trace_service);
    548 	    my_dsn.reason = vstring_str(junk);
    549 	    status = defer_append_intern(flags, id, stats, rcpt, relay, tstats,
    550 					 &my_dsn);
    551 	    vstring_free(junk);
    552 	} else {
    553 	    status = -1;
    554 	}
    555 	return (status);
    556     }
    557 }
    558 
    559 /* bounce_client_init - initialize bounce/defer DSN filter */
    560 
    561 void    bounce_client_init(const char *title, const char *maps)
    562 {
    563     static const char myname[] = "bounce_client_init";
    564 
    565     if (delivery_status_filter != 0)
    566 	msg_panic("%s: duplicate initialization", myname);
    567     if (*maps)
    568 	delivery_status_filter = dsn_filter_create(title, maps);
    569 }
    570