1/*++
2/* NAME
3/*	dsn
4/* SUMMARY
5/*	RFC-compliant delivery status information
6/* SYNOPSIS
7/*	#include <dsn.h>
8/*
9/*	typedef struct {
10/* .in +4
11/*		const char *status;	/* RFC 3463 status */
12/*		const char *action;	/* null or RFC 3464 action */
13/*		const char *reason;	/* human-readable text */
14/*		const char *dtype;	/* null or diagnostic type */
15/*		const char *dtext;	/* null or diagnostic code */
16/*		const char *mtype;	/* null or MTA type */
17/*		const char *mname;	/* null or remote MTA */
18/* .in -4
19/*	} DSN;
20/*
21/*	DSN	*create(status, action, reason, dtype, dtext, mtype, mname)
22/*	const char *status;
23/*	const char *action;
24/*	const char *reason;
25/*	const char *dtype;
26/*	const char *dtext;
27/*	const char *mtype;
28/*	const char *mname;
29/*
30/*	DSN	*DSN_COPY(dsn)
31/*	DSN	*dsn;
32/*
33/*	void	dsn_free(dsn)
34/*	DSN	*dsn;
35/*
36/*	DSN	*DSN_ASSIGN(dsn, status, action, reason, dtype, dtext,
37/*						mtype, mname)
38/*	DSN	*dsn;
39/*	const char *status;
40/*	const char *action;
41/*	const char *reason;
42/*	const char *dtype;
43/*	const char *dtext;
44/*	const char *mtype;
45/*	const char *mname;
46/*
47/*	DSN	*DSN_SIMPLE(dsn, status, action, reason)
48/*	DSN	*dsn;
49/*	const char *status;
50/*	const char *action;
51/*	const char *reason;
52/* DESCRIPTION
53/*	This module maintains delivery error information. For a
54/*	description of structure field members see "Arguments"
55/*	below.  Function-like names spelled in upper case are macros.
56/*	These may evaluate some arguments more than once.
57/*
58/*	dsn_create() creates a DSN structure and copies its arguments.
59/*	The DSN structure should be destroyed with dsn_free().
60/*
61/*	DSN_COPY() creates a deep copy of its argument.
62/*
63/*	dsn_free() destroys a DSN structure and makes its storage
64/*	available for reuse.
65/*
66/*	DSN_ASSIGN() updates a DSN structure and DOES NOT copy
67/*	arguments or free memory.  The result DSN structure must
68/*	NOT be passed to dsn_free(). DSN_ASSIGN() is typically used
69/*	for stack-based short-lived storage.
70/*
71/*	DSN_SIMPLE() takes the minimally required subset of all the
72/*	attributes and sets the rest to empty strings.
73/*	This is a wrapper around the DSN_ASSIGN() macro.
74/*
75/*	Arguments:
76/* .IP reason
77/*	Human-readable text, used for logging purposes, and for
78/*	updating the message-specific \fBbounce\fR or \fIdefer\fR
79/*	logfile.
80/* .IP status
81/*	Enhanced status code as specified in RFC 3463.
82/* .IP action
83/*	DSN_NO_ACTION, empty string, or action as defined in RFC 3464.
84/*	If no action is specified, a default action is chosen.
85/* .IP dtype
86/*	DSN_NO_DTYPE, empty string, or diagnostic code type as
87/*	specified in RFC 3464.
88/* .IP dtext
89/*	DSN_NO_DTEXT, empty string, or diagnostic code as specified
90/*	in RFC 3464.
91/* .IP mtype
92/*	DSN_NO_MTYPE, empty string, DSN_MTYPE_DNS or DSN_MTYPE_UNIX.
93/* .IP mname
94/*	DSN_NO_MNAME, empty string, or remote MTA as specified in
95/*	RFC 3464.
96/* DIAGNOSTICS
97/*	Panic: null or empty status or reason.
98/*	Fatal: out of memory.
99/* LICENSE
100/* .ad
101/* .fi
102/*	The Secure Mailer license must be distributed with this software.
103/* AUTHOR(S)
104/*	Wietse Venema
105/*	IBM T.J. Watson Research
106/*	P.O. Box 704
107/*	Yorktown Heights, NY 10598, USA
108/*--*/
109
110/* System library. */
111
112#include <sys_defs.h>
113
114/* Utility library. */
115
116#include <msg.h>
117#include <mymalloc.h>
118
119/* Global library. */
120
121#include <dsn.h>
122
123/* dsn_create - create DSN structure */
124
125DSN    *dsn_create(const char *status, const char *action, const char *reason,
126		           const char *dtype, const char *dtext,
127		           const char *mtype, const char *mname)
128{
129    const char *myname = "dsn_create";
130    DSN    *dsn;
131
132    dsn = (DSN *) mymalloc(sizeof(*dsn));
133
134    /*
135     * Status and reason must not be empty. Other members may be empty
136     * strings.
137     *
138     * Early implementations represented unavailable information with null
139     * pointers. This resulted in code that was difficult to maintain. We now
140     * use empty strings instead. For safety sake we keep the null pointer
141     * test for input, but we always convert to empty string on output.
142     */
143#define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0)
144
145    if (NULL_OR_EMPTY(status))
146	msg_panic("%s: null dsn status", myname);
147    else
148	dsn->status = mystrdup(status);
149
150    if (NULL_OR_EMPTY(action))
151	dsn->action = mystrdup("");
152    else
153	dsn->action = mystrdup(action);
154
155    if (NULL_OR_EMPTY(reason))
156	msg_panic("%s: null dsn reason", myname);
157    else
158	dsn->reason = mystrdup(reason);
159
160    if (NULL_OR_EMPTY(dtype) || NULL_OR_EMPTY(dtext)) {
161	dsn->dtype = mystrdup("");
162	dsn->dtext = mystrdup("");
163    } else {
164	dsn->dtype = mystrdup(dtype);
165	dsn->dtext = mystrdup(dtext);
166    }
167    if (NULL_OR_EMPTY(mtype) || NULL_OR_EMPTY(mname)) {
168	dsn->mtype = mystrdup("");
169	dsn->mname = mystrdup("");
170    } else {
171	dsn->mtype = mystrdup(mtype);
172	dsn->mname = mystrdup(mname);
173    }
174    return (dsn);
175}
176
177/* dsn_free - destroy DSN structure */
178
179void    dsn_free(DSN *dsn)
180{
181    myfree((char *) dsn->status);
182    myfree((char *) dsn->action);
183    myfree((char *) dsn->reason);
184    myfree((char *) dsn->dtype);
185    myfree((char *) dsn->dtext);
186    myfree((char *) dsn->mtype);
187    myfree((char *) dsn->mname);
188    myfree((char *) dsn);
189}
190