]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5-20071223
authorWietse Venema <wietse@porcupine.org>
Sun, 23 Dec 2007 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:33:45 +0000 (06:33 +0000)
13 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/src/global/dsb_scan.c
postfix/src/global/dsn_print.c
postfix/src/global/mail_version.h
postfix/src/global/msg_stats_print.c
postfix/src/global/rcpt_buf.c
postfix/src/global/rcpt_print.c
postfix/src/milter/Makefile.in
postfix/src/milter/milter.c
postfix/src/milter/milter.h
postfix/src/milter/milter8.c
postfix/src/milter/milter_macros.c [new file with mode: 0644]

index 30e4668578cdf40eaabd545bef35eb9e95be6d5f..3b8209c42fc553088f863e71734ace63898208f1 100644 (file)
 -TMILTER
 -TMILTER8
 -TMILTERS
+-TMILTER_MACROS
 -TMILTER_MSG_CONTEXT
 -TMIME_ENCODING
 -TMIME_INFO
index ebc0f1657430f72401d93783b5b52cc4a41c0bfd..5e90db6fd9d7b25471034fb3945e3d0e9b77910f 100644 (file)
@@ -14053,3 +14053,12 @@ Apologies for any names omitted.
 
        Further polishing of the Milter code and logging. File:
        milter/milter8.c.
