xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/attr_print64.c (revision a7e090f70e491979434963c9a27df4020fe0a18b)
1 /*	$NetBSD: attr_print64.c,v 1.1.1.1 2009/06/23 10:08:58 tron 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 type
47 /*	The type determines the arguments that follow.
48 /* .RS
49 /* .IP "ATTR_TYPE_INT (char *, int)"
50 /*	This argument is followed by an attribute name and an integer.
51 /* .IP "ATTR_TYPE_LONG (char *, long)"
52 /*	This argument is followed by an attribute name and a long integer.
53 /* .IP "ATTR_TYPE_STR (char *, char *)"
54 /*	This argument is followed by an attribute name and a null-terminated
55 /*	string.
56 /* .IP "ATTR_TYPE_DATA (char *, ssize_t, char *)"
57 /*	This argument is followed by an attribute name, an attribute value
58 /*	length, and an attribute value pointer.
59 /* .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)"
60 /*	This argument is followed by a function pointer and generic data
61 /*	pointer. The caller-specified function returns whatever the
62 /*	specified attribute printing function returns.
63 /* .IP "ATTR_TYPE_HASH (HTABLE *)"
64 /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)"
65 /*	The content of the table is sent as a sequence of string-valued
66 /*	attributes with names equal to the table lookup keys.
67 /* .IP ATTR_TYPE_END
68 /*	This terminates the attribute list.
69 /* .RE
70 /* DIAGNOSTICS
71 /*	The result value is 0 in case of success, VSTREAM_EOF in case
72 /*	of trouble.
73 /*
74 /*	Panic: interface violation. All system call errors are fatal.
75 /* SEE ALSO
76 /*	attr_scan64(3) recover attributes from byte stream
77 /* LICENSE
78 /* .ad
79 /* .fi
80 /*	The Secure Mailer license must be distributed with this software.
81 /* AUTHOR(S)
82 /*	Wietse Venema
83 /*	IBM T.J. Watson Research
84 /*	P.O. Box 704
85 /*	Yorktown Heights, NY 10598, USA
86 /*--*/
87 
88 /* System library. */
89 
90 #include <sys_defs.h>
91 #include <stdarg.h>
92 #include <string.h>
93 
94 /* Utility library. */
95 
96 #include <msg.h>
97 #include <mymalloc.h>
98 #include <vstream.h>
99 #include <htable.h>
100 #include <base64_code.h>
101 #include <attr.h>
102 
103 #define STR(x)	vstring_str(x)
104 #define LEN(x)	VSTRING_LEN(x)
105 
106 /* attr_print64_str - encode and send attribute information */
107 
108 static void attr_print64_str(VSTREAM *fp, const char *str, ssize_t len)
109 {
110     static VSTRING *base64_buf;
111 
112     if (base64_buf == 0)
113 	base64_buf = vstring_alloc(10);
114 
115     base64_encode(base64_buf, str, len);
116     vstream_fputs(STR(base64_buf), fp);
117 }
118 
119 static void attr_print64_num(VSTREAM *fp, unsigned num)
120 {
121     static VSTRING *plain;
122 
123     if (plain == 0)
124 	plain = vstring_alloc(10);
125 
126     vstring_sprintf(plain, "%u", num);
127     attr_print64_str(fp, STR(plain), LEN(plain));
128 }
129 
130 static void attr_print64_long_num(VSTREAM *fp, unsigned long long_num)
131 {
132     static VSTRING *plain;
133 
134     if (plain == 0)
135 	plain = vstring_alloc(10);
136 
137     vstring_sprintf(plain, "%lu", long_num);
138     attr_print64_str(fp, STR(plain), LEN(plain));
139 }
140 
141 /* attr_vprint64 - send attribute list to stream */
142 
143 int     attr_vprint64(VSTREAM *fp, int flags, va_list ap)
144 {
145     const char *myname = "attr_print64";
146     int     attr_type;
147     char   *attr_name;
148     unsigned int_val;
149     unsigned long long_val;
150     char   *str_val;
151     HTABLE_INFO **ht_info_list;
152     HTABLE_INFO **ht;
153     ssize_t len_val;
154     ATTR_PRINT_SLAVE_FN print_fn;
155     void   *print_arg;
156 
157     /*
158      * Sanity check.
159      */
160     if (flags & ~ATTR_FLAG_ALL)
161 	msg_panic("%s: bad flags: 0x%x", myname, flags);
162 
163     /*
164      * Iterate over all (type, name, value) triples, and produce output on
165      * the fly.
166      */
167     while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
168 	switch (attr_type) {
169 	case ATTR_TYPE_INT:
170 	    attr_name = va_arg(ap, char *);
171 	    attr_print64_str(fp, attr_name, strlen(attr_name));
172 	    int_val = va_arg(ap, int);
173 	    VSTREAM_PUTC(':', fp);
174 	    attr_print64_num(fp, (unsigned) int_val);
175 	    VSTREAM_PUTC('\n', fp);
176 	    if (msg_verbose)
177 		msg_info("send attr %s = %u", attr_name, int_val);
178 	    break;
179 	case ATTR_TYPE_LONG:
180 	    attr_name = va_arg(ap, char *);
181 	    attr_print64_str(fp, attr_name, strlen(attr_name));
182 	    long_val = va_arg(ap, long);
183 	    VSTREAM_PUTC(':', fp);
184 	    attr_print64_long_num(fp, (unsigned long) long_val);
185 	    VSTREAM_PUTC('\n', fp);
186 	    if (msg_verbose)
187 		msg_info("send attr %s = %lu", attr_name, long_val);
188 	    break;
189 	case ATTR_TYPE_STR:
190 	    attr_name = va_arg(ap, char *);
191 	    attr_print64_str(fp, attr_name, strlen(attr_name));
192 	    str_val = va_arg(ap, char *);
193 	    VSTREAM_PUTC(':', fp);
194 	    attr_print64_str(fp, str_val, strlen(str_val));
195 	    VSTREAM_PUTC('\n', fp);
196 	    if (msg_verbose)
197 		msg_info("send attr %s = %s", attr_name, str_val);
198 	    break;
199 	case ATTR_TYPE_DATA:
200 	    attr_name = va_arg(ap, char *);
201 	    attr_print64_str(fp, attr_name, strlen(attr_name));
202 	    len_val = va_arg(ap, ssize_t);
203 	    str_val = va_arg(ap, char *);
204 	    VSTREAM_PUTC(':', fp);
205 	    attr_print64_str(fp, str_val, len_val);
206 	    VSTREAM_PUTC('\n', fp);
207 	    if (msg_verbose)
208 		msg_info("send attr %s = [data %ld bytes]",
209 			 attr_name, (long) len_val);
210 	    break;
211 	case ATTR_TYPE_FUNC:
212 	    print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN);
213 	    print_arg = va_arg(ap, void *);
214 	    print_fn(attr_print64, fp, flags | ATTR_FLAG_MORE, print_arg);
215 	    break;
216 	case ATTR_TYPE_HASH:
217 	    ht_info_list = htable_list(va_arg(ap, HTABLE *));
218 	    for (ht = ht_info_list; *ht; ht++) {
219 		attr_print64_str(fp, ht[0]->key, strlen(ht[0]->key));
220 		VSTREAM_PUTC(':', fp);
221 		attr_print64_str(fp, ht[0]->value, strlen(ht[0]->value));
222 		VSTREAM_PUTC('\n', fp);
223 		if (msg_verbose)
224 		    msg_info("send attr name %s value %s",
225 			     ht[0]->key, ht[0]->value);
226 	    }
227 	    myfree((char *) ht_info_list);
228 	    break;
229 	default:
230 	    msg_panic("%s: unknown type code: %d", myname, attr_type);
231 	}
232     }
233     if ((flags & ATTR_FLAG_MORE) == 0)
234 	VSTREAM_PUTC('\n', fp);
235     return (vstream_ferror(fp));
236 }
237 
238 int     attr_print64(VSTREAM *fp, int flags,...)
239 {
240     va_list ap;
241     int     ret;
242 
243     va_start(ap, flags);
244     ret = attr_vprint64(fp, flags, ap);
245     va_end(ap);
246     return (ret);
247 }
248 
249 #ifdef TEST
250 
251  /*
252   * Proof of concept test program.  Mirror image of the attr_scan64 test
253   * program.
254   */
255 #include <msg_vstream.h>
256 
257 int     main(int unused_argc, char **argv)
258 {
259     HTABLE *table = htable_create(1);
260 
261     msg_vstream_init(argv[0], VSTREAM_ERR);
262     msg_verbose = 1;
263     htable_enter(table, "foo-name", mystrdup("foo-value"));
264     htable_enter(table, "bar-name", mystrdup("bar-value"));
265     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
266 		 ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
267 		 ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
268 		 ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
269 	       ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
270 		 ATTR_TYPE_HASH, table,
271 		 ATTR_TYPE_END);
272     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
273 		 ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
274 		 ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
275 		 ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
276 	       ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
277 		 ATTR_TYPE_END);
278     if (vstream_fflush(VSTREAM_OUT) != 0)
279 	msg_fatal("write error: %m");
280 
281     htable_free(table, myfree);
282     return (0);
283 }
284 
285 #endif
286