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