Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / dsn_buf.c
blobeac2ed6cb5abb8ea1df880e3d90107f89577a21a
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* dsn_buf 3
6 /* SUMMARY
7 /* delivery status buffer
8 /* SYNOPSIS
9 /* #include <dsn_buf.h>
11 /* typedef struct {
12 /* .in +4
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 */
24 /* .in -4
25 /* } DSN_BUF;
27 /* DSN_BUF *dsb_create(void)
29 /* DSN_BUF *dsb_update(dsb, status, action, mtype, mname, dtype,
30 /* dtext, reason_fmt, ...)
31 /* DSN_BUF *dsb;
32 /* const char *status;
33 /* const char *action;
34 /* const char *mtype;
35 /* const char *mname;
36 /* const char *dtype;
37 /* const char *dtext;
38 /* const char *reason_fmt;
40 /* DSN_BUF *dsb_simple(dsb, status, reason_fmt, ...)
41 /* DSN_BUF *dsb;
42 /* const char *status;
43 /* const char *reason_fmt;
45 /* DSN_BUF *dsb_unix(dsb, status, dtext, reason_fmt, ...)
46 /* DSN_BUF *dsb;
47 /* const char *status;
48 /* const char *reason_fmt;
50 /* DSN_BUF *dsb_formal(dsb, status, action, mtype, mname, dtype,
51 /* dtext)
52 /* DSN_BUF *dsb;
53 /* const char *status;
54 /* const char *action;
55 /* const char *mtype;
56 /* const char *mname;
57 /* const char *dtype;
58 /* const char *dtext;
60 /* DSN_BUF *dsb_status(dsb, status)
61 /* DSN_BUF *dsb;
62 /* const char *status;
64 /* void dsb_reset(dsb)
65 /* DSN_BUF *dsb;
67 /* void dsb_free(dsb)
68 /* DSN_BUF *dsb;
70 /* DSN *DSN_FROM_DSN_BUF(dsb)
71 /* DSN_BUF *dsb;
72 /* DESCRIPTION
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.
106 /* Arguments:
107 /* .IP dsb
108 /* Delivery status buffer.
109 /* .IP status
110 /* RFC 3463 "enhanced" status code.
111 /* .IP action
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.
116 /* .IP mtype
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.
121 /* .IP mname
122 /* Remote MTA name.
123 /* .IP dtype
124 /* The reply type.
125 /* DSB_DTYPE_SMTP or DSB_DTYPE_UNIX. The macro DSB_SKIP_REPLY
126 /* conveniently expands into a null argument list for the reply
127 /* type and text.
128 /* .IP dtext
129 /* The reply text. The reply text is reset when dtype is
130 /* DSB_SKIP_REPLY.
131 /* .IP reason_fmt
132 /* The informal reason format.
133 /* SEE ALSO
134 /* msg(3) diagnostics interface
135 /* DIAGNOSTICS
136 /* Fatal: out of memory.
137 /* LICENSE
138 /* .ad
139 /* .fi
140 /* The Secure Mailer license must be distributed with this software.
141 /* AUTHOR(S)
142 /* Wietse Venema
143 /* IBM T.J. Watson Research
144 /* P.O. Box 704
145 /* Yorktown Heights, NY 10598, USA
146 /*--*/
148 /* System library. */
150 #include <sys_defs.h>
151 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */
152 #include <stdarg.h>
153 #include <string.h>
155 /* Utility library. */
157 #include <msg.h>
158 #include <mymalloc.h>
159 #include <vstring.h>
161 /* Global library. */
163 #include <dsn_buf.h>
165 /* Application-specific. */
167 #define STR(x) vstring_str(x)
169 /* dsb_create - create delivery status buffer */
171 DSN_BUF *dsb_create(void)
173 DSN_BUF *dsb;
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);
187 return (dsb);
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); \
223 } else { \
224 vstring_strcpy((dsb)->mtype, (type)); \
225 vstring_strcpy((dsb)->mname, (name)); \
227 } while (0)
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); \
233 } else { \
234 vstring_strcpy((dsb)->dtype, (type)); \
235 vstring_strcpy((dsb)->dtext, (text)); \
237 } while (0)
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,...)
246 va_list ap;
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);
254 va_end(ap);
256 return (dsb);
259 /* dsb_simple - update status and informal text */
261 DSN_BUF *dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
263 va_list ap;
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);
273 va_end(ap);
275 return (dsb);
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,...)
283 va_list ap;
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);
293 va_end(ap);
295 return (dsb);
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);
308 return (dsb);
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);
321 return (dsb);
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);