7 /* delivery status buffer
9 /* #include <dsn_buf.h>
13 /* /* Convenience member */
14 /* DSN dsn; /* light-weight, dsn(3) */
15 /* /* Formal members... */
16 /* VSTRING *status; /* RFC 3463 */
17 /* VSTRING *action; /* RFC 3464 */
18 /* VSTRING *mtype; /* dns */
19 /* VSTRING *mname; /* host or domain */
20 /* VSTRING *dtype; /* smtp, x-unix */
21 /* VSTRING *dtext; /* RFC 2821, sysexits.h */
22 /* /* Informal members... */
23 /* VSTRING *reason; /* informal text */
27 /* DSN_BUF *dsb_create(void)
29 /* DSN_BUF *dsb_update(dsb, status, action, mtype, mname, dtype,
30 /* dtext, reason_fmt, ...)
32 /* const char *status;
33 /* const char *action;
38 /* const char *reason_fmt;
40 /* DSN_BUF *dsb_simple(dsb, status, reason_fmt, ...)
42 /* const char *status;
43 /* const char *reason_fmt;
45 /* DSN_BUF *dsb_unix(dsb, status, dtext, reason_fmt, ...)
47 /* const char *status;
48 /* const char *reason_fmt;
50 /* DSN_BUF *dsb_formal(dsb, status, action, mtype, mname, dtype,
53 /* const char *status;
54 /* const char *action;
60 /* DSN_BUF *dsb_status(dsb, status)
62 /* const char *status;
64 /* void dsb_reset(dsb)
70 /* DSN *DSN_FROM_DSN_BUF(dsb)
73 /* This module implements a simple to update delivery status
74 /* buffer for Postfix-internal use. Typically it is filled in
75 /* the course of delivery attempt, and then formatted into a
76 /* DSN structure for external notification.
78 /* dsb_create() creates initialized storage for formal RFC 3464
79 /* attributes, and human-readable informal text.
81 /* dsb_update() updates all fields.
83 /* dsb_simple() updates the status and informal text, and resets all
84 /* other fields to defaults.
86 /* dsb_unix() updates the status, diagnostic code, diagnostic
87 /* text, and informal text, sets the diagnostic type to UNIX,
88 /* and resets all other fields to defaults.
90 /* dsb_formal() updates all fields except the informal text.
92 /* dsb_status() updates the status field, and resets all
93 /* formal fields to defaults.
95 /* dsb_reset() resets all fields in a DSN_BUF structure without
96 /* deallocating memory.
98 /* dsb_free() recycles the storage that was allocated by
99 /* dsb_create(), and so on.
101 /* DSN_FROM_DSN_BUF() populates the DSN member with a shallow
102 /* copy of the contents of the formal and informal fields, and
103 /* returns a pointer to the DSN member. This is typically used
104 /* for external reporting.
108 /* Delivery status buffer.
110 /* RFC 3463 "enhanced" status code.
112 /* RFC 3464 action code; specify DSB_DEF_ACTION to derive the
113 /* action from the status value. The only values that really
114 /* matter here are "expanded" and "relayed"; all other values
115 /* are already implied by the context.
117 /* The remote MTA type.
118 /* The only valid type is DSB_MTYPE_DNS. The macro DSB_SKIP_RMTA
119 /* conveniently expands into a null argument list for the
120 /* remote MTA type and name.
125 /* DSB_DTYPE_SMTP or DSB_DTYPE_UNIX. The macro DSB_SKIP_REPLY
126 /* conveniently expands into a null argument list for the reply
129 /* The reply text. The reply text is reset when dtype is
132 /* The informal reason format.
134 /* msg(3) diagnostics interface
136 /* Fatal: out of memory.
140 /* The Secure Mailer license must be distributed with this software.
143 /* IBM T.J. Watson Research
145 /* Yorktown Heights, NY 10598, USA
148 /* System library. */
150 #include <sys_defs.h>
151 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */
155 /* Utility library. */
158 #include <mymalloc.h>
161 /* Global library. */
165 /* Application-specific. */
167 #define STR(x) vstring_str(x)
169 /* dsb_create - create delivery status buffer */
171 DSN_BUF
*dsb_create(void)
176 * Some fields aren't needed until we want to report an error.
178 dsb
= (DSN_BUF
*) mymalloc(sizeof(*dsb
));
179 dsb
->status
= vstring_alloc(10);
180 dsb
->action
= vstring_alloc(10);
181 dsb
->mtype
= vstring_alloc(10);
182 dsb
->mname
= vstring_alloc(100);
183 dsb
->dtype
= vstring_alloc(10);
184 dsb
->dtext
= vstring_alloc(100);
185 dsb
->reason
= vstring_alloc(100);
190 /* dsb_free - destroy storage */
192 void dsb_free(DSN_BUF
*dsb
)
194 vstring_free(dsb
->status
);
195 vstring_free(dsb
->action
);
196 vstring_free(dsb
->mtype
);
197 vstring_free(dsb
->mname
);
198 vstring_free(dsb
->dtype
);
199 vstring_free(dsb
->dtext
);
200 vstring_free(dsb
->reason
);
201 myfree((char *) dsb
);
205 * Initial versions of this code represented unavailable inputs with null
206 * pointers, which produced fragile and hard to maintain code. The current
207 * code uses empty strings instead of null pointers.
209 * For safety we keep the test for null pointers in input. It's cheap.
211 #define DSB_TRUNCATE(s) \
212 do { VSTRING_RESET(s); VSTRING_TERMINATE(s); } while (0)
214 #define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0)
216 #define DSB_ACTION(dsb, stat, act) \
217 vstring_strcpy((dsb)->action, !NULL_OR_EMPTY(act) ? (act) : "")
219 #define DSB_MTA(dsb, type, name) do { \
220 if (NULL_OR_EMPTY(type) || NULL_OR_EMPTY(name)) { \
221 DSB_TRUNCATE((dsb)->mtype); \
222 DSB_TRUNCATE((dsb)->mname); \
224 vstring_strcpy((dsb)->mtype, (type)); \
225 vstring_strcpy((dsb)->mname, (name)); \
229 #define DSB_DIAG(dsb, type, text) do { \
230 if (NULL_OR_EMPTY(type) || NULL_OR_EMPTY(text)) { \
231 DSB_TRUNCATE((dsb)->dtype); \
232 DSB_TRUNCATE((dsb)->dtext); \
234 vstring_strcpy((dsb)->dtype, (type)); \
235 vstring_strcpy((dsb)->dtext, (text)); \
239 /* dsb_update - update formal attributes and informal text */
241 DSN_BUF
*dsb_update(DSN_BUF
*dsb
, const char *status
, const char *action
,
242 const char *mtype
, const char *mname
,
243 const char *dtype
, const char *dtext
,
244 const char *format
,...)
248 vstring_strcpy(dsb
->status
, status
);
249 DSB_ACTION(dsb
, status
, action
);
250 DSB_MTA(dsb
, mtype
, mname
);
251 DSB_DIAG(dsb
, dtype
, dtext
);
252 va_start(ap
, format
);
253 vstring_vsprintf(dsb
->reason
, format
, ap
);
259 /* dsb_simple - update status and informal text */
261 DSN_BUF
*dsb_simple(DSN_BUF
*dsb
, const char *status
, const char *format
,...)
265 vstring_strcpy(dsb
->status
, status
);
266 DSB_TRUNCATE(dsb
->action
);
267 DSB_TRUNCATE(dsb
->mtype
);
268 DSB_TRUNCATE(dsb
->mname
);
269 DSB_TRUNCATE(dsb
->dtype
);
270 DSB_TRUNCATE(dsb
->dtext
);
271 va_start(ap
, format
);
272 vstring_vsprintf(dsb
->reason
, format
, ap
);
278 /* dsb_unix - update status, UNIX diagnostic and informal text */
280 DSN_BUF
*dsb_unix(DSN_BUF
*dsb
, const char *status
,
281 const char *dtext
, const char *format
,...)
285 vstring_strcpy(dsb
->status
, status
);
286 DSB_TRUNCATE(dsb
->action
);
287 DSB_TRUNCATE(dsb
->mtype
);
288 DSB_TRUNCATE(dsb
->mname
);
289 vstring_strcpy(dsb
->dtype
, DSB_DTYPE_UNIX
);
290 vstring_strcpy(dsb
->dtext
, dtext
);
291 va_start(ap
, format
);
292 vstring_vsprintf(dsb
->reason
, format
, ap
);
298 /* dsb_formal - update the formal fields */
300 DSN_BUF
*dsb_formal(DSN_BUF
*dsb
, const char *status
, const char *action
,
301 const char *mtype
, const char *mname
,
302 const char *dtype
, const char *dtext
)
304 vstring_strcpy(dsb
->status
, status
);
305 DSB_ACTION(dsb
, status
, action
);
306 DSB_MTA(dsb
, mtype
, mname
);
307 DSB_DIAG(dsb
, dtype
, dtext
);
311 /* dsb_status - update the status, reset other formal fields */
313 DSN_BUF
*dsb_status(DSN_BUF
*dsb
, const char *status
)
315 vstring_strcpy(dsb
->status
, status
);
316 DSB_TRUNCATE(dsb
->action
);
317 DSB_TRUNCATE(dsb
->mtype
);
318 DSB_TRUNCATE(dsb
->mname
);
319 DSB_TRUNCATE(dsb
->dtype
);
320 DSB_TRUNCATE(dsb
->dtext
);
324 /* dsb_reset - reset all fields */
326 void dsb_reset(DSN_BUF
*dsb
)
328 DSB_TRUNCATE(dsb
->status
);
329 DSB_TRUNCATE(dsb
->action
);
330 DSB_TRUNCATE(dsb
->mtype
);
331 DSB_TRUNCATE(dsb
->mname
);
332 DSB_TRUNCATE(dsb
->dtype
);
333 DSB_TRUNCATE(dsb
->dtext
);
334 DSB_TRUNCATE(dsb
->reason
);