Home | History | Annotate | Line # | Download | only in util
      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