+
+20071123
+
+       Further polishing of the Milter code. With SETSYMLIST, each
+       Milter can update its own macros instead of clobbering
+       the global copy is shared with other Milters. Also an
+       opportunity to clean up some ad-hoc code for sending macro
+       lists from smtp(8) to cleanup(8). Files: milter/milter.c,
+       milter/milter8.c, milter/milter_macros.c.
index 0693d58877c788ab83c5119dddc08c7f967a8115..8331022c5235e23e9b146fe486791831944b4c5f 100644 (file)
@@ -16,7 +16,7 @@
 /*     specified attribute scan routine. dsb_scan() is meant
 /*     to be passed as a call-back to attr_scan(), thusly:
 /*
-/*     ... ATTR_SCAN_FUNC, dsb_scan, (void *) &dsbuf, ...
+/*     ... ATTR_TYPE_FUNC, dsb_scan, (void *) &dsbuf, ...
 /* DIAGNOSTICS
 /*     Fatal: out of memory.
 /* LICENSE
index 9b21a6904a02e57d191c6b4f50fe1e0a1fa8b7b5..58f06a34c7728ecb967d90106560a5b21cd15bb8 100644 (file)
@@ -16,7 +16,7 @@
 /*     the specified attribute print routine. dsn_print() is meant
 /*     to be passed as a call-back to attr_print(), thusly:
 /*
-/*     ... ATTR_PRINT_FUNC, dsn_print, (void *) dsn, ...
+/*     ... ATTR_TYPE_FUNC, dsn_print, (void *) dsn, ...
 /* DIAGNOSTICS
 /*     Fatal: out of memory.
 /* LICENSE
index e6708f71a97c0dcacf2eafc0631b79e5699ba245..70c942d3cbc41d64d7669cb26bcedd0d02a1fc11 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20071222"
+#define MAIL_RELEASE_DATE      "20071223"
 #define MAIL_VERSION_NUMBER    "2.5"
 
 #ifdef SNAPSHOT
index 98d468dcde9116bbbe9daa30dcec3b00d5b09f76..f39b73c99cbeef98e561061174a5083e0899345f 100644 (file)
@@ -17,7 +17,7 @@
 /*     msg_stats_print() is meant to be passed as a call-back to
 /*     attr_print(), thusly:
 /*
-/*     ... ATTR_PRINT_FUNC, msg_stats_print, (void *) stats, ...
+/*     ... ATTR_TYPE_FUNC, msg_stats_print, (void *) stats, ...
 /* DIAGNOSTICS
 /*     Fatal: out of memory.
 /* LICENSE
index 3c8edddaddbe9d1cdfa0c17126a165cf8eb567f4..798929d84b7db9fb36962cfba615d04dba832c3d 100644 (file)
@@ -41,7 +41,7 @@
 /*     using the specified attribute scan routine. rcpb_scan()
 /*     is meant to be passed as a call-back to attr_scan(), thusly:
 /*
-/*     ... ATTR_SCAN_FUNC, rcpb_scan, (void *) rcpt_buf, ...
+/*     ... ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf, ...
 /*
 /*     rcpb_create(), rcpb_reset() and rcpb_free() create, wipe
 /*     and destroy recipient buffer instances.
index 985f42c3275124b8d32786756d014db44e529032..1c8b0cfa7f62ab8d70b85ada888951808760239d 100644 (file)
@@ -17,7 +17,7 @@
 /*     routine. rcpt_print() is meant to be passed as a call-back
 /*     to attr_print(), thusly:
 /*
-/*     ... ATTR_PRINT_FUNC, rcpt_print, (void *) recipient, ...
+/*     ... ATTR_TYPE_FUNC, rcpt_print, (void *) recipient, ...
 /* DIAGNOSTICS
 /*     Fatal: out of memory.
 /* LICENSE
index 3aba2663521ff8deeb0ace39ed3be2174cd55cbf..8bb27c08abdc6ccb10b21f3df7fb5756926f68dc 100644 (file)
@@ -1,6 +1,6 @@
 SHELL  = /bin/sh
-SRCS   = milter.c milter8.c
-OBJS   = milter.o milter8.o
+SRCS   = milter.c milter8.c milter_macros.c
+OBJS   = milter.o milter8.o milter_macros.o
 HDRS   = milter.h
 TESTSRC        = 
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -117,4 +117,15 @@ milter8.o: ../../include/vstream.h
 milter8.o: ../../include/vstring.h
 milter8.o: milter.h
 milter8.o: milter8.c
+milter_macros.o: ../../include/argv.h
+milter_macros.o: ../../include/attr.h
+milter_macros.o: ../../include/iostuff.h
+milter_macros.o: ../../include/mail_proto.h
+milter_macros.o: ../../include/mymalloc.h
+milter_macros.o: ../../include/sys_defs.h
+milter_macros.o: ../../include/vbuf.h
+milter_macros.o: ../../include/vstream.h
+milter_macros.o: ../../include/vstring.h
+milter_macros.o: milter.h
+milter_macros.o: milter_macros.c
 test-milter.o: test-milter.c
index e9024f721474219b03cbc6fc8a81e4de1ee02393..54871653d31c36a51a5f8d075d7e6551c3b4514b 100644 (file)
@@ -310,15 +310,27 @@ const char *milter_conn_event(MILTERS *milters,
 {
     const char *resp;
     MILTER *m;
-    ARGV   *macros;
+    ARGV   *global_macros = 0;
+    ARGV   *any_macros;
+
+#define MILTER_MACRO_EVAL(global_macros, m, milters, member) \
+       ((m->macros && m->macros->member[0]) ? \
+           milter_macro_lookup(milters, m->macros->member) : \
+               global_macros ? global_macros : \
+                   (global_macros = \
+                        milter_macro_lookup(milters, milters->macros->member)))
 
     if (msg_verbose)
        msg_info("report connect to all milters");
-    macros = milter_macro_lookup(milters, milters->conn_macros);
-    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
+    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+       any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, conn_macros);
        resp = m->conn_event(m, client_name, client_addr, client_port,
-                            addr_family, macros);
-    argv_free(macros);
+                            addr_family, any_macros);
+       if (any_macros != global_macros)
+           argv_free(any_macros);
+    }
+    if (global_macros)
+       argv_free(global_macros);
     return (resp);
 }
 
@@ -329,16 +341,19 @@ const char *milter_helo_event(MILTERS *milters, const char *helo_name,
 {
     const char *resp;
     MILTER *m;
-    ARGV   *macros;
+    ARGV   *global_macros = 0;
+    ARGV   *any_macros;
 
     if (msg_verbose)
        msg_info("report helo to all milters");
-    macros = milters->helo_macros == 0 ? 0 :
-       milter_macro_lookup(milters, milters->helo_macros);
-    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
-       resp = m->helo_event(m, helo_name, esmtp_flag, macros);
-    if (macros)
-       argv_free(macros);
+    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+       any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, helo_macros);
+       resp = m->helo_event(m, helo_name, esmtp_flag, any_macros);
+       if (any_macros != global_macros)
+           argv_free(any_macros);
+    }
+    if (global_macros)
+       argv_free(global_macros);
     return (resp);
 }
 
@@ -348,16 +363,19 @@ const char *milter_mail_event(MILTERS *milters, const char **argv)
 {
     const char *resp;
     MILTER *m;
-    ARGV   *macros;
+    ARGV   *global_macros = 0;
+    ARGV   *any_macros;
 
     if (msg_verbose)
        msg_info("report sender to all milters");
-    macros = milters->mail_macros == 0 ? 0 :
-       milter_macro_lookup(milters, milters->mail_macros);
-    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
-       resp = m->mail_event(m, argv, macros);
-    if (macros)
-       argv_free(macros);
+    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+       any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, mail_macros);
+       resp = m->mail_event(m, argv, any_macros);
+       if (any_macros != global_macros)
+           argv_free(any_macros);
+    }
+    if (global_macros)
+       argv_free(global_macros);
     return (resp);
 }
 
@@ -367,16 +385,19 @@ const char *milter_rcpt_event(MILTERS *milters, const char **argv)
 {
     const char *resp;
     MILTER *m;
-    ARGV   *macros;
+    ARGV   *global_macros = 0;
+    ARGV   *any_macros;
 
     if (msg_verbose)
        msg_info("report recipient to all milters");
-    macros = milters->rcpt_macros == 0 ? 0 :
-       milter_macro_lookup(milters, milters->rcpt_macros);
-    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
-       resp = m->rcpt_event(m, argv, macros);
-    if (macros)
-       argv_free(macros);
+    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+       any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, rcpt_macros);
+       resp = m->rcpt_event(m, argv, any_macros);
+       if (any_macros != global_macros)
+           argv_free(any_macros);
+    }
+    if (global_macros)
+       argv_free(global_macros);
     return (resp);
 }
 
@@ -384,26 +405,21 @@ const char *milter_rcpt_event(MILTERS *milters, const char **argv)
 
 const char *milter_data_event(MILTERS *milters)
 {
-    const char *myname = "milter_data_event";
     const char *resp;
     MILTER *m;
-    ARGV   *macros = 0;
+    ARGV   *global_macros = 0;
+    ARGV   *any_macros;
 
     if (msg_verbose)
        msg_info("report data to all milters");
     for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
-       if (m->data_event) {
-           if (macros == 0 && milters->data_macros)
-               macros = milter_macro_lookup(milters, milters->data_macros);
-           resp = m->data_event(m, macros);
-       } else {
-           if (msg_verbose)
-               msg_info("%s: skip milter %s (command unimplemented)",
-                        myname, m->name);
-       }
+       any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, data_macros);
+       resp = m->data_event(m, any_macros);
+       if (any_macros != global_macros)
+           argv_free(any_macros);
     }
-    if (macros)
-       argv_free(macros);
+    if (global_macros)
+       argv_free(global_macros);
     return (resp);
 }
 
@@ -411,26 +427,21 @@ const char *milter_data_event(MILTERS *milters)
 
 const char *milter_unknown_event(MILTERS *milters, const char *command)
 {
-    const char *myname = "milter_unknown_event";
     const char *resp;
     MILTER *m;
-    ARGV   *macros = 0;
+    ARGV   *global_macros = 0;
+    ARGV   *any_macros;
 
     if (msg_verbose)
        msg_info("report unknown command to all milters");
     for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
-       if (m->unknown_event) {
-           if (macros == 0 && milters->unk_macros)
-               macros = milter_macro_lookup(milters, milters->unk_macros);
-           resp = m->unknown_event(m, command, macros);
-       } else {
-           if (msg_verbose)
-               msg_info("%s: skip milter %s (command unimplemented)",
-                        myname, m->name);
-       }
+       any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, unk_macros);
+       resp = m->unknown_event(m, command, any_macros);
+       if (any_macros != global_macros)
+           argv_free(any_macros);
     }
-    if (macros)
-       argv_free(macros);
+    if (global_macros)
+       argv_free(global_macros);
     return (resp);
 }
 
@@ -454,21 +465,26 @@ const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset)
 {
     const char *resp;
     MILTER *m;
-    ARGV   *eoh_macros;
-    ARGV   *eod_macros;
+    ARGV   *global_eoh_macros = 0;
+    ARGV   *global_eod_macros = 0;
+    ARGV   *any_eoh_macros;
+    ARGV   *any_eod_macros;
 
     if (msg_verbose)
        msg_info("inspect content by all milters");
-    eoh_macros = milters->eoh_macros == 0 ? 0 :
-       milter_macro_lookup(milters, milters->eoh_macros);
-    eod_macros = milters->eod_macros == 0 ? 0 :
-       milter_macro_lookup(milters, milters->eod_macros);
-    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
-       resp = m->message(m, fp, data_offset, eoh_macros, eod_macros);
-    if (eoh_macros)
-       argv_free(eoh_macros);
-    if (eod_macros)
-       argv_free(eod_macros);
+    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
+       any_eoh_macros = MILTER_MACRO_EVAL(global_eoh_macros, m, milters, eoh_macros);
+       any_eod_macros = MILTER_MACRO_EVAL(global_eod_macros, m, milters, eod_macros);
+       resp = m->message(m, fp, data_offset, any_eoh_macros, any_eod_macros);
+       if (any_eoh_macros != global_eoh_macros)
+           argv_free(any_eoh_macros);
+       if (any_eod_macros != global_eod_macros)
+           argv_free(any_eod_macros);
+    }
+    if (global_eoh_macros)
+       argv_free(global_eoh_macros);
+    if (global_eod_macros)
+       argv_free(global_eod_macros);
     return (resp);
 }
 
@@ -496,22 +512,15 @@ void    milter_disc_event(MILTERS *milters)
        m->disc_event(m);
 }
 
-/* milter_create - create milter list */
-
-MILTERS *milter_create(const char *names,
-                              int conn_timeout,
-                              int cmd_timeout,
-                              int msg_timeout,
-                              const char *protocol,
-                              const char *def_action,
-                              const char *conn_macros,
-                              const char *helo_macros,
-                              const char *mail_macros,
-                              const char *rcpt_macros,
-                              const char *data_macros,
-                              const char *eoh_macros,
-                              const char *eod_macros,
-                              const char *unk_macros)
+/* milter_new - create milter list */
+
+MILTERS *milter_new(const char *names,
+                           int conn_timeout,
+                           int cmd_timeout,
+                           int msg_timeout,
+                           const char *protocol,
+                           const char *def_action,
+                           MILTER_MACROS *macros)
 {
     MILTERS *milters;
     MILTER *head = 0;
@@ -544,14 +553,7 @@ MILTERS *milter_create(const char *names,
     milters->milter_list = head;
     milters->mac_lookup = 0;
     milters->mac_context = 0;
-    milters->conn_macros = mystrdup(conn_macros);
-    milters->helo_macros = mystrdup(helo_macros);
-    milters->mail_macros = mystrdup(mail_macros);
-    milters->rcpt_macros = mystrdup(rcpt_macros);
-    milters->data_macros = mystrdup(data_macros);
-    milters->eoh_macros = mystrdup(eoh_macros);
-    milters->eod_macros = mystrdup(eod_macros);
-    milters->unk_macros = mystrdup(unk_macros);
+    milters->macros = macros;
     milters->add_header = 0;
     milters->upd_header = milters->ins_header = 0;
     milters->del_header = 0;
@@ -572,39 +574,11 @@ void    milter_free(MILTERS *milters)
        msg_info("free all milters");
     for (m = milters->milter_list; m != 0; m = next)
        next = m->next, m->free(m);
-    if (milters->conn_macros)
-       myfree(milters->conn_macros);
-    if (milters->helo_macros)
-       myfree(milters->helo_macros);
-    if (milters->mail_macros)
-       myfree(milters->mail_macros);
-    if (milters->rcpt_macros)
-       myfree(milters->rcpt_macros);
-    if (milters->rcpt_macros)
-       myfree(milters->data_macros);
-    if (milters->eoh_macros)
-       myfree(milters->eoh_macros);
-    if (milters->eod_macros)
-       myfree(milters->eod_macros);
-    if (milters->unk_macros)
-       myfree(milters->unk_macros);
+    if (milters->macros)
+       milter_macros_free(milters->macros);
     myfree((char *) milters);
 }
 
- /*
-  * Temporary protocol to send /receive milter instances. This needs to be
-  * extended with type information when we support both Sendmail8 and
-  * Sendmail X protocols.
-  */
-#define MAIL_ATTR_MILT_CONN    "conn_macros"
-#define MAIL_ATTR_MILT_HELO    "helo_macros"
-#define MAIL_ATTR_MILT_MAIL    "mail_macros"
-#define MAIL_ATTR_MILT_RCPT    "rcpt_macros"
-#define MAIL_ATTR_MILT_DATA    "data_macros"
-#define MAIL_ATTR_MILT_EOH     "eoh_macros"
-#define MAIL_ATTR_MILT_EOD     "eod_macros"
-#define MAIL_ATTR_MILT_UNK     "unk_macros"
-
 /* milter_dummy - send empty milter list */
 
 int     milter_dummy(MILTERS *milters, VSTREAM *stream)
@@ -640,14 +614,8 @@ int     milter_send(MILTERS *milters, VSTREAM *stream)
      * Send the filter macro names.
      */
     (void) attr_print(stream, ATTR_FLAG_MORE,
-                  ATTR_TYPE_STR, MAIL_ATTR_MILT_CONN, milters->conn_macros,
-                  ATTR_TYPE_STR, MAIL_ATTR_MILT_HELO, milters->helo_macros,
-                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAIL, milters->mail_macros,
-                  ATTR_TYPE_STR, MAIL_ATTR_MILT_RCPT, milters->rcpt_macros,
-                  ATTR_TYPE_STR, MAIL_ATTR_MILT_DATA, milters->data_macros,
-                     ATTR_TYPE_STR, MAIL_ATTR_MILT_EOH, milters->eoh_macros,
-                     ATTR_TYPE_STR, MAIL_ATTR_MILT_EOD, milters->eod_macros,
-                     ATTR_TYPE_STR, MAIL_ATTR_MILT_UNK, milters->unk_macros,
+                     ATTR_TYPE_FUNC, milter_macros_print,
+                     (void *) milters->macros,
                      ATTR_TYPE_END);
 
     /*
@@ -675,44 +643,12 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
     MILTER *head = 0;
     MILTER *tail = 0;
     MILTER *milter = 0;
-    VSTRING *conn_macros;
-    VSTRING *helo_macros;
-    VSTRING *mail_macros;
-    VSTRING *rcpt_macros;
-    VSTRING *data_macros;
-    VSTRING *eoh_macros;
-    VSTRING *eod_macros;
-    VSTRING *unk_macros;
+    MILTER_MACROS *macros = milter_macros_alloc(MILTER_MACROS_ALLOC_ZERO);
 
-    /*
-     * Receive filter macros.
-     */
-#define FREE_BUFFERS() do { \
-       vstring_free(conn_macros); vstring_free(helo_macros); \
-       vstring_free(mail_macros); vstring_free(rcpt_macros); \
-       vstring_free(data_macros); vstring_free(eoh_macros); \
-       vstring_free(eod_macros); vstring_free(unk_macros); \
-   } while (0)
-
-    conn_macros = vstring_alloc(10);
-    helo_macros = vstring_alloc(10);
-    mail_macros = vstring_alloc(10);
-    rcpt_macros = vstring_alloc(10);
-    data_macros = vstring_alloc(10);
-    eoh_macros = vstring_alloc(10);
-    eod_macros = vstring_alloc(10);
-    unk_macros = vstring_alloc(10);
     if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_CONN, conn_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_HELO, helo_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAIL, mail_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_RCPT, rcpt_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_DATA, data_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_EOH, eoh_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_EOD, eod_macros,
