1 /* $NetBSD: attr_print_plain.c,v 1.3 2022/10/08 16:12:50 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* attr_print_plain 3
6 /* SUMMARY
7 /* send attributes over byte stream
8 /* SYNOPSIS
9 /* #include <attr.h>
10 /*
11 /* int attr_print_plain(fp, flags, type, name, ..., ATTR_TYPE_END)
12 /* VSTREAM fp;
13 /* int flags;
14 /* int type;
15 /* char *name;
16 /*
17 /* int attr_vprint_plain(fp, flags, ap)
18 /* VSTREAM fp;
19 /* int flags;
20 /* va_list ap;
21 /* DESCRIPTION
22 /* attr_print_plain() takes zero or more (name, value) simple attributes
23 /* and converts its input to a byte stream that can be recovered with
24 /* attr_scan_plain(). The stream is not flushed.
25 /*
26 /* attr_vprint_plain() 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_print_plain() argument list. This routine satisfies the formatting
31 /* rules as outlined in attr_scan_plain(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_print_plain() 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_scan_plain(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 <vstring.h>
106 #include <attr.h>
107
108 #define STR(x) vstring_str(x)
109 #define LEN(x) VSTRING_LEN(x)
110
111 /* attr_vprint_plain - send attribute list to stream */
112
attr_vprint_plain(VSTREAM * fp,int flags,va_list ap)113 int attr_vprint_plain(VSTREAM *fp, int flags, va_list ap)
114 {
115 const char *myname = "attr_print_plain";
116 int attr_type;
117 char *attr_name;
118 unsigned int_val;
119 unsigned long long_val;
120 char *str_val;
121 HTABLE_INFO **ht_info_list;
122 HTABLE_INFO **ht;
123 static VSTRING *base64_buf;
124 ssize_t len_val;
125 ATTR_PRINT_CUSTOM_FN print_fn;
126 void *print_arg;
127
128 /*
129 * Sanity check.
130 */
131 if (flags & ~ATTR_FLAG_ALL)
132 msg_panic("%s: bad flags: 0x%x", myname, flags);
133
134 /*
135 * Iterate over all (type, name, value) triples, and produce output on
136 * the fly.
137 */
138 while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
139 switch (attr_type) {
140 case ATTR_TYPE_INT:
141 attr_name = va_arg(ap, char *);
142 int_val = va_arg(ap, int);
143 vstream_fprintf(fp, "%s=%u\n", attr_name, (unsigned) int_val);
144 if (msg_verbose)
145 msg_info("send attr %s = %u", attr_name, (unsigned) int_val);
146 break;
147 case ATTR_TYPE_LONG:
148 attr_name = va_arg(ap, char *);
149 long_val = va_arg(ap, long);
150 vstream_fprintf(fp, "%s=%lu\n", attr_name, long_val);
151 if (msg_verbose)
152 msg_info("send attr %s = %lu", attr_name, long_val);
153 break;
154 case ATTR_TYPE_STR:
155 attr_name = va_arg(ap, char *);
156 str_val = va_arg(ap, char *);
157 vstream_fprintf(fp, "%s=%s\n", attr_name, str_val);
158 if (msg_verbose)
159 msg_info("send attr %s = %s", attr_name, str_val);
160 break;
161 case ATTR_TYPE_DATA:
162 attr_name = va_arg(ap, char *);
163 len_val = va_arg(ap, ssize_t);
164 str_val = va_arg(ap, char *);
165 if (base64_buf == 0)
166 base64_buf = vstring_alloc(10);
167 base64_encode(base64_buf, str_val, len_val);
168 vstream_fprintf(fp, "%s=%s\n", attr_name, STR(base64_buf));
169 if (msg_verbose)
170 msg_info("send attr %s = [data %ld bytes]",
171 attr_name, (long) len_val);
172 break;
173 case ATTR_TYPE_FUNC:
174 print_fn = va_arg(ap, ATTR_PRINT_CUSTOM_FN);
175 print_arg = va_arg(ap, void *);
176 print_fn(attr_print_plain, fp, flags | ATTR_FLAG_MORE, print_arg);
177 break;
178 case ATTR_TYPE_HASH:
179 vstream_fwrite(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN));
180 VSTREAM_PUTC('\n', fp);
181 ht_info_list = htable_list(va_arg(ap, HTABLE *));
182 for (ht = ht_info_list; *ht; ht++) {
183 vstream_fprintf(fp, "%s=%s\n", ht[0]->key, (char *) ht[0]->value);
184 if (msg_verbose)
185 msg_info("send attr name %s value %s",
186 ht[0]->key, (char *) ht[0]->value);
187 }
188 myfree((void *) ht_info_list);
189 vstream_fwrite(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE));
190 VSTREAM_PUTC('\n', fp);
191 break;
192 default:
193 msg_panic("%s: unknown type code: %d", myname, attr_type);
194 }
195 }
196 if ((flags & ATTR_FLAG_MORE) == 0)
197 VSTREAM_PUTC('\n', fp);
198 return (vstream_ferror(fp));
199 }
200
attr_print_plain(VSTREAM * fp,int flags,...)201 int attr_print_plain(VSTREAM *fp, int flags,...)
202 {
203 va_list ap;
204 int ret;
205
206 va_start(ap, flags);
207 ret = attr_vprint_plain(fp, flags, ap);
208 va_end(ap);
209 return (ret);
210 }
211
212 #ifdef TEST
213
214 /*
215 * Proof of concept test program. Mirror image of the attr_scan_plain test
216 * program.
217 */
218 #include <msg_vstream.h>
219
main(int unused_argc,char ** argv)220 int main(int unused_argc, char **argv)
221 {
222 HTABLE *table = htable_create(1);
223
224 msg_vstream_init(argv[0], VSTREAM_ERR);
225 msg_verbose = 1;
226 htable_enter(table, "foo-name", mystrdup("foo-value"));
227 htable_enter(table, "bar-name", mystrdup("bar-value"));
228 attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
229 SEND_ATTR_STR("protocol", "test"),
230 SEND_ATTR_INT(ATTR_NAME_INT, 4711),
231 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L),
232 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
233 SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
234 SEND_ATTR_HASH(table),
235 SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L),
236 ATTR_TYPE_END);
237 attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
238 SEND_ATTR_STR("protocol", "test"),
239 SEND_ATTR_INT(ATTR_NAME_INT, 4711),
240 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L),
241 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
242 SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
243 ATTR_TYPE_END);
244 attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
245 SEND_ATTR_STR("protocol", "not-test"),
246 ATTR_TYPE_END);
247 if (vstream_fflush(VSTREAM_OUT) != 0)
248 msg_fatal("write error: %m");
249
250 htable_free(table, myfree);
251 return (0);
252 }
253
254 #endif
255