1 /* $NetBSD: attr_print64.c,v 1.3 2022/10/08 16:12:50 christos 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 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_scan64(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 <attr.h> 106 107 #define STR(x) vstring_str(x) 108 #define LEN(x) VSTRING_LEN(x) 109 110 /* attr_print64_str - encode and send attribute information */ 111 112 static void attr_print64_str(VSTREAM *fp, const char *str, ssize_t len) 113 { 114 static VSTRING *base64_buf; 115 116 if (base64_buf == 0) 117 base64_buf = vstring_alloc(10); 118 119 base64_encode(base64_buf, str, len); 120 vstream_fputs(STR(base64_buf), fp); 121 } 122 123 static void attr_print64_num(VSTREAM *fp, unsigned num) 124 { 125 static VSTRING *plain; 126 127 if (plain == 0) 128 plain = vstring_alloc(10); 129 130 vstring_sprintf(plain, "%u", num); 131 attr_print64_str(fp, STR(plain), LEN(plain)); 132 } 133 134 static void attr_print64_long_num(VSTREAM *fp, unsigned long long_num) 135 { 136 static VSTRING *plain; 137 138 if (plain == 0) 139 plain = vstring_alloc(10); 140 141 vstring_sprintf(plain, "%lu", long_num); 142 attr_print64_str(fp, STR(plain), LEN(plain)); 143 } 144 145 /* attr_vprint64 - send attribute list to stream */ 146 147 int attr_vprint64(VSTREAM *fp, int flags, va_list ap) 148 { 149 const char *myname = "attr_print64"; 150 int attr_type; 151 char *attr_name; 152 unsigned int_val; 153 unsigned long long_val; 154 char *str_val; 155 HTABLE_INFO **ht_info_list; 156 HTABLE_INFO **ht; 157 ssize_t len_val; 158 ATTR_PRINT_CUSTOM_FN print_fn; 159 void *print_arg; 160 161 /* 162 * Sanity check. 163 */ 164 if (flags & ~ATTR_FLAG_ALL) 165 msg_panic("%s: bad flags: 0x%x", myname, flags); 166 167 /* 168 * Iterate over all (type, name, value) triples, and produce output on 169 * the fly. 170 */ 171 while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { 172 switch (attr_type) { 173 case ATTR_TYPE_INT: 174 attr_name = va_arg(ap, char *); 175 attr_print64_str(fp, attr_name, strlen(attr_name)); 176 int_val = va_arg(ap, int); 177 VSTREAM_PUTC(':', fp); 178 attr_print64_num(fp, (unsigned) int_val); 179 VSTREAM_PUTC('\n', fp); 180 if (msg_verbose) 181 msg_info("send attr %s = %u", attr_name, int_val); 182 break; 183 case ATTR_TYPE_LONG: 184 attr_name = va_arg(ap, char *); 185 attr_print64_str(fp, attr_name, strlen(attr_name)); 186 long_val = va_arg(ap, long); 187 VSTREAM_PUTC(':', fp); 188 attr_print64_long_num(fp, (unsigned long) long_val); 189 VSTREAM_PUTC('\n', fp); 190 if (msg_verbose) 191 msg_info("send attr %s = %lu", attr_name, long_val); 192 break; 193 case ATTR_TYPE_STR: 194 attr_name = va_arg(ap, char *); 195 attr_print64_str(fp, attr_name, strlen(attr_name)); 196 str_val = va_arg(ap, char *); 197 VSTREAM_PUTC(':', fp); 198 attr_print64_str(fp, str_val, strlen(str_val)); 199 VSTREAM_PUTC('\n', fp); 200 if (msg_verbose) 201 msg_info("send attr %s = %s", attr_name, str_val); 202 break; 203 case ATTR_TYPE_DATA: 204 attr_name = va_arg(ap, char *); 205 attr_print64_str(fp, attr_name, strlen(attr_name)); 206 len_val = va_arg(ap, ssize_t); 207 str_val = va_arg(ap, char *); 208 VSTREAM_PUTC(':', fp); 209 attr_print64_str(fp, str_val, len_val); 210 VSTREAM_PUTC('\n', fp); 211 if (msg_verbose) 212 msg_info("send attr %s = [data %ld bytes]", 213 attr_name, (long) len_val); 214 break; 215 case ATTR_TYPE_FUNC: 216 print_fn = va_arg(ap, ATTR_PRINT_CUSTOM_FN); 217 print_arg = va_arg(ap, void *); 218 print_fn(attr_print64, fp, flags | ATTR_FLAG_MORE, print_arg); 219 break; 220 case ATTR_TYPE_HASH: 221 attr_print64_str(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN) - 1); 222 VSTREAM_PUTC('\n', fp); 223 ht_info_list = htable_list(va_arg(ap, HTABLE *)); 224 for (ht = ht_info_list; *ht; ht++) { 225 attr_print64_str(fp, ht[0]->key, strlen(ht[0]->key)); 226 VSTREAM_PUTC(':', fp); 227 attr_print64_str(fp, ht[0]->value, strlen(ht[0]->value)); 228 VSTREAM_PUTC('\n', fp); 229 if (msg_verbose) 230 msg_info("send attr name %s value %s", 231 ht[0]->key, (char *) ht[0]->value); 232 } 233 myfree((void *) ht_info_list); 234 attr_print64_str(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE) - 1); 235 VSTREAM_PUTC('\n', fp); 236 break; 237 default: 238 msg_panic("%s: unknown type code: %d", myname, attr_type); 239 } 240 } 241 if ((flags & ATTR_FLAG_MORE) == 0) 242 VSTREAM_PUTC('\n', fp); 243 return (vstream_ferror(fp)); 244 } 245 246 int attr_print64(VSTREAM *fp, int flags,...) 247 { 248 va_list ap; 249 int ret; 250 251 va_start(ap, flags); 252 ret = attr_vprint64(fp, flags, ap); 253 va_end(ap); 254 return (ret); 255 } 256 257 #ifdef TEST 258 259 /* 260 * Proof of concept test program. Mirror image of the attr_scan64 test 261 * program. 262 */ 263 #include <msg_vstream.h> 264 265 int main(int unused_argc, char **argv) 266 { 267 HTABLE *table = htable_create(1); 268 269 msg_vstream_init(argv[0], VSTREAM_ERR); 270 msg_verbose = 1; 271 htable_enter(table, "foo-name", mystrdup("foo-value")); 272 htable_enter(table, "bar-name", mystrdup("bar-value")); 273 attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE, 274 SEND_ATTR_STR("protocol", "test"), 275 SEND_ATTR_INT(ATTR_NAME_INT, 4711), 276 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L), 277 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"), 278 SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"), 279 SEND_ATTR_HASH(table), 280 SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L), 281 ATTR_TYPE_END); 282 attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE, 283 SEND_ATTR_STR("protocol", "test"), 284 SEND_ATTR_INT(ATTR_NAME_INT, 4711), 285 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L), 286 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"), 287 SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"), 288 ATTR_TYPE_END); 289 attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE, 290 SEND_ATTR_STR("protocol", "not-test"), 291 ATTR_TYPE_END); 292 if (vstream_fflush(VSTREAM_OUT) != 0) 293 msg_fatal("write error: %m"); 294 295 htable_free(table, myfree); 296 return (0); 297 } 298 299 #endif 300