/*++ /* NAME /* dsn_filter 3 /* SUMMARY /* filter delivery status code or text /* SYNOPSIS /* #include /* /* DSN_FILTER *dsn_filter_create( /* const char *title, /* const char *map_names) /* /* DSN *dsn_filter_lookup( /* DSN_FILTER *fp, /* DSN *dsn) /* /* void dsn_filter_free( /* DSN_FILTER *fp) /* DESCRIPTION /* This module maps (bounce or defer non-delivery status code /* and text) into replacement (bounce or defer non-delivery /* status code and text), or maps (success status code and /* text) into replacement (success status code and text). Other /* DSN attributes are passed through without modification. /* /* dsn_filter_create() instantiates a delivery status filter. /* /* dsn_filter_lookup() queries the specified filter. The input /* DSN must be a success, bounce or defer DSN. If a match is /* found a non-delivery status must map to a non-delivery /* status, a success status must map to a success status, and /* the text must be non-empty. The result is a null pointer /* when no valid match is found. Otherwise, the result is /* overwritten upon each call. This function must not be /* called with the result from a dsn_filter_lookup() call. /* /* dsn_filter_free() destroys the specified delivery status /* filter. /* /* Arguments: /* .IP title /* Origin of the mapnames argument, typically a configuration /* parameter name. This is reported in diagnostics. /* .IP mapnames /* List of lookup tables, separated by whitespace or comma. /* .IP fp /* filter created with dsn_filter_create() /* .IP dsn /* A success, bounce or defer DSN data structure. The /* dsn_filter_lookup() result value is in part a shallow copy /* of this argument. /* SEE ALSO /* maps(3) multi-table search /* DIAGNOSTICS /* Panic: invalid dsn argument; recursive call. Fatal error: /* memory allocation problem. Warning: invalid DSN lookup /* result. /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ /* * System libraries. */ #include /* * Utility library. */ #include #include #include /* * Global library. */ #include #include #include #include #include /* * Private data structure. */ struct DSN_FILTER { MAPS *maps; /* Replacement (status, text) */ VSTRING *buffer; /* Status code and text */ DSN_SPLIT dp; /* Parsing aid */ DSN dsn; /* Shallow copy */ }; /* * SLMs. */ #define STR(x) vstring_str(x) /* dsn_filter_create - create delivery status filter */ DSN_FILTER *dsn_filter_create(const char *title, const char *map_names) { static const char myname[] = "dsn_filter_create"; DSN_FILTER *fp; if (msg_verbose) msg_info("%s: %s %s", myname, title, map_names); fp = (DSN_FILTER *) mymalloc(sizeof(*fp)); fp->buffer = vstring_alloc(100); fp->maps = maps_create(title, map_names, DICT_FLAG_LOCK); return (fp); } /* dsn_filter_lookup - apply delivery status filter */ DSN *dsn_filter_lookup(DSN_FILTER *fp, DSN *dsn) { static const char myname[] = "dsn_filter_lookup"; const char *result; int ndr_dsn = 0; if (msg_verbose) msg_info("%s: %s %s", myname, dsn->status, dsn->reason); /* * XXX Instead of hard-coded '4' etc., use some form of encapsulation * when reading or updating the status class field. */ #define IS_SUCCESS_DSN(s) (dsn_valid(s) && (s)[0] == '2') #define IS_NDR_DSN(s) (dsn_valid(s) && ((s)[0] == '4' || (s)[0] == '5')) /* * Sanity check. We filter only success/bounce/defer DSNs. */ if (IS_SUCCESS_DSN(dsn->status)) ndr_dsn = 0; else if (IS_NDR_DSN(dsn->status)) ndr_dsn = 1; else msg_panic("%s: dsn argument with bad status code: %s", myname, dsn->status); /* * Sanity check. A delivery status filter must not be invoked with its * own result. */ if (dsn->reason == fp->dsn.reason) msg_panic("%s: recursive call is not allowed", myname); /* * Look up replacement status and text. */ vstring_sprintf(fp->buffer, "%s %s", dsn->status, dsn->reason); if ((result = maps_find(fp->maps, STR(fp->buffer), 0)) != 0) { /* Sanity check. Do not allow success<=>error mappings. */ if ((ndr_dsn == 0 && !IS_SUCCESS_DSN(result)) || (ndr_dsn != 0 && !IS_NDR_DSN(result))) { msg_warn("%s: bad status code: %s", fp->maps->title, result); return (0); } else { vstring_strcpy(fp->buffer, result); dsn_split(&fp->dp, "can't happen", STR(fp->buffer)); (void) DSN_ASSIGN(&fp->dsn, DSN_STATUS(fp->dp.dsn), (result[0] == '4' ? "delayed" : result[0] == '5' ? "failed" : dsn->action), fp->dp.text, dsn->dtype, dsn->dtext, dsn->mtype, dsn->mname); return (&fp->dsn); } } return (0); } /* dsn_filter_free - destroy delivery status filter */ void dsn_filter_free(DSN_FILTER *fp) { static const char myname[] = "dsn_filter_free"; if (msg_verbose) msg_info("%s: %s", myname, fp->maps->title); maps_free(fp->maps); vstring_free(fp->buffer); myfree((void *) fp); }