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 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 an attribute value pointer. 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_scan0(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 <attr.h> 99#include <base64_code.h> 100 101#define STR(x) vstring_str(x) 102#define LEN(x) VSTRING_LEN(x) 103 104/* attr_vprint0 - send attribute list to stream */ 105 106int attr_vprint0(VSTREAM *fp, int flags, va_list ap) 107{ 108 const char *myname = "attr_print0"; 109 int attr_type; 110 char *attr_name; 111 unsigned int_val; 112 unsigned long long_val; 113 char *str_val; 114 HTABLE_INFO **ht_info_list; 115 HTABLE_INFO **ht; 116 ssize_t len_val; 117 static VSTRING *base64_buf; 118 ATTR_PRINT_SLAVE_FN print_fn; 119 void *print_arg; 120 121 /* 122 * Sanity check. 123 */ 124 if (flags & ~ATTR_FLAG_ALL) 125 msg_panic("%s: bad flags: 0x%x", myname, flags); 126 127 /* 128 * Iterate over all (type, name, value) triples, and produce output on 129 * the fly. 130 */ 131 while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { 132 switch (attr_type) { 133 case ATTR_TYPE_INT: 134 attr_name = va_arg(ap, char *); 135 vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); 136 int_val = va_arg(ap, int); 137 vstream_fprintf(fp, "%u", (unsigned) int_val); 138 VSTREAM_PUTC('\0', fp); 139 if (msg_verbose) 140 msg_info("send attr %s = %u", attr_name, int_val); 141 break; 142 case ATTR_TYPE_LONG: 143 attr_name = va_arg(ap, char *); 144 vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); 145 long_val = va_arg(ap, unsigned long); 146 vstream_fprintf(fp, "%lu", (unsigned long) long_val); 147 VSTREAM_PUTC('\0', fp); 148 if (msg_verbose) 149 msg_info("send attr %s = %lu", attr_name, long_val); 150 break; 151 case ATTR_TYPE_STR: 152 attr_name = va_arg(ap, char *); 153 vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); 154 str_val = va_arg(ap, char *); 155 vstream_fwrite(fp, str_val, strlen(str_val) + 1); 156 if (msg_verbose) 157 msg_info("send attr %s = %s", attr_name, str_val); 158 break; 159 case ATTR_TYPE_DATA: 160 attr_name = va_arg(ap, char *); 161 vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); 162 len_val = va_arg(ap, ssize_t); 163 str_val = va_arg(ap, char *); 164 if (base64_buf == 0) 165 base64_buf = vstring_alloc(10); 166 base64_encode(base64_buf, str_val, len_val); 167 vstream_fwrite(fp, STR(base64_buf), LEN(base64_buf) + 1); 168 if (msg_verbose) 169 msg_info("send attr %s = [data %ld bytes]", 170 attr_name, (long) len_val); 171 break; 172 case ATTR_TYPE_FUNC: 173 print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); 174 print_arg = va_arg(ap, void *); 175 print_fn(attr_print0, fp, flags | ATTR_FLAG_MORE, print_arg); 176 break; 177 case ATTR_TYPE_HASH: 178 ht_info_list = htable_list(va_arg(ap, HTABLE *)); 179 for (ht = ht_info_list; *ht; ht++) { 180 vstream_fwrite(fp, ht[0]->key, strlen(ht[0]->key) + 1); 181 vstream_fwrite(fp, ht[0]->value, strlen(ht[0]->value) + 1); 182 if (msg_verbose) 183 msg_info("send attr name %s value %s", 184 ht[0]->key, ht[0]->value); 185 } 186 myfree((char *) ht_info_list); 187 break; 188 default: 189 msg_panic("%s: unknown type code: %d", myname, attr_type); 190 } 191 } 192 if ((flags & ATTR_FLAG_MORE) == 0) 193 VSTREAM_PUTC('\0', fp); 194 return (vstream_ferror(fp)); 195} 196 197int attr_print0(VSTREAM *fp, int flags,...) 198{ 199 va_list ap; 200 int ret; 201 202 va_start(ap, flags); 203 ret = attr_vprint0(fp, flags, ap); 204 va_end(ap); 205 return (ret); 206} 207 208#ifdef TEST 209 210 /* 211 * Proof of concept test program. Mirror image of the attr_scan0 test 212 * program. 213 */ 214#include <msg_vstream.h> 215 216int main(int unused_argc, char **argv) 217{ 218 HTABLE *table = htable_create(1); 219 220 msg_vstream_init(argv[0], VSTREAM_ERR); 221 msg_verbose = 1; 222 htable_enter(table, "foo-name", mystrdup("foo-value")); 223 htable_enter(table, "bar-name", mystrdup("bar-value")); 224 attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE, 225 ATTR_TYPE_INT, ATTR_NAME_INT, 4711, 226 ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234L, 227 ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", 228 ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", 229 ATTR_TYPE_HASH, table, 230 ATTR_TYPE_END); 231 attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE, 232 ATTR_TYPE_INT, ATTR_NAME_INT, 4711, 233 ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234L, 234 ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", 235 ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", 236 ATTR_TYPE_END); 237 if (vstream_fflush(VSTREAM_OUT) != 0) 238 msg_fatal("write error: %m"); 239 240 htable_free(table, myfree); 241 return (0); 242} 243 244#endif 245