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