-                 ATTR_TYPE_STR, MAIL_ATTR_MILT_UNK, unk_macros,
-                 ATTR_TYPE_END) != 8) {
-       FREE_BUFFERS();
+                 ATTR_TYPE_FUNC, milter_macros_scan, (void *) macros,
+                 ATTR_TYPE_END) != 1) {
+       milter_macros_free(macros);
        return (0);
     }
 #define NO_MILTERS     ((char *) 0)
@@ -720,12 +656,7 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
 #define NO_PROTOCOL    ((char *) 0)
 #define NO_ACTION      ((char *) 0)
 
-    milters = milter_create(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION,
-                           STR(conn_macros), STR(helo_macros),
-                           STR(mail_macros), STR(rcpt_macros),
-                           STR(data_macros), STR(eoh_macros),
-                           STR(eod_macros), STR(unk_macros));
-    FREE_BUFFERS();
+    milters = milter_new(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION, macros);
 
     /*
      * Receive the filters.
index b47efb95978498ce3f547850742d3c93882c15dc..1f9b7f62920677d0d3888f828cb343529616d08b 100644 (file)
 #include <vstream.h>
 #include <argv.h>
 
+ /*
+  * Global library.
+  */
+#include <attr.h>
+
  /*
   * Each Milter handle is an element of a null-terminated linked list. The
   * functions are virtual so that we can support multiple MTA-side Milter
@@ -28,6 +33,7 @@ typedef struct MILTER {
     char   *name;                      /* full name including transport */
     struct MILTER *next;               /* linkage */
     struct MILTERS *parent;            /* parent information */
