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