Home | History | Annotate | Line # | Download | only in global
      1 /*	$NetBSD: dsn_filter.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	dsn_filter 3
      6 /* SUMMARY
      7 /*	filter delivery status code or text
      8 /* SYNOPSIS
      9 /*	#include <dsn_filter.h>
     10 /*
     11 /*	DSN_FILTER *dsn_filter_create(
     12 /*	const char *title,
     13 /*	const char *map_names)
     14 /*
     15 /*	DSN	*dsn_filter_lookup(
     16 /*	DSN_FILTER *fp,
     17 /*	DSN	*dsn)
     18 /*
     19 /*	void	dsn_filter_free(
     20 /*	DSN_FILTER *fp)
     21 /* DESCRIPTION
     22 /*	This module maps (bounce or defer non-delivery status code
     23 /*	and text) into replacement (bounce or defer non-delivery
     24 /*	status code and text), or maps (success status code and
     25 /*	text) into replacement (success status code and text). Other
     26 /*	DSN attributes are passed through without modification.
     27 /*
     28 /*	dsn_filter_create() instantiates a delivery status filter.
     29 /*
     30 /*	dsn_filter_lookup() queries the specified filter. The input
     31 /*	DSN must be a success, bounce or defer DSN. If a match is
     32 /*	found a non-delivery status must map to a non-delivery
     33 /*	status, a success status must map to a success status, and
     34 /*	the text must be non-empty. The result is a null pointer
     35 /*	when no valid match is found. Otherwise, the result is
     36 /*	overwritten upon each call.  This function must not be
     37 /*	called with the result from a dsn_filter_lookup() call.
     38 /*
     39 /*	dsn_filter_free() destroys the specified delivery status
     40 /*	filter.
     41 /*
     42 /*	Arguments:
     43 /* .IP title
     44 /*	Origin of the mapnames argument, typically a configuration
     45 /*	parameter name. This is reported in diagnostics.
     46 /* .IP mapnames
     47 /*	List of lookup tables, separated by whitespace or comma.
     48 /* .IP fp
     49 /*	filter created with dsn_filter_create()
     50 /* .IP dsn
     51 /*	A success, bounce or defer DSN data structure. The
     52 /*	dsn_filter_lookup() result value is in part a shallow copy
     53 /*	of this argument.
     54 /* SEE ALSO
     55 /*	maps(3) multi-table search
     56 /* DIAGNOSTICS
     57 /*	Panic: invalid dsn argument; recursive call. Fatal error:
     58 /*	memory allocation problem. Warning: invalid DSN lookup
     59 /*	result.
     60 /* LICENSE
     61 /* .ad
     62 /* .fi
     63 /*	The Secure Mailer license must be distributed with this software.
     64 /* AUTHOR(S)
     65 /*	Wietse Venema
     66 /*	IBM T.J. Watson Research
     67 /*	P.O. Box 704
     68 /*	Yorktown Heights, NY 10598, USA
     69 /*--*/
     70 
     71  /*
     72   * System libraries.
     73   */
     74 #include <sys_defs.h>
     75 
     76  /*
     77   * Utility library.
     78   */
     79 #include <msg.h>
     80 #include <mymalloc.h>
     81 #include <vstring.h>
     82 
     83  /*
     84   * Global library.
     85   */
     86 #include <maps.h>
     87 #include <dsn.h>
     88 #include <dsn_util.h>
     89 #include <maps.h>
     90 #include <dsn_filter.h>
     91 
     92  /*
     93   * Private data structure.
     94   */
     95 struct DSN_FILTER {
     96     MAPS   *maps;			/* Replacement (status, text) */
     97     VSTRING *buffer;			/* Status code and text */
     98     DSN_SPLIT dp;			/* Parsing aid */
     99     DSN     dsn;			/* Shallow copy */
    100 };
    101 
    102  /*
    103   * SLMs.
    104   */
    105 #define STR(x) vstring_str(x)
    106 
    107 /* dsn_filter_create - create delivery status filter */
    108 
    109 DSN_FILTER *dsn_filter_create(const char *title, const char *map_names)
    110 {
    111     static const char myname[] = "dsn_filter_create";
    112     DSN_FILTER *fp;
    113 
    114     if (msg_verbose)
    115 	msg_info("%s: %s %s", myname, title, map_names);
    116 
    117     fp = (DSN_FILTER *) mymalloc(sizeof(*fp));
    118     fp->buffer = vstring_alloc(100);
    119     fp->maps = maps_create(title, map_names, DICT_FLAG_LOCK);
    120     return (fp);
    121 }
    122 
    123 /* dsn_filter_lookup - apply delivery status filter */
    124 
    125 DSN    *dsn_filter_lookup(DSN_FILTER *fp, DSN *dsn)
    126 {
    127     static const char myname[] = "dsn_filter_lookup";
    128     const char *result;
    129     int     ndr_dsn = 0;
    130 
    131     if (msg_verbose)
    132 	msg_info("%s: %s %s", myname, dsn->status, dsn->reason);
    133 
    134     /*
    135      * XXX Instead of hard-coded '4' etc., use some form of encapsulation
    136      * when reading or updating the status class field.
    137      */
    138 #define IS_SUCCESS_DSN(s) (dsn_valid(s) && (s)[0] == '2')
    139 #define IS_NDR_DSN(s) (dsn_valid(s) && ((s)[0] == '4' || (s)[0] == '5'))
    140 
    141     /*
    142      * Sanity check. We filter only success/bounce/defer DSNs.
    143      */
    144     if (IS_SUCCESS_DSN(dsn->status))
    145 	ndr_dsn = 0;
    146     else if (IS_NDR_DSN(dsn->status))
    147 	ndr_dsn = 1;
    148     else
    149 	msg_panic("%s: dsn argument with bad status code: %s",
    150 		  myname, dsn->status);
    151 
    152     /*
    153      * Sanity check. A delivery status filter must not be invoked with its
    154      * own result.
    155      */
    156     if (dsn->reason == fp->dsn.reason)
    157 	msg_panic("%s: recursive call is not allowed", myname);
    158 
    159     /*
    160      * Look up replacement status and text.
    161      */
    162     vstring_sprintf(fp->buffer, "%s %s", dsn->status, dsn->reason);
    163     if ((result = maps_find(fp->maps, STR(fp->buffer), 0)) != 0) {
    164 	/* Sanity check. Do not allow success<=>error mappings. */
    165 	if ((ndr_dsn == 0 && !IS_SUCCESS_DSN(result))
    166 	    || (ndr_dsn != 0 && !IS_NDR_DSN(result))) {
    167 	    msg_warn("%s: bad status code: %s", fp->maps->title, result);
    168 	    return (0);
    169 	} else {
    170 	    vstring_strcpy(fp->buffer, result);
    171 	    dsn_split(&fp->dp, "can't happen", STR(fp->buffer));
    172 	    (void) DSN_ASSIGN(&fp->dsn, DSN_STATUS(fp->dp.dsn),
    173 			      (result[0] == '4' ? "delayed" :
    174 			       result[0] == '5' ? "failed" :
    175 			       dsn->action),
    176 			      fp->dp.text, dsn->dtype, dsn->dtext,
    177 			      dsn->mtype, dsn->mname);
    178 	    return (&fp->dsn);
    179 	}
    180     }
    181     return (0);
    182 }
    183 
    184 /* dsn_filter_free - destroy delivery status filter */
    185 
    186 void    dsn_filter_free(DSN_FILTER *fp)
    187 {
    188     static const char myname[] = "dsn_filter_free";
    189 
    190     if (msg_verbose)
    191 	msg_info("%s: %s", myname, fp->maps->title);
    192 
    193     maps_free(fp->maps);
    194     vstring_free(fp->buffer);
    195     myfree((void *) fp);
    196 }
    197