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
dsn_filter_create(const char * title,const char * map_names)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
dsn_filter_lookup(DSN_FILTER * fp,DSN * dsn)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
dsn_filter_free(DSN_FILTER * fp)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