+    struct MILTER_MACROS *macros;      /* private macros */
     const char *(*conn_event) (struct MILTER *, const char *, const char *, const char *, unsigned, ARGV *);
     const char *(*helo_event) (struct MILTER *, const char *, int, ARGV *);
     const char *(*mail_event) (struct MILTER *, const char **, ARGV *);
@@ -46,6 +52,70 @@ typedef struct MILTER {
 extern MILTER *milter8_create(const char *, int, int, int, const char *, const char *, struct MILTERS *);
 extern MILTER *milter8_receive(VSTREAM *, struct MILTERS *);
 
+ /*
+  * As of Sendmail 8.14 each milter can override the default macro list. If a
+  * Milter has its own macro list, a null member means use the global
+  * definition.
+  */
+typedef struct MILTER_MACROS {
+    char   *conn_macros;               /* macros for connect event */
+    char   *helo_macros;               /* macros for HELO/EHLO command */
+    char   *mail_macros;               /* macros for MAIL FROM command */
+    char   *rcpt_macros;               /* macros for RCPT TO command */
+    char   *data_macros;               /* macros for DATA command */
+    char   *eoh_macros;                        /* macros for end-of-headers */
+    char   *eod_macros;                        /* macros for END-OF-DATA command */
+    char   *unk_macros;                        /* macros for unknown command */
+} MILTER_MACROS;
+
+extern MILTER_MACROS *milter_macros_create(const char *, const char *,
+                                                const char *, const char *,
+                                                const char *, const char *,
+                                               const char *, const char *);
+extern MILTER_MACROS *milter_macros_alloc(int);
+extern void milter_macros_free(MILTER_MACROS *);
+extern int milter_macros_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+extern int milter_macros_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+
+#define MILTER_MACROS_ALLOC_ZERO       1       /* null pointer */
+#define MILTER_MACROS_ALLOC_EMPTY      2       /* mystrdup(""); */
+
+#define milter_macros_wipe(mp) do { \
+       MILTER_MACROS *__mp = mp; \
+       if (__mp->conn_macros) \
+           myfree(__mp->conn_macros); \
+       if (__mp->helo_macros) \
+           myfree(__mp->helo_macros); \
+       if (__mp->mail_macros) \
+           myfree(__mp->mail_macros); \
+       if (__mp->rcpt_macros) \
+           myfree(__mp->rcpt_macros); \
+       if (__mp->data_macros) \
+           myfree(__mp->data_macros); \
+       if (__mp->eoh_macros) \
+           myfree(__mp->eoh_macros); \
+       if (__mp->eod_macros) \
+           myfree(__mp->eod_macros); \
+       if (__mp->unk_macros) \
+           myfree(__mp->unk_macros); \
+    } while (0)
+
+#define milter_macros_zero(mp) milter_macros_init(mp, 0)
+
+#define milter_macros_init(mp, expr) do { \
+       MILTER_MACROS *__mp = (mp); \
+       char *__expr = (expr); \
+       __mp->conn_macros = __expr; \
+       __mp->helo_macros = __expr; \
+       __mp->mail_macros = __expr; \
+       __mp->rcpt_macros = __expr; \
+       __mp->data_macros = __expr; \
+       __mp->eoh_macros = __expr; \
+       __mp->eod_macros = __expr; \
+       __mp->unk_macros = __expr; \
+    } while (0)
+
+
  /*
   * A bunch of Milters.
   */
