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