]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20011010
authorWietse Venema <wietse@porcupine.org>
Wed, 10 Oct 2001 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:27:28 +0000 (06:27 +0000)
postfix/.indent.pro
postfix/src/global/mail_version.h
postfix/src/master/multi_server.c
postfix/src/master/single_server.c
postfix/src/util/Makefile.in
postfix/src/util/attr_io.h [new file with mode: 0644]
postfix/src/util/attr_print.c [new file with mode: 0644]
postfix/src/util/attr_scan.c [new file with mode: 0644]
postfix/src/util/intv.c [new file with mode: 0644]
postfix/src/util/intv.h [new file with mode: 0644]
postfix/src/util/sys_defs.h

index a0d1c27f70dea9dc33aca4fff4567ea9a47edbc1..5e1656aa2218ad97cb05395db04c4e3783fa8fb1 100644 (file)
@@ -54,6 +54,7 @@
 -THTABLE
 -THTABLE_INFO
 -TINET_ADDR_LIST
+-TINTV
 -TINT_TABLE
 -TJMP_BUF_WRAPPER
 -TLMTP_ATTR
index f6824de79f94dbf13b0edf4e7611c06397fe7e6d..584ed2da153b5e32d1c43146403ebf0881d274b6 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20011008"
+#define DEF_MAIL_VERSION       "Snapshot-20011010"
 extern char *var_mail_version;
 
 /* LICENSE
index 0be6a633586a47660ab626f5e507c96d1755e623..39aab4331b85a98b42ea8deff39ada7a49684764 100644 (file)
@@ -272,13 +272,16 @@ static void multi_server_enable_read(int unused_event, char *context)
 static void multi_server_wakeup(int fd)
 {
     VSTREAM *stream;
-
+    char   *tmp;
     if (msg_verbose)
        msg_info("connection established fd %d", fd);
     non_blocking(fd, BLOCKING);
     close_on_exec(fd, CLOSE_ON_EXEC);
     client_count++;
     stream = vstream_fdopen(fd, O_RDWR);
+    tmp = concatenate(multi_server_name, " socket", (char *) 0);
+    vstream_control(stream, VSTREAM_CTL_PATH, tmp,  VSTREAM_CTL_END);
+    myfree(tmp);
     timed_ipc_setup(stream);
     if (multi_server_in_flow_delay && mail_flow_get(1) < 0)
        event_request_timer(multi_server_enable_read, (char *) stream,
index 21079f8e9b2b3f6c6ba064290ff738cd9170f812..d110e40102cce81f80180d4726cf16a26a1ba7e2 100644 (file)
@@ -221,6 +221,7 @@ static void single_server_timeout(int unused_event, char *unused_context)
 static void single_server_wakeup(int fd)
 {
     VSTREAM *stream;
+    char   *tmp;
 
     /*
      * If the accept() succeeds, be sure to disable non-blocking I/O, because
@@ -233,6 +234,9 @@ static void single_server_wakeup(int fd)
     non_blocking(fd, BLOCKING);
     close_on_exec(fd, CLOSE_ON_EXEC);
     stream = vstream_fdopen(fd, O_RDWR);
+    tmp = concatenate(single_server_name, " socket", (char *) 0);
+    vstream_control(stream, VSTREAM_CTL_PATH, tmp,  VSTREAM_CTL_END);
+    myfree(tmp);
     timed_ipc_setup(stream);
     if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
        single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
index dd2c9154273d78244401de05c83f57f835261f19..bf8ecebdaac701929bab998e7fbe6b5474cf0b4d 100644 (file)
@@ -23,7 +23,8 @@ SRCS  = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
        clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
        sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
        hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
-       sane_socketpair.c myrand.c netstring.c ctable.c
+       sane_socketpair.c myrand.c netstring.c ctable.c attr_print.c intv.c \
+       attr_scan.c
 OBJS   = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
        dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
@@ -48,7 +49,8 @@ OBJS  = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
        sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
        hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
-       sane_socketpair.o myrand.o netstring.o ctable.o
+       sane_socketpair.o myrand.o netstring.o ctable.o attr_print.o intv.o \
+       attr_scan.o
 HDRS   = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
        dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
@@ -64,7 +66,8 @@ HDRS  = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
        dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
        watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
-       sane_time.h sane_socketpair.h myrand.h netstring.h ctable.h
+       sane_time.h sane_socketpair.h myrand.h netstring.h ctable.h \
+       attr_io.h intv.h
 TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
        stream_test.c dup2_pass_on_exec.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -81,7 +84,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
        mystrtok sigdelay translit valid_hostname vstream_popen \
        vstring vstring_vstream doze select_bug stream_test mac_expand \
        watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
-       inet_addr_list
+       inet_addr_list attr_print attr_scan
 
 LIB_DIR        = ../../lib
 INC_DIR        = ../../include
@@ -285,6 +288,16 @@ inet_addr_list: $(LIB) $@.o
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
        mv junk $@.o
 
+attr_print: $(LIB) $@.o
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+       mv junk $@.o
+
+attr_scan: $(LIB) $@.o
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+       mv junk $@.o
+
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
        set -e; for i in [a-z][a-z0-9]*.c; do \
@@ -359,6 +372,21 @@ attr.o: sys_defs.h
 attr.o: mymalloc.h
 attr.o: htable.h
 attr.o: attr.h
+attr_print.o: attr_print.c
+attr_print.o: sys_defs.h
+attr_print.o: vstream.h
+attr_print.o: vbuf.h
+attr_print.o: msg.h
+attr_print.o: attr_io.h
+attr_scan.o: attr_scan.c
+attr_scan.o: sys_defs.h
+attr_scan.o: vstream.h
+attr_scan.o: vbuf.h
+attr_scan.o: vstring.h
+attr_scan.o: msg.h
+attr_scan.o: argv.h
+attr_scan.o: intv.h
+attr_scan.o: attr_io.h
 basename.o: basename.c
 basename.o: sys_defs.h
 basename.o: stringops.h
@@ -682,6 +710,11 @@ inet_util.o: sys_defs.h
 inet_util.o: mymalloc.h
 inet_util.o: split_at.h
 inet_util.o: inet_util.h
+intv.o: intv.c
+intv.o: sys_defs.h
+intv.o: mymalloc.h
+intv.o: msg.h
+intv.o: intv.h
 line_wrap.o: line_wrap.c
 line_wrap.o: sys_defs.h
 line_wrap.o: line_wrap.h
diff --git a/postfix/src/util/attr_io.h b/postfix/src/util/attr_io.h
new file mode 100644 (file)
index 0000000..44c0bd3
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _ATTR_PRINT_H_INCLUDED_
+#define _ATTR_PRINT_H_INCLUDED_
+
+/*++
+/* NAME
+/*     attr_type 3h
+/* SUMMARY
+/*     attribute list I/O
+/* SYNOPSIS
+/*     #include "attr_type.h"
+ DESCRIPTION
+ .nf
+
+ /*
+  * System library.
+  */
+#include <stdarg.h>
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+
+ /*
+  * External interface.
+  */
+#define ATTR_TYPE_END          0       /* end of data */
+#define ATTR_TYPE_NUM          1       /* Unsigned integer */
+#define ATTR_TYPE_STR          2       /* Character string */
+#define ATTR_TYPE_NUM_ARRAY    3       /* Unsigned integer sequence */
+#define ATTR_TYPE_STR_ARRAY    4       /* Character string sequence */
+
+#define ATTR_FLAG_MISSING      (1<<0)  /* Flag missing attribute */
+#define ATTR_FLAG_EXTRA                (1<<1)  /* Flag spurious attribute */
+
+extern int attr_print(VSTREAM *,...);
+extern int attr_vprint(VSTREAM *, va_list);
+extern int attr_scan(VSTREAM *, int,...);
+extern int attr_vscan(VSTREAM *, int, va_list);
+
+ /*
+  * Attribute names for testing the compatibility of the read and write
+  * routines.
+  */
+#ifdef TEST
+#define ATTR_NAME_NUM          "number"
+#define ATTR_NAME_STR          "string"
+#define ATTR_NAME_NUM_ARRAY    "number_array"
+#define ATTR_NAME_STR_ARRAY    "string_array"
+#endif
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/util/attr_print.c b/postfix/src/util/attr_print.c
new file mode 100644 (file)
index 0000000..226a5cb
--- /dev/null
@@ -0,0 +1,175 @@
+/*++
+/* NAME
+/*     attr_print 3
+/* SUMMARY
+/*     send attributes over byte stream
+/* SYNOPSIS
+/*     #include <attr_io.h>
+/*
+/*     int     attr_print(fp, type, name, ...)
+/*     VSTREAM fp;
+/*     int     type;
+/*     char    *name;
+/* DESCRIPTION
+/*     attr_print() takes zero or more (name, value) simple attributes
+/*     or (name, count, value) list attributes, and converts its input
+/*     to a byte stream that can be recovered with attr_scan(). The stream
+/*     is not flushed.
+/*
+/*     Attributes are sent in the requested order as specified with the
+/*     attr_print() argument list. This routine satisfies the formatting
+/*     rules as outlined in attr_scan(3).
+/*
+/*     Arguments:
+/* .IP fp
+/*     Stream to write the result to.
+/* .IP type
+/*     The type determines the arguments that follow.
+/* .RS
+/* .IP "ATTR_TYPE_NUM (char *, int)"
+/*     This argument is followed by an attribute name and an integer.
+/* .IP "ATTR_TYPE_STR (char *, char *)"
+/*     This argument is followed by an attribute name and a null-terminated
+/*     string.
+/* .IP "ATTR_TYPE_NUM_ARRAY (char *, int, int *)"
+/*     This argument is followed by an attribute name, an integer array
+/*     element count, and a pointer to integer.
+/* .IP "ATTR_TYPE_NUM_ARRAY (char *, int, char **)"
+/*     This argument is followed by an attribute name, an integer array
+/*     element count, and a pointer to a null-terminated array of
+/*     null-terminated strings.
+/* .IP ATTR_TYPE_END
+/*     This terminates the attribute list.
+/* .RE
+/* DIAGNOSTICS
+/*     The result value is 0 in case of success, VSTREAM_EOF in case
+/*     of trouble.
+/*
+/*     Panic: interface violation. All system call errors are fatal.
+/* SEE ALSO
+/*     attr_scan(3) recover attributes from byte stream
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdarg.h>
+
+/* Utility library. */
+
+#include <vstream.h>
+#include <msg.h>
+#include <attr_io.h>
+
+/* attr_fprintf - encode attribute information on the fly */
+
+static void PRINTFLIKE(2, 3) attr_fprintf(VSTREAM *fp, const char *format,...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    vstream_vfprintf(fp, format, ap);
+    va_end(ap);
+}
+
+/* attr_vprint - send attribute list to stream */
+
+int     attr_vprint(VSTREAM *fp, va_list ap)
+{
+    const char *myname = "attr_print";
+    int     attr_type;
+    char   *attr_name;
+    unsigned int_val;
+    char   *str_val;
+    char  **cpp_val;
+    unsigned *ip_val;
+    int     count_val;
+    int     i;
+
+    /*
+     * Iterate over all (type, name, value) triples, and produce output on
+     * the fly.
+     */
+    while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
+       attr_name = va_arg(ap, char *);
+       attr_fprintf(fp, "%s", attr_name);
+       switch (attr_type) {
+       case ATTR_TYPE_NUM:
+           int_val = va_arg(ap, int);
+           attr_fprintf(fp, ":%u", (unsigned) int_val);
+           break;
+       case ATTR_TYPE_STR:
+           str_val = va_arg(ap, char *);
+           attr_fprintf(fp, ":%s", str_val);
+           break;
+       case ATTR_TYPE_NUM_ARRAY:
+           ip_val = va_arg(ap, int *);
+           count_val = va_arg(ap, int);
+           for (i = 0; i < count_val; i++)
+               attr_fprintf(fp, ":%u", (unsigned) *ip_val++);
+           break;
+       case ATTR_TYPE_STR_ARRAY:
+           cpp_val = va_arg(ap, char **);
+           count_val = va_arg(ap, int);
+           for (i = 0; i < count_val; i++) {
+               str_val = *cpp_val++;
+               attr_fprintf(fp, ":%s", str_val);
+           }
+           break;
+       default:
+           msg_panic("%s: unknown type code: %d", myname, attr_type);
+       }
+       VSTREAM_PUTC('\n', fp);
+    }
+    VSTREAM_PUTC('\n', fp);
+    return (vstream_ferror(fp));
+}
+
+int     attr_print(VSTREAM *fp,...)
+{
+    va_list ap;
+    int     ret;
+
+    va_start(ap, fp);
+    ret = attr_vprint(fp, ap);
+    va_end(ap);
+    return (ret);
+}
+
+#ifdef TEST
+
+ /*
+  * Proof of concept test program.  Mirror image of the attr_scan test
+  * program.
+  */
+#include <msg_vstream.h>
+
+int     main(int argc, char **argv)
+{
+    static int int_array[] = {0, 1, 2, 3, 4, 5, 6, 7};
+    static char *str_array[] = {"a", "b", "c", "d", "e", "f", "g", "h"};
+
+    msg_vstream_init(argv[0], VSTREAM_ERR);
+    attr_print(VSTREAM_OUT,
+              ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+              ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+              ATTR_TYPE_NUM_ARRAY, ATTR_NAME_NUM_ARRAY,
+              int_array, sizeof(int_array) / sizeof(int_array[0]),
+              ATTR_TYPE_STR_ARRAY, ATTR_NAME_STR_ARRAY,
+              str_array, sizeof(str_array) / sizeof(str_array[0]),
+              ATTR_TYPE_END);
+    if (vstream_fflush(VSTREAM_OUT) != 0)
+       msg_fatal("write error: %m");
+    return (0);
+}
+
+#endif
diff --git a/postfix/src/util/attr_scan.c b/postfix/src/util/attr_scan.c
new file mode 100644 (file)
index 0000000..c40d906
--- /dev/null
@@ -0,0 +1,369 @@
+/*++
+/* NAME
+/*     attr_scan 3
+/* SUMMARY
+/*     recover attributes from byte stream
+/* SYNOPSIS
+/*     #include <attr_io.h>
+/*
+/*     int     attr_scan(fp, flags, type, name, ...)
+/*     VSTREAM fp;
+/*     int     flags;
+/*     int     type;
+/*     char    *name;
+/* DESCRIPTION
+/*     attr_scan() takes zero or more (name, value) scalar or array
+/*     attribute arguments, and recovers the attribute values from the
+/*     byte stream that was generated by attr_print().
+/*
+/*     The input stream is formatted as follows, where (item)* stands
+/*     for zero or more instances of the specified item, and where
+/*     (item1 | item2) stands for choice:
+/*
+/* .in +5
+/*     attr-list :== (simple-attr | list-attr)* newline
+/* .br
+/*     simple-attr :== attr-name colon attr-value newline
+/* .br
+/*     list-attr :== attr-name (colon attr-value)* newline
+/* .br
+/*     attr-name :== any base64 encoded string
+/* .br
+/*     attr-value :== any base64 encoded string
+/* .br
+/*     colon :== the ASCII colon character
+/* .br
+/*     newline :== the ASCII newline character
+/* .in
+/*
+/*     All character values are 7-bit ASCII. All attribute names and
+/*     attribute values are sent as base64-encoded strings. The
+/*     formatting rules aim to make implementations in PERL and other
+/*     non-C languages easy.
+/*
+/*     Attributes must be sent in the requested order as specified with
+/*     the attr_scan() argument list. The input stream may contain
+/*     additional attributes at any point in the input stream, including
+/*     additional instances of requested attributes.
+/*
+/*     Additional attributes are silently skipped over, unless the
+/*     ATTR_FLAG_EXTRA processing flag is specified (see below). This
+/*     allows for some flexibility in the evolution of protocols while
+/*     still providing the option of being strict where desirable.
+/*
+/*     Arguments:
+/* .IP fp
+/*     Stream to recover the attributes from.
+/* .IP flags
+/*     The bit-wise OR of zero or more of the following.
+/* .RS
+/* .IP ATTR_FLAG_MISSING
+/*     Log a warning when the input attribute list terminates before all
+/*     requested attributes are recovered. It is always an error when the
+/*     input stream ends without the newline attribute list terminator.
+/* .IP ATTR_FLAG_EXTRA
+/*     Log a warning and stop attribute recovery when the input stream
+/*     contains an attribute that was not requested.
+/* .RE
+/* .IP type
+/*     The type determines the arguments that follow.
+/* .RS
+/* .IP "ATTR_TYPE_NUM (char *, int *)"
+/*     This argument is followed by an attribute name and an integer pointer.
+/*     This is used for recovering an integer attribute value.
+/* .IP "ATTR_TYPE_STR (char *, VSTRING *)"
+/*     This argument is followed by an attribute name and a VSTRING pointer.
+/*     This is used for recovering a string attribute value.
+/* .IP "ATTR_TYPE_NUM_ARRAY (char *, INTV *)"
+/*     This argument is followed by an attribute name and an INTV pointer.
+/*     This is used for recovering an integer array attribute value.
+/* .IP "ATTR_TYPE_NUM_ARRAY (char *, ARGV *)"
+/*     This argument is followed by an attribute name and an ARGV pointer.
+/*     This is used for recovering a string array attribute value.
+/* .IP ATTR_TYPE_END
+/*     This terminates the requested attribute list.
+/* .RE
+/* DIAGNOSTICS
+/*     The result value is the number of attributes that were successfully
+/*     recovered from the input stream (an array-valued attribute counts
+/*     as one attribute).
+/*
+/*     Panic: interface violation. All system call errors are fatal.
+/* SEE ALSO
+/*     attr_print(3) send attributes over byte stream.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* Utility library. */
+
+#include <vstream.h>
+#include <vstring.h>
+#include <msg.h>
+#include <argv.h>
+#include <intv.h>
+#include <attr_io.h>
+
+/* Application specific. */
+
+extern int var_line_limit;             /* XXX */
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* attr_scan_string - pull a string from the input stream */
+
+static int attr_scan_string(VSTREAM *fp, VSTRING *plain_buf, const char *context)
+{
+    VSTRING *base64_buf = 0;
+    int     limit = var_line_limit * 5 / 4;
+    int     ch;
+
+    if (base64_buf == 0)
+       base64_buf = vstring_alloc(10);
+
+    VSTRING_RESET(base64_buf);
+    while ((ch = VSTREAM_GETC(fp)) != ':' && ch != '\n') {
+       if (ch == VSTREAM_EOF) {
+           msg_warn("premature end-of-input from %s while reading %s",
+                    VSTREAM_PATH(fp), context);
+           return (-1);
+       }
+       if (LEN(base64_buf) > limit) {
+           msg_warn("string length > %d characters from %s while reading %s",
+                    limit, VSTREAM_PATH(fp), context);
+           return (-1);
+       }
+       VSTRING_ADDCH(base64_buf, ch);
+    }
+    VSTRING_TERMINATE(base64_buf);
+    vstring_strcpy(plain_buf, STR(base64_buf));
+    if (msg_verbose)
+       msg_info("%s: %s", context, STR(plain_buf));
+    return (ch);
+}
+
+/* attr_scan_number - pull a number from the input stream */
+
+static int attr_scan_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
+                                   const char *context)
+{
+    char    junk = 0;
+    int     ch;
+
+    if ((ch = attr_scan_string(fp, str_buf, context)) < 0)
+       return (-1);
+    if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) {
+       msg_warn("malformed numerical data from %s while %s: %.100s",
+                VSTREAM_PATH(fp), context, STR(str_buf));
+       return (-1);
+    }
+    return (ch);
+}
+
+/* attr_vscan - receive attribute list from stream */
+
+int     attr_vscan(VSTREAM *fp, int flags, va_list ap)
+{
+    const char *myname = "attr_scan";
+    static VSTRING *str_buf = 0;
+    int     wanted_type;
+    char   *wanted_name;
+    int    *number;
+    VSTRING *string;
+    INTV   *number_array;
+    ARGV   *string_array;
+    unsigned num_val;
+    int     ch;
+    int     conversions = 0;
+
+    /*
+     * Initialize.
+     */
+    if (str_buf == 0)
+       str_buf = vstring_alloc(10);
+
+    /*
+     * Iterate over all (type, name, value) triples.
+     */
+    for (;;) {
+
+       /*
+        * Determine the next attribute name on the caller's wish list.
+        */
+       wanted_type = va_arg(ap, int);
+       if (wanted_type == ATTR_TYPE_END) {
+           wanted_name = "attribute list terminator";
+       } else {
+           wanted_name = va_arg(ap, char *);
+       }
+
+       /*
+        * Locate the next attribute of interest in the input stream.
+        */
+       for (;;) {
+
+           /*
+            * Get the name of the next attribute. Hitting the end-of-input
+            * early is OK if the caller is prepared to deal with missing
+            * inputs.
+            */
+           if ((ch = attr_scan_string(fp, str_buf,
+                                      "attribute name")) == VSTREAM_EOF)
+               return (conversions);
+           if (ch == '\n' && LEN(str_buf) == 0) {
+               if (wanted_type == ATTR_TYPE_END
+                   || (flags & ATTR_FLAG_MISSING) == 0)
+                   return (conversions);
+               msg_warn("missing attribute %s in input from %s",
+                        wanted_name, VSTREAM_PATH(fp));
+               return (conversions);
+           }
+           if (msg_verbose)
+               msg_info("want attribute %s, found attribute: %s",
+                        wanted_name, STR(str_buf));
+
+           /*
+            * See if the caller asks for this attribute.
+            */
+           if (wanted_type != ATTR_TYPE_END
+               && strcmp(wanted_name, STR(str_buf)) == 0)
+               break;
+           if ((flags & ATTR_FLAG_EXTRA) != 0) {
+               msg_warn("spurious attribute %s in input from %s",
+                        STR(str_buf), VSTREAM_PATH(fp));
+               return (conversions);
+           }
+
+           /*
+            * Skip over this attribute. The caller does not ask for it.
+            */
+           while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n')
+                /* void */ ;
+       }
+
+       /*
+        * Do the requested conversion. If the target attribute is a
+        * non-array type, do not allow the sender to send a multi-valued
+        * attribute. If the target attribute is an array type, allow the
+        * sender to send a zero-element array.
+        */
+       switch (wanted_type) {
+       case ATTR_TYPE_NUM:
+           number = va_arg(ap, int *);
+           if ((ch = attr_scan_number(fp, number, str_buf,
+                                      "attribute value")) < 0)
+               return (conversions);
+           if (ch != '\n') {
+               msg_warn("too many values for attribute %s from %s",
+                        wanted_name, VSTREAM_PATH(fp));
+               return (conversions);
+           }
+           break;
+       case ATTR_TYPE_STR:
+           string = va_arg(ap, VSTRING *);
+           if ((ch = attr_scan_string(fp, string, "attribute value")) < 0)
+               return (conversions);
+           if (ch != '\n') {
+               msg_warn("too many values for attribute %s from %s",
+                        wanted_name, VSTREAM_PATH(fp));
+               return (conversions);
+           }
+           break;
+       case ATTR_TYPE_NUM_ARRAY:
+           number_array = va_arg(ap, INTV *);
+           while (ch != '\n') {
+               if ((ch = attr_scan_number(fp, &num_val, str_buf,
+                                          "attribute value")) < 0)
+                   return (conversions);
+               intv_add(number_array, 1, num_val);
+           }
+           break;
+       case ATTR_TYPE_STR_ARRAY:
+           string_array = va_arg(ap, ARGV *);
+           while (ch != '\n') {
+               if ((ch = attr_scan_string(fp, str_buf, "attribute value")) < 0)
+                   return (conversions);
+               argv_add(string_array, STR(str_buf), (char *) 0);
+           }
+           break;
+       default:
+           msg_panic("%s: unknown type code: %d", myname, wanted_type);
+       }
+       conversions++;
+    }
+}
+
+/* attr_scan - read attribute list from stream */
+
+int     attr_scan(VSTREAM *fp, int flags,...)
+{
+    va_list ap;
+    int     ret;
+
+    va_start(ap, flags);
+    ret = attr_vscan(fp, flags, ap);
+    va_end(ap);
+    return (ret);
+}
+
+#ifdef TEST
+
+ /*
+  * Proof of concept test program.  Mirror image of the attr_scan test
+  * program.
+  */
+#include <msg_vstream.h>
+
+int     var_line_limit = 2048;
+
+int     main(int unused_argc, char **used_argv)
+{
+    INTV   *intv = intv_alloc(1);
+    ARGV   *argv = argv_alloc(1);
+    VSTRING *str_val = vstring_alloc(1);
+    int     int_val;
+    int     ret;
+    int     i;
+
+    msg_verbose = 1;
+    msg_vstream_init(used_argv[0], VSTREAM_ERR);
+    if ((ret = attr_scan(VSTREAM_IN,
+                        ATTR_FLAG_MISSING | ATTR_FLAG_EXTRA,
+                        ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+                        ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+                        ATTR_TYPE_NUM_ARRAY, ATTR_NAME_NUM_ARRAY, intv,
+                        ATTR_TYPE_STR_ARRAY, ATTR_NAME_STR_ARRAY, argv,
+                        ATTR_TYPE_END)) == 4) {
+       vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+       vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s", ATTR_NAME_NUM_ARRAY);
+       for (i = 0; i < intv->intc; i++)
+           vstream_printf(" %d", intv->intv[i]);
+       vstream_printf("\n");
+       vstream_printf("%s", ATTR_NAME_STR_ARRAY);
+       for (i = 0; i < argv->argc; i++)
+           vstream_printf(" %s", argv->argv[i]);
+       vstream_printf("\n");
+    } else {
+       vstream_printf("return: %d\n", ret);
+    }
+    if (vstream_fflush(VSTREAM_OUT) != 0)
+       msg_fatal("write error: %m");
+    return (0);
+}
+
+#endif
diff --git a/postfix/src/util/intv.c b/postfix/src/util/intv.c
new file mode 100644 (file)
index 0000000..1d117fe
--- /dev/null
@@ -0,0 +1,114 @@
+/*++
+/* NAME
+/*     intv 3
+/* SUMMARY
+/*     integer array utilities
+/* SYNOPSIS
+/*     #include <intv.h>
+/*
+/*     INTV    *intv_alloc(len)
+/*     int     len;
+/*
+/*     INTV    *intv_free(intvp)
+/*     INTV    *intvp;
+/*
+/*     void    intv_add(intvp, count, arg, ...)
+/*     INTV    *intvp;
+/*     int     count;
+/*     int     *arg;
+/* DESCRIPTION
+/*     The functions in this module manipulate arrays of integers.
+/*     An INTV structure contains the following members:
+/* .IP len
+/*     The actual length of the \fIintv\fR array.
+/* .IP intc
+/*     The number of \fIintv\fR elements used.
+/* .IP intv
+/*     An array of integer values.
+/* .PP
+/*     intv_alloc() returns an empty integer array of the requested
+/*     length. The result is ready for use by intv_add().
+/*
+/*     intv_add() copies zero or more integers and adds them to the
+/*     specified integer array.
+/*
+/*     intv_free() releases storage for an integer array, and conveniently
+/*     returns a null pointer.
+/* SEE ALSO
+/*     msg(3) diagnostics interface
+/* DIAGNOSTICS
+/*     Fatal errors: memory allocation problem.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+
+/* Application-specific. */
+
+#include "mymalloc.h"
+#include "msg.h"
+#include "intv.h"
+
+/* intv_free - destroy integer array */
+
+INTV   *intv_free(INTV *intvp)
+{
+    myfree((char *) intvp->intv);
+    myfree((char *) intvp);
+    return (0);
+}
+
+/* intv_alloc - initialize integer array */
+
+INTV   *intv_alloc(int len)
+{
+    INTV   *intvp;
+
+    /*
+     * Sanity check.
+     */
+    if (len < 1)
+       msg_panic("intv_alloc: bad array length %d", len);
+
+    /*
+     * Initialize.
+     */
+    intvp = (INTV *) mymalloc(sizeof(*intvp));
+    intvp->len = len;
+    intvp->intv = (int *) mymalloc(intvp->len * sizeof(intvp->intv[0]));
+    intvp->intc = 0;
+    return (intvp);
+}
+
+/* intv_add - add integer to vector */
+
+void    intv_add(INTV *intvp, int count,...)
+{
+    va_list ap;
+
+    /*
+     * Make sure that always intvp->intc < intvp->len.
+     */
+    va_start(ap, count);
+    while (count-- > 0) {
+       if (intvp->intc >= intvp->len) {
+           intvp->len *= 2;
+           intvp->intv = (int *) myrealloc((char *) intvp->intv,
+                                            intvp->len * sizeof(int));
+       }
+       intvp->intv[intvp->intc++] = va_arg(ap, int);
+    }
+    va_end(ap);
+}
diff --git a/postfix/src/util/intv.h b/postfix/src/util/intv.h
new file mode 100644 (file)
index 0000000..d84c5b4
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _INTV_H_INCLUDED_
+#define _INTV_H_INCLUDED_
+
+/*++
+/* NAME
+/*     intv 3h
+/* SUMMARY
+/*     string array utilities
+/* SYNOPSIS
+/*     #include "intv.h"
+ DESCRIPTION
+ .nf
+
+ /*
+  * External interface.
+  */
+typedef struct INTV {
+    int     len;                       /* number of array elements */
+    int     intc;                      /* array elements in use */
+    int    *intv;                      /* integer array */
+} INTV;
+
+extern INTV *intv_alloc(int);
+extern void intv_add(INTV *, int,...);
+extern INTV *intv_free(INTV *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index da8388d3138d051aa730dbb76670a8ee4b7bfb2f..13b07c6f1fef57f1169bdd1184ad4618bffd556d 100644 (file)
@@ -26,7 +26,7 @@
 #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
     || defined(FREEBSD5) \
     || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
-    || defined(OPENBSD2) || defined(NETBSD1)
+    || defined(OPENBSD2) || defined(OPENBSD3) || defined(NETBSD1)
 #define SUPPORTED
 #include <sys/types.h>
 #include <sys/param.h>
@@ -58,7 +58,8 @@
 #define HAS_DUPLEX_PIPE
 #endif
 
-#if defined(OPENBSD2) || defined(FREEBSD3) || defined(FREEBSD4)
+#if defined(OPENBSD2) || defined(OPENBSD3) \
+    || defined(FREEBSD3) || defined(FREEBSD4)
 #define HAS_ISSETUGID
 #endif