Home | History | Annotate | Line # | Download | only in global
      1 /*	$NetBSD: dsn_buf.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	dsn_buf 3
      6 /* SUMMARY
      7 /*	delivery status buffer
      8 /* SYNOPSIS
      9 /*	#include <dsn_buf.h>
     10 /*
     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;
     26 /*
     27 /*	DSN_BUF	*dsb_create(void)
     28 /*
     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;
     39 /*
     40 /*	DSN_BUF	*dsb_simple(dsb, status, reason_fmt, ...)
     41 /*	DSN_BUF	*dsb;
     42 /*	const char *status;
     43 /*	const char *reason_fmt;
     44 /*
     45 /*	DSN_BUF	*dsb_unix(dsb, status, dtext, reason_fmt, ...)
     46 /*	DSN_BUF	*dsb;
     47 /*	const char *status;
     48 /*	const char *reason_fmt;
     49 /*
     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;
     59 /*
     60 /*	DSN_BUF	*dsb_status(dsb, status)
     61 /*	DSN_BUF	*dsb;
     62 /*	const char *status;
     63 /*
     64 /*	void	dsb_reset(dsb)
     65 /*	DSN_BUF	*dsb;
     66 /*
     67 /*	void	dsb_free(dsb)
     68 /*	DSN_BUF	*dsb;
     69 /*
     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.
     77 /*
     78 /*	dsb_create() creates initialized storage for formal RFC 3464
     79 /*	attributes, and human-readable informal text.
     80 /*
     81 /*	dsb_update() updates all fields.
     82 /*
     83 /*	dsb_simple() updates the status and informal text, and resets all
     84 /*	other fields to defaults.
     85 /*
     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.
     89 /*
     90 /*	dsb_formal() updates all fields except the informal text.
     91 /*
     92 /*	dsb_status() updates the status field, and resets all
     93 /*	formal fields to defaults.
     94 /*
     95 /*	dsb_reset() resets all fields in a DSN_BUF structure without
     96 /*	deallocating memory.
     97 /*
     98 /*	dsb_free() recycles the storage that was allocated by
     99 /*	dsb_create(), and so on.
    100 /*
    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.
    105 /*
    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 /*--*/
    147 
    148 /* System library. */
    149 
    150 #include <sys_defs.h>
    151 #include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
    152 #include <stdarg.h>
    153 #include <string.h>
    154 
    155 /* Utility library. */
    156 
    157 #include <msg.h>
    158 #include <mymalloc.h>
    159 #include <vstring.h>
    160 
    161 /* Global library. */
    162 
    163 #include <dsn_buf.h>
    164 
    165 /* Application-specific. */
    166 
    167 #define STR(x)	vstring_str(x)
    168 
    169 /* dsb_create - create delivery status buffer */
    170 
    171 DSN_BUF *dsb_create(void)
    172 {
    173     DSN_BUF *dsb;
    174 
    175     /*
    176      * Some fields aren't needed until we want to report an error.
    177      */
    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);
    186 
    187     return (dsb);
    188 }
    189 
    190 /* dsb_free - destroy storage */
    191 
    192 void    dsb_free(DSN_BUF *dsb)
    193 {
    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((void *) dsb);
    202 }
    203 
    204  /*
    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.
    208   *
    209   * For safety we keep the test for null pointers in input. It's cheap.
    210   */
    211 #define DSB_TRUNCATE(s) \
    212     do { VSTRING_RESET(s); VSTRING_TERMINATE(s); } while (0)
    213 
    214 #define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0)
    215 
    216 #define DSB_ACTION(dsb, stat, act) \
    217     vstring_strcpy((dsb)->action, !NULL_OR_EMPTY(act) ? (act) : "")
    218 
    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)); \
    226     } \
    227 } while (0)
    228 
    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)); \
    236     } \
    237 } while (0)
    238 
    239 /* dsb_update - update formal attributes and informal text */
    240 
    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,...)
    245 {
    246     va_list ap;
    247 
    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);
    255 
    256     return (dsb);
    257 }
    258 
    259 /* vdsb_simple - update status and informal text, va_list form */
    260 
    261 DSN_BUF *vdsb_simple(DSN_BUF *dsb, const char *status, const char *format,
    262 		             va_list ap)
    263 {
    264     vstring_strcpy(dsb->status, status);
    265     DSB_TRUNCATE(dsb->action);
    266     DSB_TRUNCATE(dsb->mtype);
    267     DSB_TRUNCATE(dsb->mname);
    268     DSB_TRUNCATE(dsb->dtype);
    269     DSB_TRUNCATE(dsb->dtext);
    270     vstring_vsprintf(dsb->reason, format, ap);
    271 
    272     return (dsb);
    273 }
    274 
    275 /* dsb_simple - update status and informal text */
    276 
    277 DSN_BUF *dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
    278 {
    279     va_list ap;
    280 
    281     va_start(ap, format);
    282     (void) vdsb_simple(dsb, status, format, ap);
    283     va_end(ap);
    284     return (dsb);
    285 }
    286 
    287 /* dsb_unix - update status, UNIX diagnostic and informal text */
    288 
    289 DSN_BUF *dsb_unix(DSN_BUF *dsb, const char *status,
    290 		          const char *dtext, const char *format,...)
    291 {
    292     va_list ap;
    293 
    294     vstring_strcpy(dsb->status, status);
    295     DSB_TRUNCATE(dsb->action);
    296     DSB_TRUNCATE(dsb->mtype);
    297     DSB_TRUNCATE(dsb->mname);
    298     vstring_strcpy(dsb->dtype, DSB_DTYPE_UNIX);
    299     vstring_strcpy(dsb->dtext, dtext);
    300     va_start(ap, format);
    301     vstring_vsprintf(dsb->reason, format, ap);
    302     va_end(ap);
    303 
    304     return (dsb);
    305 }
    306 
    307 /* dsb_formal - update the formal fields */
    308 
    309 DSN_BUF *dsb_formal(DSN_BUF *dsb, const char *status, const char *action,
    310 		            const char *mtype, const char *mname,
    311 		            const char *dtype, const char *dtext)
    312 {
    313     vstring_strcpy(dsb->status, status);
    314     DSB_ACTION(dsb, status, action);
    315     DSB_MTA(dsb, mtype, mname);
    316     DSB_DIAG(dsb, dtype, dtext);
    317     return (dsb);
    318 }
    319 
    320 /* dsb_status - update the status, reset other formal fields */
    321 
    322 DSN_BUF *dsb_status(DSN_BUF *dsb, const char *status)
    323 {
    324     vstring_strcpy(dsb->status, status);
    325     DSB_TRUNCATE(dsb->action);
    326     DSB_TRUNCATE(dsb->mtype);
    327     DSB_TRUNCATE(dsb->mname);
    328     DSB_TRUNCATE(dsb->dtype);
    329     DSB_TRUNCATE(dsb->dtext);
    330     return (dsb);
    331 }
    332 
    333 /* dsb_reset - reset all fields */
    334 
    335 void    dsb_reset(DSN_BUF *dsb)
    336 {
    337     DSB_TRUNCATE(dsb->status);
    338     DSB_TRUNCATE(dsb->action);
    339     DSB_TRUNCATE(dsb->mtype);
    340     DSB_TRUNCATE(dsb->mname);
    341     DSB_TRUNCATE(dsb->dtype);
    342     DSB_TRUNCATE(dsb->dtext);
    343     DSB_TRUNCATE(dsb->reason);
    344 }
    345