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