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