@@ -60,14 +130,7 @@ typedef struct MILTERS {
     MILTER *milter_list;               /* linked list of Milters */
     MILTER_MAC_LOOKUP_FN mac_lookup;
     void   *mac_context;               /* macro lookup context */
-    char   *conn_macros;               /* macros for connect event */
-    char   *helo_macros;               /* macros for HELO/EHLO command */
-    char   *mail_macros;               /* macros for MAIL FROM command */
-    char   *rcpt_macros;               /* macros for RCPT TO command */
-    char   *data_macros;               /* macros for DATA command */
-    char   *eoh_macros;                        /* macros for end-of-headers */
-    char   *eod_macros;                        /* macros for END-OF-DATA command */
-    char   *unk_macros;                        /* macros for unknown command */
+    struct MILTER_MACROS *macros;
     void   *chg_context;               /* context for queue file changes */
     MILTER_ADD_HEADER_FN add_header;
     MILTER_EDIT_HEADER_FN upd_header;
@@ -78,12 +141,17 @@ typedef struct MILTERS {
     MILTER_EDIT_BODY_FN repl_body;
 } MILTERS;
 
-extern MILTERS *milter_create(const char *, int, int, int,
-                                     const char *, const char *,
-                                     const char *, const char *,
-                                     const char *, const char *,
-                                     const char *, const char *,
-                                     const char *, const char *);
+#define milter_create(milter_names, conn_timeout, cmd_timeout, msg_timeout, \
+                       protocol, def_action, conn_macros, helo_macros, \
+                       mail_macros, rcpt_macros, data_macros, eoh_macros, \
+                       eod_macros, unk_macros) \
+       milter_new(milter_names, conn_timeout, cmd_timeout, msg_timeout, \
+                   protocol, def_action, milter_macros_create(conn_macros, \
+                   helo_macros, mail_macros, rcpt_macros, data_macros, \
+                   eoh_macros, eod_macros, unk_macros))
+
+extern MILTERS *milter_new(const char *, int, int, int, const char *,
+                                  const char *, MILTER_MACROS *);
 extern void milter_macro_callback(MILTERS *, MILTER_MAC_LOOKUP_FN, void *);
 extern void milter_edit_callback(MILTERS *milters, MILTER_ADD_HEADER_FN,
                               MILTER_EDIT_HEADER_FN, MILTER_EDIT_HEADER_FN,
index 43d2d780065ba982bc7c29f07ecc3894166ee832..fc2cccc330568112a05a6a71de8b26872c541120 100644 (file)
@@ -322,17 +322,17 @@ static NAME_CODE smfim_table[] = {
   * members, without using a switch statement.
   */
 static size_t milter8_macro_offsets[] = {
-    offsetof(MILTERS, conn_macros),    /* SMFIM_CONNECT */
-    offsetof(MILTERS, helo_macros),    /* SMFIM_HELO */
-    offsetof(MILTERS, mail_macros),    /* SMFIM_ENVFROM */
-    offsetof(MILTERS, rcpt_macros),    /* SMFIM_ENVRCPT */
-    offsetof(MILTERS, data_macros),    /* SMFIM_DATA */
-    offsetof(MILTERS, eod_macros),     /* Note: SMFIM_EOM < SMFIM_EOH */
-    offsetof(MILTERS, eoh_macros),     /* Note: SMFIM_EOH > SMFIM_EOM */
+    offsetof(MILTER_MACROS, conn_macros),      /* SMFIM_CONNECT */
+    offsetof(MILTER_MACROS, helo_macros),      /* SMFIM_HELO */
+    offsetof(MILTER_MACROS, mail_macros),      /* SMFIM_ENVFROM */
+    offsetof(MILTER_MACROS, rcpt_macros),      /* SMFIM_ENVRCPT */
+    offsetof(MILTER_MACROS, data_macros),      /* SMFIM_DATA */
+    offsetof(MILTER_MACROS, eod_macros),/* Note: SMFIM_EOM < SMFIM_EOH */
+    offsetof(MILTER_MACROS, eoh_macros),/* Note: SMFIM_EOH > SMFIM_EOM */
 };
 
-#define MILTER8_MACRO_PTR(__milters, __type) \
-       ((char **) (((char *) (__milters)) + milter8_macro_offsets[(__type)]))
+#define MILTER8_MACRO_PTR(__macros, __type) \
+       ((char **) (((char *) (__macros)) + milter8_macro_offsets[(__type)]))
 
  /*
   * How much buffer space is available for sending body content.
@@ -1734,6 +1734,8 @@ static void milter8_connect(MILTER8 *milter)
        const char *smfim_name;
        char  **mac_value_ptr;
 
+       milter->m.macros = milter_macros_alloc(MILTER_MACROS_ALLOC_EMPTY);
+
        while (data_len > 0
               && milter8_read_data(milter, &data_len,
                                    MILTER8_DATA_HLONG, &mac_type,
@@ -1747,7 +1749,7 @@ static void milter8_connect(MILTER8 *milter)
                if (msg_verbose)
                    msg_info("override %s macro list with \"%s\"",
                             smfim_name, STR(buf));
-               mac_value_ptr = MILTER8_MACRO_PTR(milter->m.parent, mac_type);
+               mac_value_ptr = MILTER8_MACRO_PTR(milter->m.macros, mac_type);
                if (*mac_value_ptr != 0)
                    myfree(*mac_value_ptr);
                *mac_value_ptr = mystrdup(STR(buf));
@@ -2467,6 +2469,7 @@ static const char *milter8_message(MILTER *m, VSTREAM *qfile,
 #define MAIL_ATTR_MILT_CMD     "milter_cmd_timeout"
 #define MAIL_ATTR_MILT_MSG     "milter_msg_timeout"
 #define MAIL_ATTR_MILT_ACT     "milter_action"
+#define MAIL_ATTR_MILT_MAC     "milter_macro_list"
 
 /* milter8_active - report if this milter still wants events */
 
@@ -2489,7 +2492,7 @@ static int milter8_send(MILTER *m, VSTREAM *stream)
     if (msg_verbose)
        msg_info("%s: milter %s", myname, milter->m.name);
 
-    if (attr_print(stream, ATTR_FLAG_NONE,
+    if (attr_print(stream, ATTR_FLAG_MORE,
                   ATTR_TYPE_STR, MAIL_ATTR_MILT_NAME, milter->m.name,
                   ATTR_TYPE_INT, MAIL_ATTR_MILT_VERS, milter->version,
                   ATTR_TYPE_INT, MAIL_ATTR_MILT_ACTS, milter->rq_mask,
@@ -2500,7 +2503,16 @@ static int milter8_send(MILTER *m, VSTREAM *stream)
                   ATTR_TYPE_INT, MAIL_ATTR_MILT_CMD, milter->cmd_timeout,
                   ATTR_TYPE_INT, MAIL_ATTR_MILT_MSG, milter->msg_timeout,
                   ATTR_TYPE_STR, MAIL_ATTR_MILT_ACT, milter->def_action,
+                  ATTR_TYPE_INT, MAIL_ATTR_MILT_MAC, milter->m.macros != 0,
                   ATTR_TYPE_END) != 0
+       || (milter->m.macros != 0
+           && attr_print(stream, ATTR_FLAG_NONE,
+                         ATTR_TYPE_FUNC, milter_macros_print,
+                         (void *) milter->m.macros,
+                         ATTR_TYPE_END) != 0)
+       || (milter->m.macros == 0
+           && attr_print(stream, ATTR_FLAG_NONE,
+                         ATTR_TYPE_END) != 0)
        || vstream_fflush(stream) != 0) {
        return (-1);
 #ifdef CANT_WRITE_BEFORE_SENDING_FD
@@ -2524,7 +2536,7 @@ static int milter8_send(MILTER *m, VSTREAM *stream)
 }
 
 static MILTER8 *milter8_alloc(const char *, int, int, int, const char *,
-                                     const char *, MILTERS *);
+                                 const char *, MILTERS *);
 
 /* milter8_receive - receive milter instance */
 
@@ -2543,12 +2555,20 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent)
     int     cmd_timeout;
     int     msg_timeout;
     int     fd;
+    int     has_macros;
+    MILTER_MACROS *macros = 0;
+
+#define FREE_MACROS_AND_RETURN(x) do { \
+       if (macros) \
+           milter_macros_free(macros); \
+       return (x); \
+    } while (0)
 
     if (name_buf == 0) {
        name_buf = vstring_alloc(10);
        act_buf = vstring_alloc(10);
     }
-    if (attr_scan(stream, ATTR_FLAG_STRICT,
+    if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_NAME, name_buf,
                  ATTR_TYPE_INT, MAIL_ATTR_MILT_VERS, &version,
                  ATTR_TYPE_INT, MAIL_ATTR_MILT_ACTS, &rq_mask,
@@ -2559,22 +2579,32 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent)
                  ATTR_TYPE_INT, MAIL_ATTR_MILT_CMD, &cmd_timeout,
                  ATTR_TYPE_INT, MAIL_ATTR_MILT_MSG, &msg_timeout,
                  ATTR_TYPE_STR, MAIL_ATTR_MILT_ACT, act_buf,
-                 ATTR_TYPE_END) < 9) {
-       return (0);
+                 ATTR_TYPE_INT, MAIL_ATTR_MILT_MAC, &has_macros,
+                 ATTR_TYPE_END) < 10
+       || (has_macros != 0
+           && attr_scan(stream, ATTR_FLAG_STRICT,
+                        ATTR_TYPE_FUNC, milter_macros_scan,
+                        (void *) (macros =
+                            milter_macros_alloc(MILTER_MACROS_ALLOC_ZERO)),
+                        ATTR_TYPE_END) < 1)
+       || (has_macros == 0
+           && attr_scan(stream, ATTR_FLAG_STRICT,
+                        ATTR_TYPE_END) < 0)) {
+       FREE_MACROS_AND_RETURN(0);
 #ifdef CANT_WRITE_BEFORE_SENDING_FD
     } else if (attr_print(stream, ATTR_FLAG_NONE,
                          ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
                          ATTR_TYPE_END) != 0
               || vstream_fflush(stream) != 0) {
-       return (0);
+       FREE_MACROS_AND_RETURN(0);
 #endif
     } else if ((fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
-       return (0);
+       FREE_MACROS_AND_RETURN(0);
 #ifdef MUST_READ_AFTER_SENDING_FD
     } else if (attr_print(stream, ATTR_FLAG_NONE,
                          ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
                          ATTR_TYPE_END) != 0) {
-       return (0);
+       FREE_MACROS_AND_RETURN(0);
 #endif
     } else {
 #define NO_PROTOCOL    ((char *) 0)
@@ -2585,6 +2615,7 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent)
        milter = milter8_alloc(STR(name_buf), conn_timeout, cmd_timeout,
                            msg_timeout, NO_PROTOCOL, STR(act_buf), parent);
        milter->fp = vstream_fdopen(fd, O_RDWR);
+       milter->m.macros = macros;
        vstream_control(milter->fp, VSTREAM_CTL_DOUBLE, VSTREAM_CTL_END);
        /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */
        vstream_tweak_sock(milter->fp);
@@ -2615,6 +2646,8 @@ static void milter8_free(MILTER *m)
     myfree(milter->def_action);
     if (milter->def_reply)
        myfree(milter->def_reply);
+    if (milter->m.macros)
+       milter_macros_free(milter->m.macros);
     myfree((char *) milter);
 }
 
