xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/attr_print64.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: attr_print64.c,v 1.3 2022/10/08 16:12:50 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	attr_print64 3
6 /* SUMMARY
7 /*	send attributes over byte stream
8 /* SYNOPSIS
9 /*	#include <attr.h>
10 /*
11 /*	int	attr_print64(fp, flags, type, name, ..., ATTR_TYPE_END)
12 /*	VSTREAM	fp;
13 /*	int	flags;
14 /*	int	type;
15 /*	char	*name;
16 /*
17 /*	int	attr_vprint64(fp, flags, ap)
18 /*	VSTREAM	fp;
19 /*	int	flags;
20 /*	va_list	ap;
21 /* DESCRIPTION
22 /*	attr_print64() takes zero or more (name, value) simple attributes
23 /*	and converts its input to a byte stream that can be recovered with
24 /*	attr_scan64(). The stream is not flushed.
25 /*
26 /*	attr_vprint64() provides an alternate interface that is convenient
27 /*	for calling from within variadic functions.
28 /*
29 /*	Attributes are sent in the requested order as specified with the
30 /*	attr_print64() argument list. This routine satisfies the formatting
31 /*	rules as outlined in attr_scan64(3).
32 /*
33 /*	Arguments:
34 /* .IP fp
35 /*	Stream to write the result to.
36 /* .IP flags
37 /*	The bit-wise OR of zero or more of the following.
38 /* .RS
39 /* .IP ATTR_FLAG_MORE
40 /*	After sending the requested attributes, leave the output stream in
41 /*	a state that is usable for more attribute sending operations on
42 /*	the same output attribute list.
43 /*	By default, attr_print64() automatically appends an attribute list
44 /*	terminator when it has sent the last requested attribute.
45 /* .RE
46 /* .IP List of attributes followed by terminator:
47 /* .RS
48 /* .IP "SEND_ATTR_INT(const char *name, int value)"
49 /*	The arguments are an attribute name and an integer.
50 /* .IP "SEND_ATTR_LONG(const char *name, long value)"
51 /*	The arguments are an attribute name and a long integer.
52 /* .IP "SEND_ATTR_STR(const char *name, const char *value)"
53 /*	The arguments are an attribute name and a null-terminated
54 /*	string.
55 /* .IP "SEND_ATTR_DATA(const char *name, ssize_t len, const void *value)"
56 /*	The arguments are an attribute name, an attribute value
57 /*	length, and an attribute value pointer.
58 /* .IP "SEND_ATTR_FUNC(ATTR_PRINT_CUSTOM_FN, const void *value)"
59 /*	The arguments are a function pointer and generic data
60 /*	pointer. The caller-specified function returns whatever the
61 /*	specified attribute printing function returns.
62 /* .IP "SEND_ATTR_HASH(const HTABLE *table)"
63 /* .IP "SEND_ATTR_NAMEVAL(const NVTABLE *table)"
64 /*	The content of the table is sent as a sequence of string-valued
65 /*	attributes with names equal to the table lookup keys.
66 /* .IP ATTR_TYPE_END
67 /*	This terminates the attribute list.
68 /* .RE
69 /* DIAGNOSTICS
70 /*	The result value is 0 in case of success, VSTREAM_EOF in case
71 /*	of trouble.
72 /*
73 /*	Panic: interface violation. All system call errors are fatal.
74 /* SEE ALSO
75 /*	attr_scan64(3) recover attributes from byte stream
76 /* LICENSE
77 /* .ad
78 /* .fi
79 /*	The Secure Mailer license must be distributed with this software.
80 /* AUTHOR(S)
81 /*	Wietse Venema
82 /*	IBM T.J. Watson Research
83 /*	P.O. Box 704
84 /*	Yorktown Heights, NY 10598, USA
85 /*
86 /*	Wietse Venema
87 /*	Google, Inc.
88 /*	111 8th Avenue
89 /*	New York, NY 10011, USA
90 /*--*/
91 
92 /* System library. */
93 
94 #include <sys_defs.h>
95 #include <stdarg.h>
96 #include <string.h>
97 
98 /* Utility library. */
99 
100 #include <msg.h>
101 #include <mymalloc.h>
102 #include <vstream.h>
103 #include <htable.h>
104 #include <base64_code.h>
105 #include <attr.h>
106 
107 #define STR(x)	vstring_str(x)
108 #define LEN(x)	VSTRING_LEN(x)
109 
110 /* attr_print64_str - encode and send attribute information */
111 
attr_print64_str(VSTREAM * fp,const char * str,ssize_t len)112 static void attr_print64_str(VSTREAM *fp, const char *str, ssize_t len)
113 {
114     static VSTRING *base64_buf;
115 
116     if (base64_buf == 0)
117 	base64_buf = vstring_alloc(10);
118 
119     base64_encode(base64_buf, str, len);
120     vstream_fputs(STR(base64_buf), fp);
121 }
122 
attr_print64_num(VSTREAM * fp,unsigned num)123 static void attr_print64_num(VSTREAM *fp, unsigned num)
124 {
125     static VSTRING *plain;
126 
127     if (plain == 0)
128 	plain = vstring_alloc(10);
129 
130     vstring_sprintf(plain, "%u", num);
131     attr_print64_str(fp, STR(plain), LEN(plain));
132 }
133 
attr_print64_long_num(VSTREAM * fp,unsigned long long_num)134 static void attr_print64_long_num(VSTREAM *fp, unsigned long long_num)
135 {
136     static VSTRING *plain;
137 
138     if (plain == 0)
139 	plain = vstring_alloc(10);
140 
141     vstring_sprintf(plain, "%lu", long_num);
142     attr_print64_str(fp, STR(plain), LEN(plain));
143 }
144 
145 /* attr_vprint64 - send attribute list to stream */
146 
attr_vprint64(VSTREAM * fp,int flags,va_list ap)147 int     attr_vprint64(VSTREAM *fp, int flags, va_list ap)
148 {
149     const char *myname = "attr_print64";
150     int     attr_type;
151     char   *attr_name;
152     unsigned int_val;
153     unsigned long long_val;
154     char   *str_val;
155     HTABLE_INFO **ht_info_list;
156     HTABLE_INFO **ht;
157     ssize_t len_val;
158     ATTR_PRINT_CUSTOM_FN print_fn;
159     void   *print_arg;
160 
161     /*
162      * Sanity check.
163      */
164     if (flags & ~ATTR_FLAG_ALL)
165 	msg_panic("%s: bad flags: 0x%x", myname, flags);
166 
167     /*
168      * Iterate over all (type, name, value) triples, and produce output on
169      * the fly.
170      */
171     while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
172 	switch (attr_type) {
173 	case ATTR_TYPE_INT:
174 	    attr_name = va_arg(ap, char *);
175 	    attr_print64_str(fp, attr_name, strlen(attr_name));
176 	    int_val = va_arg(ap, int);
177 	    VSTREAM_PUTC(':', fp);
178 	    attr_print64_num(fp, (unsigned) int_val);
179 	    VSTREAM_PUTC('\n', fp);
180 	    if (msg_verbose)
181 		msg_info("send attr %s = %u", attr_name, int_val);
182 	    break;
183 	case ATTR_TYPE_LONG:
184 	    attr_name = va_arg(ap, char *);
185 	    attr_print64_str(fp, attr_name, strlen(attr_name));
186 	    long_val = va_arg(ap, long);
187 	    VSTREAM_PUTC(':', fp);
188 	    attr_print64_long_num(fp, (unsigned long) long_val);
189 	    VSTREAM_PUTC('\n', fp);
190 	    if (msg_verbose)
191 		msg_info("send attr %s = %lu", attr_name, long_val);
192 	    break;
193 	case ATTR_TYPE_STR:
194 	    attr_name = va_arg(ap, char *);
195 	    attr_print64_str(fp, attr_name, strlen(attr_name));
196 	    str_val = va_arg(ap, char *);
197 	    VSTREAM_PUTC(':', fp);
198 	    attr_print64_str(fp, str_val, strlen(str_val));
199 	    VSTREAM_PUTC('\n', fp);
200 	    if (msg_verbose)
201 		msg_info("send attr %s = %s", attr_name, str_val);
202 	    break;
203 	case ATTR_TYPE_DATA:
204 	    attr_name = va_arg(ap, char *);
205 	    attr_print64_str(fp, attr_name, strlen(attr_name));
206 	    len_val = va_arg(ap, ssize_t);
207 	    str_val = va_arg(ap, char *);
208 	    VSTREAM_PUTC(':', fp);
209 	    attr_print64_str(fp, str_val, len_val);
210 	    VSTREAM_PUTC('\n', fp);
211 	    if (msg_verbose)
212 		msg_info("send attr %s = [data %ld bytes]",
213 			 attr_name, (long) len_val);
214 	    break;
215 	case ATTR_TYPE_FUNC:
216 	    print_fn = va_arg(ap, ATTR_PRINT_CUSTOM_FN);
217 	    print_arg = va_arg(ap, void *);
218 	    print_fn(attr_print64, fp, flags | ATTR_FLAG_MORE, print_arg);
219 	    break;
220 	case ATTR_TYPE_HASH:
221 	    attr_print64_str(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN) - 1);
222 	    VSTREAM_PUTC('\n', fp);
223 	    ht_info_list = htable_list(va_arg(ap, HTABLE *));
224 	    for (ht = ht_info_list; *ht; ht++) {
225 		attr_print64_str(fp, ht[0]->key, strlen(ht[0]->key));
226 		VSTREAM_PUTC(':', fp);
227 		attr_print64_str(fp, ht[0]->value, strlen(ht[0]->value));
228 		VSTREAM_PUTC('\n', fp);
229 		if (msg_verbose)
230 		    msg_info("send attr name %s value %s",
231 			     ht[0]->key, (char *) ht[0]->value);
232 	    }
233 	    myfree((void *) ht_info_list);
234 	    attr_print64_str(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE) - 1);
235 	    VSTREAM_PUTC('\n', fp);
236 	    break;
237 	default:
238 	    msg_panic("%s: unknown type code: %d", myname, attr_type);
239 	}
240     }
241     if ((flags & ATTR_FLAG_MORE) == 0)
242 	VSTREAM_PUTC('\n', fp);
243     return (vstream_ferror(fp));
244 }
245 
attr_print64(VSTREAM * fp,int flags,...)246 int     attr_print64(VSTREAM *fp, int flags,...)
247 {
248     va_list ap;
249     int     ret;
250 
251     va_start(ap, flags);
252     ret = attr_vprint64(fp, flags, ap);
253     va_end(ap);
254     return (ret);
255 }
256 
257 #ifdef TEST
258 
259  /*
260   * Proof of concept test program.  Mirror image of the attr_scan64 test
261   * program.
262   */
263 #include <msg_vstream.h>
264 
main(int unused_argc,char ** argv)265 int     main(int unused_argc, char **argv)
266 {
267     HTABLE *table = htable_create(1);
268 
269     msg_vstream_init(argv[0], VSTREAM_ERR);
270     msg_verbose = 1;
271     htable_enter(table, "foo-name", mystrdup("foo-value"));
272     htable_enter(table, "bar-name", mystrdup("bar-value"));
273     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
274 		 SEND_ATTR_STR("protocol", "test"),
275 		 SEND_ATTR_INT(ATTR_NAME_INT, 4711),
276 		 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L),
277 		 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
278 	       SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
279 		 SEND_ATTR_HASH(table),
280 		 SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L),
281 		 ATTR_TYPE_END);
282     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
283 		 SEND_ATTR_STR("protocol", "test"),
284 		 SEND_ATTR_INT(ATTR_NAME_INT, 4711),
285 		 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L),
286 		 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
287 	       SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
288 		 ATTR_TYPE_END);
289     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
290 		 SEND_ATTR_STR("protocol", "not-test"),
291 		 ATTR_TYPE_END);
292     if (vstream_fflush(VSTREAM_OUT) != 0)
293 	msg_fatal("write error: %m");
294 
295     htable_free(table, myfree);
296     return (0);
297 }
298 
299 #endif
300