xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/dsn_buf.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1*e89934bbSchristos /*	$NetBSD: dsn_buf.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
241fbaed0Stron 
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /*	dsn_buf 3
641fbaed0Stron /* SUMMARY
741fbaed0Stron /*	delivery status buffer
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /*	#include <dsn_buf.h>
1041fbaed0Stron /*
1141fbaed0Stron /*	typedef struct {
1241fbaed0Stron /* .in +4
1341fbaed0Stron /*		/* Convenience member */
1441fbaed0Stron /*		DSN	dsn;		/* light-weight, dsn(3) */
1541fbaed0Stron /*		/* Formal members... */
1641fbaed0Stron /*		VSTRING *status;	/* RFC 3463 */
1741fbaed0Stron /*		VSTRING *action;	/* RFC 3464 */
1841fbaed0Stron /*		VSTRING	*mtype;		/* dns */
1941fbaed0Stron /*		VSTRING	*mname;		/* host or domain */
2041fbaed0Stron /*		VSTRING	*dtype;		/* smtp, x-unix */
2141fbaed0Stron /*		VSTRING *dtext;		/* RFC 2821, sysexits.h */
2241fbaed0Stron /*		/* Informal members... */
2341fbaed0Stron /*		VSTRING	*reason;	/* informal text */
2441fbaed0Stron /* .in -4
2541fbaed0Stron /*	} DSN_BUF;
2641fbaed0Stron /*
2741fbaed0Stron /*	DSN_BUF	*dsb_create(void)
2841fbaed0Stron /*
2941fbaed0Stron /*	DSN_BUF	*dsb_update(dsb, status, action, mtype, mname, dtype,
3041fbaed0Stron /*				dtext, reason_fmt, ...)
3141fbaed0Stron /*	DSN_BUF	*dsb;
3241fbaed0Stron /*	const char *status;
3341fbaed0Stron /*	const char *action;
3441fbaed0Stron /*	const char *mtype;
3541fbaed0Stron /*	const char *mname;
3641fbaed0Stron /*	const char *dtype;
3741fbaed0Stron /*	const char *dtext;
3841fbaed0Stron /*	const char *reason_fmt;
3941fbaed0Stron /*
4041fbaed0Stron /*	DSN_BUF	*dsb_simple(dsb, status, reason_fmt, ...)
4141fbaed0Stron /*	DSN_BUF	*dsb;
4241fbaed0Stron /*	const char *status;
4341fbaed0Stron /*	const char *reason_fmt;
4441fbaed0Stron /*
4541fbaed0Stron /*	DSN_BUF	*dsb_unix(dsb, status, dtext, reason_fmt, ...)
4641fbaed0Stron /*	DSN_BUF	*dsb;
4741fbaed0Stron /*	const char *status;
4841fbaed0Stron /*	const char *reason_fmt;
4941fbaed0Stron /*
5041fbaed0Stron /*	DSN_BUF	*dsb_formal(dsb, status, action, mtype, mname, dtype,
5141fbaed0Stron /*				dtext)
5241fbaed0Stron /*	DSN_BUF	*dsb;
5341fbaed0Stron /*	const char *status;
5441fbaed0Stron /*	const char *action;
5541fbaed0Stron /*	const char *mtype;
5641fbaed0Stron /*	const char *mname;
5741fbaed0Stron /*	const char *dtype;
5841fbaed0Stron /*	const char *dtext;
5941fbaed0Stron /*
6041fbaed0Stron /*	DSN_BUF	*dsb_status(dsb, status)
6141fbaed0Stron /*	DSN_BUF	*dsb;
6241fbaed0Stron /*	const char *status;
6341fbaed0Stron /*
6441fbaed0Stron /*	void	dsb_reset(dsb)
6541fbaed0Stron /*	DSN_BUF	*dsb;
6641fbaed0Stron /*
6741fbaed0Stron /*	void	dsb_free(dsb)
6841fbaed0Stron /*	DSN_BUF	*dsb;
6941fbaed0Stron /*
7041fbaed0Stron /*	DSN	*DSN_FROM_DSN_BUF(dsb)
7141fbaed0Stron /*	DSN_BUF	*dsb;
7241fbaed0Stron /* DESCRIPTION
7341fbaed0Stron /*	This module implements a simple to update delivery status
7441fbaed0Stron /*	buffer for Postfix-internal use. Typically it is filled in
7541fbaed0Stron /*	the course of delivery attempt, and then formatted into a
7641fbaed0Stron /*	DSN structure for external notification.
7741fbaed0Stron /*
7841fbaed0Stron /*	dsb_create() creates initialized storage for formal RFC 3464
7941fbaed0Stron /*	attributes, and human-readable informal text.
8041fbaed0Stron /*
8141fbaed0Stron /*	dsb_update() updates all fields.
8241fbaed0Stron /*
8341fbaed0Stron /*	dsb_simple() updates the status and informal text, and resets all
8441fbaed0Stron /*	other fields to defaults.
8541fbaed0Stron /*
8641fbaed0Stron /*	dsb_unix() updates the status, diagnostic code, diagnostic
8741fbaed0Stron /*	text, and informal text, sets the diagnostic type to UNIX,
8841fbaed0Stron /*	and resets all other fields to defaults.
8941fbaed0Stron /*
9041fbaed0Stron /*	dsb_formal() updates all fields except the informal text.
9141fbaed0Stron /*
9241fbaed0Stron /*	dsb_status() updates the status field, and resets all
9341fbaed0Stron /*	formal fields to defaults.
9441fbaed0Stron /*
9541fbaed0Stron /*	dsb_reset() resets all fields in a DSN_BUF structure without
9641fbaed0Stron /*	deallocating memory.
9741fbaed0Stron /*
9841fbaed0Stron /*	dsb_free() recycles the storage that was allocated by
9941fbaed0Stron /*	dsb_create(), and so on.
10041fbaed0Stron /*
10141fbaed0Stron /*	DSN_FROM_DSN_BUF() populates the DSN member with a shallow
10241fbaed0Stron /*	copy of the contents of the formal and informal fields, and
10341fbaed0Stron /*	returns a pointer to the DSN member. This is typically used
10441fbaed0Stron /*	for external reporting.
10541fbaed0Stron /*
10641fbaed0Stron /*	Arguments:
10741fbaed0Stron /* .IP dsb
10841fbaed0Stron /*	Delivery status buffer.
10941fbaed0Stron /* .IP status
11041fbaed0Stron /*	RFC 3463 "enhanced" status code.
11141fbaed0Stron /* .IP action
11241fbaed0Stron /*	RFC 3464 action code; specify DSB_DEF_ACTION to derive the
11341fbaed0Stron /*	action from the status value. The only values that really
11441fbaed0Stron /*	matter here are "expanded" and "relayed"; all other values
11541fbaed0Stron /*	are already implied by the context.
11641fbaed0Stron /* .IP mtype
11741fbaed0Stron /*	The remote MTA type.
11841fbaed0Stron /*	The only valid type is DSB_MTYPE_DNS.  The macro DSB_SKIP_RMTA
11941fbaed0Stron /*	conveniently expands into a null argument list for the
12041fbaed0Stron /*	remote MTA type and name.
12141fbaed0Stron /* .IP mname
12241fbaed0Stron /*	Remote MTA name.
12341fbaed0Stron /* .IP dtype
12441fbaed0Stron /*	The reply type.
12541fbaed0Stron /*	DSB_DTYPE_SMTP or DSB_DTYPE_UNIX.  The macro DSB_SKIP_REPLY
12641fbaed0Stron /*	conveniently expands into a null argument list for the reply
12741fbaed0Stron /*	type and text.
12841fbaed0Stron /* .IP dtext
12941fbaed0Stron /*	The reply text. The reply text is reset when dtype is
13041fbaed0Stron /*	DSB_SKIP_REPLY.
13141fbaed0Stron /* .IP reason_fmt
13241fbaed0Stron /*	The informal reason format.
13341fbaed0Stron /* SEE ALSO
13441fbaed0Stron /*	msg(3) diagnostics interface
13541fbaed0Stron /* DIAGNOSTICS
13641fbaed0Stron /*	Fatal: out of memory.
13741fbaed0Stron /* LICENSE
13841fbaed0Stron /* .ad
13941fbaed0Stron /* .fi
14041fbaed0Stron /*	The Secure Mailer license must be distributed with this software.
14141fbaed0Stron /* AUTHOR(S)
14241fbaed0Stron /*	Wietse Venema
14341fbaed0Stron /*	IBM T.J. Watson Research
14441fbaed0Stron /*	P.O. Box 704
14541fbaed0Stron /*	Yorktown Heights, NY 10598, USA
14641fbaed0Stron /*--*/
14741fbaed0Stron 
14841fbaed0Stron /* System library. */
14941fbaed0Stron 
15041fbaed0Stron #include <sys_defs.h>
15141fbaed0Stron #include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
15241fbaed0Stron #include <stdarg.h>
15341fbaed0Stron #include <string.h>
15441fbaed0Stron 
15541fbaed0Stron /* Utility library. */
15641fbaed0Stron 
15741fbaed0Stron #include <msg.h>
15841fbaed0Stron #include <mymalloc.h>
15941fbaed0Stron #include <vstring.h>
16041fbaed0Stron 
16141fbaed0Stron /* Global library. */
16241fbaed0Stron 
16341fbaed0Stron #include <dsn_buf.h>
16441fbaed0Stron 
16541fbaed0Stron /* Application-specific. */
16641fbaed0Stron 
16741fbaed0Stron #define STR(x)	vstring_str(x)
16841fbaed0Stron 
16941fbaed0Stron /* dsb_create - create delivery status buffer */
17041fbaed0Stron 
dsb_create(void)17141fbaed0Stron DSN_BUF *dsb_create(void)
17241fbaed0Stron {
17341fbaed0Stron     DSN_BUF *dsb;
17441fbaed0Stron 
17541fbaed0Stron     /*
17641fbaed0Stron      * Some fields aren't needed until we want to report an error.
17741fbaed0Stron      */
17841fbaed0Stron     dsb = (DSN_BUF *) mymalloc(sizeof(*dsb));
17941fbaed0Stron     dsb->status = vstring_alloc(10);
18041fbaed0Stron     dsb->action = vstring_alloc(10);
18141fbaed0Stron     dsb->mtype = vstring_alloc(10);
18241fbaed0Stron     dsb->mname = vstring_alloc(100);
18341fbaed0Stron     dsb->dtype = vstring_alloc(10);
18441fbaed0Stron     dsb->dtext = vstring_alloc(100);
18541fbaed0Stron     dsb->reason = vstring_alloc(100);
18641fbaed0Stron 
18741fbaed0Stron     return (dsb);
18841fbaed0Stron }
18941fbaed0Stron 
19041fbaed0Stron /* dsb_free - destroy storage */
19141fbaed0Stron 
dsb_free(DSN_BUF * dsb)19241fbaed0Stron void    dsb_free(DSN_BUF *dsb)
19341fbaed0Stron {
19441fbaed0Stron     vstring_free(dsb->status);
19541fbaed0Stron     vstring_free(dsb->action);
19641fbaed0Stron     vstring_free(dsb->mtype);
19741fbaed0Stron     vstring_free(dsb->mname);
19841fbaed0Stron     vstring_free(dsb->dtype);
19941fbaed0Stron     vstring_free(dsb->dtext);
20041fbaed0Stron     vstring_free(dsb->reason);
201e262b48eSchristos     myfree((void *) dsb);
20241fbaed0Stron }
20341fbaed0Stron 
20441fbaed0Stron  /*
20541fbaed0Stron   * Initial versions of this code represented unavailable inputs with null
20641fbaed0Stron   * pointers, which produced fragile and hard to maintain code. The current
20741fbaed0Stron   * code uses empty strings instead of null pointers.
20841fbaed0Stron   *
20941fbaed0Stron   * For safety we keep the test for null pointers in input. It's cheap.
21041fbaed0Stron   */
21141fbaed0Stron #define DSB_TRUNCATE(s) \
21241fbaed0Stron     do { VSTRING_RESET(s); VSTRING_TERMINATE(s); } while (0)
21341fbaed0Stron 
21441fbaed0Stron #define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0)
21541fbaed0Stron 
21641fbaed0Stron #define DSB_ACTION(dsb, stat, act) \
21741fbaed0Stron     vstring_strcpy((dsb)->action, !NULL_OR_EMPTY(act) ? (act) : "")
21841fbaed0Stron 
21941fbaed0Stron #define DSB_MTA(dsb, type, name) do { \
22041fbaed0Stron     if (NULL_OR_EMPTY(type) || NULL_OR_EMPTY(name)) { \
22141fbaed0Stron 	DSB_TRUNCATE((dsb)->mtype); \
22241fbaed0Stron 	DSB_TRUNCATE((dsb)->mname); \
22341fbaed0Stron     } else { \
22441fbaed0Stron 	vstring_strcpy((dsb)->mtype, (type)); \
22541fbaed0Stron 	vstring_strcpy((dsb)->mname, (name)); \
22641fbaed0Stron     } \
22741fbaed0Stron } while (0)
22841fbaed0Stron 
22941fbaed0Stron #define DSB_DIAG(dsb, type, text) do { \
23041fbaed0Stron     if (NULL_OR_EMPTY(type) || NULL_OR_EMPTY(text)) { \
23141fbaed0Stron 	DSB_TRUNCATE((dsb)->dtype); \
23241fbaed0Stron 	DSB_TRUNCATE((dsb)->dtext); \
23341fbaed0Stron     } else { \
23441fbaed0Stron 	vstring_strcpy((dsb)->dtype, (type)); \
23541fbaed0Stron 	vstring_strcpy((dsb)->dtext, (text)); \
23641fbaed0Stron     } \
23741fbaed0Stron } while (0)
23841fbaed0Stron 
23941fbaed0Stron /* dsb_update - update formal attributes and informal text */
24041fbaed0Stron 
dsb_update(DSN_BUF * dsb,const char * status,const char * action,const char * mtype,const char * mname,const char * dtype,const char * dtext,const char * format,...)24141fbaed0Stron DSN_BUF *dsb_update(DSN_BUF *dsb, const char *status, const char *action,
24241fbaed0Stron 		            const char *mtype, const char *mname,
24341fbaed0Stron 		            const char *dtype, const char *dtext,
24441fbaed0Stron 		            const char *format,...)
24541fbaed0Stron {
24641fbaed0Stron     va_list ap;
24741fbaed0Stron 
24841fbaed0Stron     vstring_strcpy(dsb->status, status);
24941fbaed0Stron     DSB_ACTION(dsb, status, action);
25041fbaed0Stron     DSB_MTA(dsb, mtype, mname);
25141fbaed0Stron     DSB_DIAG(dsb, dtype, dtext);
25241fbaed0Stron     va_start(ap, format);
25341fbaed0Stron     vstring_vsprintf(dsb->reason, format, ap);
25441fbaed0Stron     va_end(ap);
25541fbaed0Stron 
25641fbaed0Stron     return (dsb);
25741fbaed0Stron }
25841fbaed0Stron 
25916d67a18Stron /* vdsb_simple - update status and informal text, va_list form */
26041fbaed0Stron 
vdsb_simple(DSN_BUF * dsb,const char * status,const char * format,va_list ap)26116d67a18Stron DSN_BUF *vdsb_simple(DSN_BUF *dsb, const char *status, const char *format,
26216d67a18Stron 		             va_list ap)
26341fbaed0Stron {
26441fbaed0Stron     vstring_strcpy(dsb->status, status);
26541fbaed0Stron     DSB_TRUNCATE(dsb->action);
26641fbaed0Stron     DSB_TRUNCATE(dsb->mtype);
26741fbaed0Stron     DSB_TRUNCATE(dsb->mname);
26841fbaed0Stron     DSB_TRUNCATE(dsb->dtype);
26941fbaed0Stron     DSB_TRUNCATE(dsb->dtext);
27041fbaed0Stron     vstring_vsprintf(dsb->reason, format, ap);
27141fbaed0Stron 
27241fbaed0Stron     return (dsb);
27341fbaed0Stron }
27441fbaed0Stron 
27516d67a18Stron /* dsb_simple - update status and informal text */
27616d67a18Stron 
dsb_simple(DSN_BUF * dsb,const char * status,const char * format,...)27716d67a18Stron DSN_BUF *dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
27816d67a18Stron {
27916d67a18Stron     va_list ap;
28016d67a18Stron 
28116d67a18Stron     va_start(ap, format);
28216d67a18Stron     (void) vdsb_simple(dsb, status, format, ap);
28316d67a18Stron     va_end(ap);
28416d67a18Stron     return (dsb);
28516d67a18Stron }
28616d67a18Stron 
28741fbaed0Stron /* dsb_unix - update status, UNIX diagnostic and informal text */
28841fbaed0Stron 
dsb_unix(DSN_BUF * dsb,const char * status,const char * dtext,const char * format,...)28941fbaed0Stron DSN_BUF *dsb_unix(DSN_BUF *dsb, const char *status,
29041fbaed0Stron 		          const char *dtext, const char *format,...)
29141fbaed0Stron {
29241fbaed0Stron     va_list ap;
29341fbaed0Stron 
29441fbaed0Stron     vstring_strcpy(dsb->status, status);
29541fbaed0Stron     DSB_TRUNCATE(dsb->action);
29641fbaed0Stron     DSB_TRUNCATE(dsb->mtype);
29741fbaed0Stron     DSB_TRUNCATE(dsb->mname);
29841fbaed0Stron     vstring_strcpy(dsb->dtype, DSB_DTYPE_UNIX);
29941fbaed0Stron     vstring_strcpy(dsb->dtext, dtext);
30041fbaed0Stron     va_start(ap, format);
30141fbaed0Stron     vstring_vsprintf(dsb->reason, format, ap);
30241fbaed0Stron     va_end(ap);
30341fbaed0Stron 
30441fbaed0Stron     return (dsb);
30541fbaed0Stron }
30641fbaed0Stron 
30741fbaed0Stron /* dsb_formal - update the formal fields */
30841fbaed0Stron 
dsb_formal(DSN_BUF * dsb,const char * status,const char * action,const char * mtype,const char * mname,const char * dtype,const char * dtext)30941fbaed0Stron DSN_BUF *dsb_formal(DSN_BUF *dsb, const char *status, const char *action,
31041fbaed0Stron 		            const char *mtype, const char *mname,
31141fbaed0Stron 		            const char *dtype, const char *dtext)
31241fbaed0Stron {
31341fbaed0Stron     vstring_strcpy(dsb->status, status);
31441fbaed0Stron     DSB_ACTION(dsb, status, action);
31541fbaed0Stron     DSB_MTA(dsb, mtype, mname);
31641fbaed0Stron     DSB_DIAG(dsb, dtype, dtext);
31741fbaed0Stron     return (dsb);
31841fbaed0Stron }
31941fbaed0Stron 
32041fbaed0Stron /* dsb_status - update the status, reset other formal fields */
32141fbaed0Stron 
dsb_status(DSN_BUF * dsb,const char * status)32241fbaed0Stron DSN_BUF *dsb_status(DSN_BUF *dsb, const char *status)
32341fbaed0Stron {
32441fbaed0Stron     vstring_strcpy(dsb->status, status);
32541fbaed0Stron     DSB_TRUNCATE(dsb->action);
32641fbaed0Stron     DSB_TRUNCATE(dsb->mtype);
32741fbaed0Stron     DSB_TRUNCATE(dsb->mname);
32841fbaed0Stron     DSB_TRUNCATE(dsb->dtype);
32941fbaed0Stron     DSB_TRUNCATE(dsb->dtext);
33041fbaed0Stron     return (dsb);
33141fbaed0Stron }
33241fbaed0Stron 
33341fbaed0Stron /* dsb_reset - reset all fields */
33441fbaed0Stron 
dsb_reset(DSN_BUF * dsb)33541fbaed0Stron void    dsb_reset(DSN_BUF *dsb)
33641fbaed0Stron {
33741fbaed0Stron     DSB_TRUNCATE(dsb->status);
33841fbaed0Stron     DSB_TRUNCATE(dsb->action);
33941fbaed0Stron     DSB_TRUNCATE(dsb->mtype);
34041fbaed0Stron     DSB_TRUNCATE(dsb->mname);
34141fbaed0Stron     DSB_TRUNCATE(dsb->dtype);
34241fbaed0Stron     DSB_TRUNCATE(dsb->dtext);
34341fbaed0Stron     DSB_TRUNCATE(dsb->reason);
34441fbaed0Stron }
345