@@ -2635,6 +2668,7 @@ static MILTER8 *milter8_alloc(const char *name, int conn_timeout,
     milter->m.name = mystrdup(name);
     milter->m.next = 0;
     milter->m.parent = parent;
+    milter->m.macros = 0;
     milter->m.conn_event = milter8_conn_event;
     milter->m.helo_event = milter8_helo_event;
     milter->m.mail_event = milter8_mail_event;
@@ -2678,7 +2712,7 @@ MILTER *milter8_create(const char *name, int conn_timeout, int cmd_timeout,
      * Fill in the structure.
      */
     milter = milter8_alloc(name, conn_timeout, cmd_timeout, msg_timeout,
-                          protocol, def_action, parent);
+                        protocol, def_action, parent);
 
     /*
      * XXX Sendmail 8 libmilter closes the MTA-to-filter socket when it finds
diff --git a/postfix/src/milter/milter_macros.c b/postfix/src/milter/milter_macros.c
new file mode 100644 (file)
index 0000000..db5c36d
--- /dev/null
@@ -0,0 +1,247 @@
+/*++
+/* NAME
+/*     milter_macros
+/* SUMMARY
+/*     manipulate MILTER_MACROS structures
+/* SYNOPSIS
+/*     #include <milter.h>
+/*
+/*     MILTER_MACROS *milter_macros_create(conn_macros, helo_macros,
+/*                                     mail_macros, rcpt_macros,
+/*                                     data_macros, eoh_macros,
+/*                                     eod_macros, unk_macros)
+/*     const char *conn_macros;
+/*     const char *helo_macros;
+/*     const char *mail_macros;
+/*     const char *rcpt_macrps;
+/*     const char *data_macros;
+/*     const char *eoh_macros;
+/*     const char *eod_macros;
+/*     const char *unk_macros;
+/*
+/*     MILTER_MACROS *milter_macros_alloc(init_mode)
+/*     int     init_mode;
+/*
+/*     void    milter_macros_free(mp)
+/*     MILTER_MACROS *mp;
+/*
+/*     int     milter_macros_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/*
+/*     int     milter_macros_scan(scan_fn, fp, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *fp;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     Sendmail mail filter (Milter) applications receive sets of
+/*     macro (name=value) pairs with each SMTP or content event.
+/*     In Postfix, the lists of names are stored in MILTER_MACROS
+/*     structures. By default, the same structure is shared by all
+/*     Milter applications; it is initialized with information
+/*     from main.cf. With Sendmail 8.14 a Milter can override one
+/*     or more lists of macro names, and individual filters may
+/*     have their own partial list.
+/*
+/*     This module maintains the macro name lists as mystrdup()'ed
+/*     values. The user is explicitly allowed to update these
+/*     values directly, as long as they respect the mystrdup()
+/*     interface.
+/*
+/*     milter_macros_create() creates a MILTER_MACROS structure
+/*     and initializes it with copies of its string arguments.
+/*
+/*     milter_macros_alloc() creates a MILTER_MACROS structure
+/*     that is initialized according to its init_mode argument.
+/* .IP MILTER_MACROS_ALLOC_ZERO
+/*     Initialize all members as null pointers. This mode is
+/*     recommended for applications that use milter_macros_scan().
+/* .IP MILTER_MACROS_ALLOC_EMPTY
+/*     Initialize all members with mystrdup(""). This is not as
+/*     expensive as it appears to be. This mode is recommend for
+/*     applications that update individual MILTER_MACROS members
+/*     directly.
+/* .PP
+/*     milter_macros_free() destroys a MILTER_MACROS structure and
+/*     frees any strings referenced by it.
+/*
+/*     milter_macros_print() writes the contents of a MILTER_MACROS
+/*     structure to the named stream using the specified attribute
+/*     print routine. milter_macros_print() is meant to be passed
+/*     as a call-back to attr_print*(), thusly:
+/*
+/*     ATTR_TYPE_FUNC, milter_macros_print, (void *) macros,
+/*
+/*     milter_macros_scan() reads a MILTER_MACROS structure from
+/*     the named stream using the specified attribute scan routine.
+/*     milter_macros_scan() is meant to be passed as a call-back
+/*     to attr_scan*(), thusly:
+/*
+/*     ATTR_TYPE_FUNC, milter_macros_scan, (void *) macros,
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* 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>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <attr.h>
+#include <mymalloc.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <milter.h>
+
+ /*
+  * Ad-hoc protocol to send/receive milter macro name lists.
+  */
+#define MAIL_ATTR_MILT_MAC_CONN        "conn_macros"
+#define MAIL_ATTR_MILT_MAC_HELO        "helo_macros"
+#define MAIL_ATTR_MILT_MAC_MAIL        "mail_macros"
+#define MAIL_ATTR_MILT_MAC_RCPT        "rcpt_macros"
+#define MAIL_ATTR_MILT_MAC_DATA        "data_macros"
+#define MAIL_ATTR_MILT_MAC_EOH "eoh_macros"
+#define MAIL_ATTR_MILT_MAC_EOD "eod_macros"
+#define MAIL_ATTR_MILT_MAC_UNK "unk_macros"
+
+/* milter_macros_print - write recipient to stream */
+
+int     milter_macros_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+                                   int flags, void *ptr)
+{
+    MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
+    int     ret;
+
+    /*
+     * The attribute order does not matter, except that it must be the same
+     * as in the milter_macros_scan() function.
+     */
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_CONN, mp->conn_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_HELO, mp->helo_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_MAIL, mp->mail_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_RCPT, mp->rcpt_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_DATA, mp->data_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOH, mp->eoh_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOD, mp->eod_macros,
+                  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_UNK, mp->unk_macros,
+                  ATTR_TYPE_END);
+    return (ret);
+}
+
+/* milter_macros_scan - receive milter macro name list */
+
+int     milter_macros_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                                  int flags, void *ptr)
+{
+    MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
+    int     ret;
+    VSTRING *conn_macros = vstring_alloc(10);
+    VSTRING *helo_macros = vstring_alloc(10);
+    VSTRING *mail_macros = vstring_alloc(10);
+    VSTRING *rcpt_macros = vstring_alloc(10);
+    VSTRING *data_macros = vstring_alloc(10);
+    VSTRING *eoh_macros = vstring_alloc(10);
+    VSTRING *eod_macros = vstring_alloc(10);
+    VSTRING *unk_macros = vstring_alloc(10);
+
+    /*
+     * The attribute order does not matter, except that it must be the same
+     * as in the milter_macros_print() function.
+     */
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_CONN, conn_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_HELO, helo_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_MAIL, mail_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_RCPT, rcpt_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_DATA, data_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOH, eoh_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOD, eod_macros,
+                 ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_UNK, unk_macros,
+                 ATTR_TYPE_END);
+
+    /*
+     * Don't optimize for error.
+     */
+    mp->conn_macros = vstring_export(conn_macros);
+    mp->helo_macros = vstring_export(helo_macros);
+    mp->mail_macros = vstring_export(mail_macros);
+    mp->rcpt_macros = vstring_export(rcpt_macros);
+    mp->data_macros = vstring_export(data_macros);
+    mp->eoh_macros = vstring_export(eoh_macros);
+    mp->eod_macros = vstring_export(eod_macros);
+    mp->unk_macros = vstring_export(unk_macros);
+
+    return (ret == 8 ? 1 : -1);
+}
+
+/* milter_macros_create - create and initialize macros structure */
+
+MILTER_MACROS *milter_macros_create(const char *conn_macros,
+                                           const char *helo_macros,
+                                           const char *mail_macros,
+                                           const char *rcpt_macros,
+                                           const char *data_macros,
+                                           const char *eoh_macros,
+                                           const char *eod_macros,
+                                           const char *unk_macros)
+{
+    MILTER_MACROS *mp;
+
+    mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
+    mp->conn_macros = mystrdup(conn_macros);
+    mp->helo_macros = mystrdup(helo_macros);
+    mp->mail_macros = mystrdup(mail_macros);
+    mp->rcpt_macros = mystrdup(rcpt_macros);
+    mp->data_macros = mystrdup(data_macros);
+    mp->eoh_macros = mystrdup(eoh_macros);
+    mp->eod_macros = mystrdup(eod_macros);
+    mp->unk_macros = mystrdup(unk_macros);
+
+    return (mp);
+}
+
+/* milter_macros_alloc - allocate memory for structure with simple initialization */
+
+MILTER_MACROS *milter_macros_alloc(int mode)
+{
+    MILTER_MACROS *mp;
+
+    mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
+    switch (mode) {
+    case MILTER_MACROS_ALLOC_ZERO:
+       milter_macros_init(mp, 0);
+       break;
+    case MILTER_MACROS_ALLOC_EMPTY:
+       milter_macros_init(mp, mystrdup(""));
+       break;
+    default:
+       msg_panic("milter_macros_alloc: unknown mode %d", mode);
+    }
+    return (mp);
+}
+
+/* milter_macros_free - destroy memory for MILTER_MACROS structure */
+
+void    milter_macros_free(MILTER_MACROS *mp)
+{
+    milter_macros_wipe(mp);
+    myfree((char *) mp);
+}