aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS38
-rw-r--r--doc/mailfromd.texi62
-rw-r--r--mfd/Makefile.am1
-rw-r--r--mfd/bi_curhdr.m4212
-rw-r--r--mfd/bi_mbox.m47
-rw-r--r--mfd/bi_msg.m426
-rw-r--r--mfd/mailfromd.h1
-rw-r--r--mfd/msg.h1
-rw-r--r--mfd/prog.c47
-rw-r--r--mfd/prog.h4
-rw-r--r--mfd/snarf.m46
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/accept.at4
-rw-r--r--tests/arg.at4
-rw-r--r--tests/atlocal.in3
-rw-r--r--tests/curmsg.at2
-rw-r--r--tests/etc/Makefile.am2
-rw-r--r--tests/etc/hdr.mts26
-rw-r--r--tests/etc/hdr2.mts48
-rw-r--r--tests/hdr-all.at47
-rw-r--r--tests/hdr-cap.at80
-rw-r--r--tests/hdr-count.at37
-rw-r--r--tests/hdr-get.at39
-rw-r--r--tests/hdr-gete.at38
-rw-r--r--tests/hdr-getn.at41
-rw-r--r--tests/hdr-itr.at44
-rw-r--r--tests/hdr-mul.at100
-rw-r--r--tests/numrcpt.at4
-rw-r--r--tests/reject.at4
-rw-r--r--tests/tempfail.at4
-rw-r--r--tests/testsuite.at30
31 files changed, 930 insertions, 40 deletions
diff --git a/NEWS b/NEWS
index 9db425d8..c79dfa7d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Mailfromd NEWS -- history of user-visible changes. 2009-05-08
+Mailfromd NEWS -- history of user-visible changes. 2009-05-09
Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -24,6 +24,42 @@ is not strictly necessary. However, keep in mind that due to the
specifics of MeTA1, the number of symbols that may be exported for
each stage is limited (Mailfromd manual, section 11.1.2).
+* New functions
+
+A set of new functions is added that allow to access the headers
+from the current message in a uniform fashion. These functions are
+available in the following handlers: eoh, body, eom.
+
+- number current_header_count([string name])
+
+Return number of headers in the current message. With an argument -
+return number of headers that have this name.
+
+- string current_header_nth_name(number n)
+
+Return the name of the nth header. N is 1-based.
+
+- string current_header_nth_value(number n)
+
+Return the value of the nth header. N is 1-based.
+
+- string current_header(string name[, number index])
+
+Return the value of the named header, e.g.:
+
+ set s current_header("Subject")
+
+Optional second argument specifies the header instance, if there are
+more than 1 header of the same name, e.g.:
+
+ set s current_header("Received", 2)
+
+
+Index is 1-based.
+
+All current_header functions raise the e_not_found exception if the
+requested header is not found.
+
* New pragma `dbprop'
This pragma defines user database properties. It takes two or three
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index 8390fbea..0d171ab0 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -232,6 +232,7 @@ Built-in and Library Functions
* Body Modification Functions::
* Mail header functions::
* Mail body functions::
+* Current Message Functions::
* Mailbox functions::
* Message functions::
* Quarantine functions::
@@ -301,6 +302,17 @@ Command Line Options.
* daemon mode::
* option summary::
+A universal socket-map program for MeTA1.
+
+* smap-conf:: Smap Configuration.
+* smap-invoke:: Smap Command Line Arguments.
+* smap-examples:: Examples of Using Smap
+
+Smap Examples
+
+* smap-userdb:: Configure local_user_map.
+* smap-aliases:: Configure aliases.
+
Pmilter multiplexer program.
* pmult configuration::
@@ -5838,6 +5850,7 @@ in version @value{VERSION}.
* Body Modification Functions::
* Mail header functions::
* Mail body functions::
+* Current Message Functions::
* Mailbox functions::
* Message functions::
* Quarantine functions::
@@ -6589,6 +6602,9 @@ a @code{body} handler to a regular @acronym{MFL} string. For more
information about its use, see @ref{body handler}.
@end deftypefn
+@node Current Message Functions
+@subsubsection Current Message Functions
+
@anchor{current_message}
@deftypefn {Built-in Function} number current_message ()
This function can be used in @code{eom} handlers only. It returns a
@@ -6596,6 +6612,52 @@ message descriptor referring to the current message. @xref{Message
functions}, for a description of functions for accessing messages.
@end deftypefn
+The functions below access the headers from the current message. They
+are available in the following handlers: @code{eoh}, @code{body}, @code{eom}.
+
+@deftypefn {Built-in Function} number current_header_count ([string @var{name}])
+
+Return number of headers in the current message. If @var{name}
+is specified, return number of headers that have this name.
+
+@smallexample
+ current_header_count() @result{} 6
+ current_header_count("Subject") @result{} 6
+@end smallexample
+@end deftypefn
+
+@deftypefn {Built-in Function} string current_header_nth_name (number @var{n})
+
+Return the name of the @var{n}th header. The index @var{n} is 1-based.
+@end deftypefn
+
+@deftypefn {Built-in Function} string current_header_nth_value (number @var{n})
+
+Return the value of the @var{n}th header. The index @var{n} is
+1-based.
+@end deftypefn
+
+@deftypefn {Built-in Function} string current_header (string name @
+ [, number @var{n}])
+Return the value of the named header, e.g.:
+
+@smallexample
+ set s current_header("Subject")
+@end smallexample
+
+Optional second argument specifies the header instance, if there are
+more than 1 header of the same name, e.g.:
+
+@smallexample
+ set s current_header("Received", 2)
+@end smallexample
+
+Header indices are 1-based.
+@end deftypefn
+
+All current_header function raise the @code{e_not_found} exception if the
+requested header is not found.
+
@node Mailbox functions
@subsubsection Mailbox Functions
@cindex mailbox functions
diff --git a/mfd/Makefile.am b/mfd/Makefile.am
index 700e51cf..03c2fca3 100644
--- a/mfd/Makefile.am
+++ b/mfd/Makefile.am
@@ -22,6 +22,7 @@ inc_DATA = status.mfh
M4_FILES=\
bi_body.m4\
bi_ctype.m4\
+ bi_curhdr.m4\
bi_db.m4\
bi_dns.m4\
bi_getopt.m4\
diff --git a/mfd/bi_curhdr.m4 b/mfd/bi_curhdr.m4
new file mode 100644
index 00000000..1472131e
--- /dev/null
+++ b/mfd/bi_curhdr.m4
@@ -0,0 +1,212 @@
+/* This file is part of Mailfromd. -*- c -*-
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "msg.h"
+
+struct current_header {
+ mu_header_t hdr;
+};
+
+static void *
+alloc_header()
+{
+ return xzalloc(sizeof(struct current_header));
+}
+
+static void
+destroy_header(void *data)
+{
+ struct current_header *chdr = data;
+ mu_header_destroy(&chdr->hdr, NULL);
+ free(chdr);
+}
+
+static void
+free_header(void *data)
+{
+ struct current_header *chdr = data;
+ mu_header_destroy(&chdr->hdr, NULL);
+}
+
+MF_DECLARE_DATA(HEADER, alloc_header, destroy_header, free_header)
+
+static mu_header_t
+get_current_header(eval_environ_t env, mu_stream_t mstr)
+{
+ struct current_header *chdr = MF_GET_DATA;
+ if (!chdr->hdr) {
+ mu_header_t hdr;
+ char *text;
+ int rc;
+ mu_off_t size;
+ size_t total;
+ size_t start;
+
+ rc = mu_stream_size (mstr, &size);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_stream_size: %s",
+ mu_strerror (rc));
+ text = malloc (size + 1);
+ MF_ASSERT(text != NULL,
+ mfe_failure,
+ _("Not enough memory"));
+ rc = mu_stream_seek(mstr, 0, SEEK_SET);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_stream_seek: %s",
+ mu_strerror(rc));
+
+ for (total = 0; total < size;) {
+ size_t nrd;
+
+ rc = mu_stream_sequential_read(mstr,
+ text + total,
+ size - total, &nrd);
+ if (rc || nrd == 0)
+ break;
+ total += nrd;
+ }
+ text[total] = 0;
+
+ /* FIXME: Reposition the stream at its end.
+ This call may happen in the middle of capturing
+ so I have to make sure to not disturb the capturing
+ process.
+ FIXME: MU: The env_reposition call is a kludge
+ necessary because MU stream interface does not offer
+ mu_stream_tell function.
+ */
+ env_reposition(env);
+
+ if (memcmp (text, "From ", 5) == 0)
+ start = strcspn (text, "\n") + 1;
+ else
+ start = 0;
+ rc = mu_header_create (&hdr, text + start, total - start,
+ NULL);
+ free(text);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_header_create: %s",
+ mu_strerror (rc));
+ chdr->hdr = hdr;
+ }
+ return chdr->hdr;
+}
+
+/* number current_header_count([string name]) */
+MF_STATE(eoh)
+MF_STATE(body)
+MF_STATE(eom)
+MF_CAPTURE
+MF_DEFUN(current_header_count, NUMBER, OPTIONAL, STRING name)
+{
+ mu_header_t hdr = get_current_header(env, env_get_stream(env));
+ size_t total;
+ size_t count;
+ int rc = mu_header_get_field_count (hdr, &total);
+
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_header_get_field_count: %s",
+ mu_strerror (rc));
+ if (MF_DEFINED(name)) {
+ size_t i;
+ count = 0;
+ for (i = 1; i <= total; i++) {
+ const char *sptr;
+ if (mu_header_sget_field_name(hdr, i, &sptr) == 0
+ && strcasecmp(sptr, name) == 0)
+ count++;
+ }
+ } else
+ count = total;
+ MF_RETURN(count);
+}
+END
+
+/* string current_header_nth_name(number index) */
+MF_STATE(eoh)
+MF_STATE(body)
+MF_STATE(eom)
+MF_CAPTURE
+MF_DEFUN(current_header_nth_name, STRING, NUMBER index)
+{
+ mu_header_t hdr = get_current_header(env, env_get_stream(env));
+ const char *sptr;
+ int rc = mu_header_sget_field_name(hdr, index, &sptr);
+
+ if (rc == MU_ERR_NOENT)
+ MF_THROW(mfe_not_found,
+ _("requested item (#%ld) not found"),
+ index);
+ else if (rc != 0)
+ MF_THROW(mfe_failure,
+ "mu_header_sget_field_name: %s",
+ mu_strerror(rc));
+ MF_RETURN_STRING(sptr);
+}
+END
+
+/* string current_header_nth_value(number index) */
+MF_STATE(eoh)
+MF_STATE(body)
+MF_STATE(eom)
+MF_CAPTURE
+MF_DEFUN(current_header_nth_value, STRING, NUMBER index)
+{
+ mu_header_t hdr = get_current_header(env, env_get_stream(env));
+ const char *sptr;
+ int rc = mu_header_sget_field_value(hdr, index, &sptr);
+
+ if (rc == MU_ERR_NOENT)
+ MF_THROW(mfe_not_found,
+ _("requested item (#%ld) not found"),
+ index);
+ else if (rc != 0)
+ MF_THROW(mfe_failure,
+ "mu_header_sget_field_name: %s",
+ mu_strerror(rc));
+ MF_RETURN_STRING(sptr);
+}
+END
+
+/* string current_header(string name[, number index]) */
+MF_STATE(eoh)
+MF_STATE(body)
+MF_STATE(eom)
+MF_CAPTURE
+MF_DEFUN(current_header, STRING, STRING name, OPTIONAL, NUMBER index)
+{
+ mu_header_t hdr = get_current_header(env, env_get_stream(env));
+ const char *sptr;
+ int rc = mu_header_sget_value_n(hdr, name, MF_OPTVAL(index, 1),
+ &sptr);
+
+ if (rc == MU_ERR_NOENT)
+ MF_THROW(mfe_not_found,
+ _("requested item (%s,%ld) not found"),
+ name, MF_OPTVAL(index, 1));
+ else if (rc != 0)
+ MF_THROW(mfe_failure,
+ "mu_header_sget_field_name: %s",
+ mu_strerror(rc));
+ MF_RETURN_STRING(sptr);
+}
+END
+
+MF_INIT
diff --git a/mfd/bi_mbox.m4 b/mfd/bi_mbox.m4
index f21dcf9d..5a6b0d54 100644
--- a/mfd/bi_mbox.m4
+++ b/mfd/bi_mbox.m4
@@ -117,6 +117,13 @@ MF_DEFUN(mailbox_open, NUMBER, STRING url, OPTIONAL, STRING mode, STRING perms)
}
}
+ /* FIXME: MU: This is ridiculous! */
+ if ((flags & (MU_STREAM_READ|MU_STREAM_WRITE))
+ == (MU_STREAM_READ|MU_STREAM_WRITE)) {
+ flags &= ~(MU_STREAM_READ|MU_STREAM_WRITE);
+ flags |= MU_STREAM_RDWR;
+ }
+
if (MF_DEFINED(perms)) {
/* If MU_STREAM_IRGRP is defined, the remaining three
permissions flags are defined as well.
diff --git a/mfd/bi_msg.m4 b/mfd/bi_msg.m4
index 43882435..b788992d 100644
--- a/mfd/bi_msg.m4
+++ b/mfd/bi_msg.m4
@@ -33,7 +33,19 @@ destroy_msgs(void *data)
free(mtab);
}
-MF_DECLARE_DATA(MSGTAB, alloc_msgs, destroy_msgs)
+void
+drop_current_message(void *data)
+{
+ int i;
+ struct mf_message *tab = data;
+ for (i = 0; i < NMSGS; i++)
+ if (tab[i].msg && tab[i].current) {
+ bi_close_message(&tab[i]);
+ break;
+ }
+}
+
+MF_DECLARE_DATA(MSGTAB, alloc_msgs, destroy_msgs, drop_current_message)
static int
find_slot(struct mf_message *tab)
@@ -96,18 +108,6 @@ bi_get_current_message(eval_environ_t env)
return -1;
}
-void
-bi_drop_current_message(eval_environ_t env)
-{
- int i;
- struct mf_message *tab = MF_GET_DATA;
- for (i = 0; i < NMSGS; i++)
- if (tab[i].msg && tab[i].current) {
- bi_close_message(&tab[i]);
- break;
- }
-}
-
m4_define([<DCL_MSG>],[<
struct mf_message *mtab = MF_GET_DATA;
diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h
index a45bf346..ac93cba4 100644
--- a/mfd/mailfromd.h
+++ b/mfd/mailfromd.h
@@ -804,6 +804,7 @@ const char *environment_get_null_symbol(eval_environ_t env,
SMFICTX *env_get_context(eval_environ_t env);
size_t env_get_line_count(eval_environ_t env);
mu_stream_t env_get_stream(eval_environ_t env);
+void env_reposition(eval_environ_t env);
int env_capture_start(eval_environ_t env);
int env_capture_write(eval_environ_t env, const char *buf, size_t size);
int env_capture_write_args(eval_environ_t env, ...);
diff --git a/mfd/msg.h b/mfd/msg.h
index de9b55d1..a62ec6b2 100644
--- a/mfd/msg.h
+++ b/mfd/msg.h
@@ -41,5 +41,4 @@ void bi_close_message(struct mf_message *msg);
int bi_message_register(eval_environ_t env, mu_list_t list, mu_message_t msg,
int current);
int bi_get_current_message(eval_environ_t env);
-void bi_drop_current_message(eval_environ_t env);
mu_message_t bi_message_from_descr(eval_environ_t env, int md);
diff --git a/mfd/prog.c b/mfd/prog.c
index 5ab7b110..3c92a9a7 100644
--- a/mfd/prog.c
+++ b/mfd/prog.c
@@ -280,6 +280,8 @@ struct eval_environ {
mu_stream_t stream; /* Capture stream */
size_t line_count; /* Number of lines in stream */
+ int reposition; /* When !0, stream must be repositioned to
+ its end before writing. */
/* Non-local exits */
prog_counter_t defcatch[mf_exception_count];
@@ -357,6 +359,12 @@ env_get_reg(eval_environ_t env)
return env->reg;
}
+void
+env_reposition(eval_environ_t env)
+{
+ env->reposition = 1;
+}
+
/* A call to expand_dataseg (see below) invalidates any C variables that
pointed to the dataseg before the call. To avoid dereferencing invalid
@@ -2138,8 +2146,8 @@ env_capture_start(eval_environ_t env)
env->line_count = 0;
if (env->stream) {
- /* Drop any previously registered current message */
- bi_drop_current_message(env);
+ /* Drop any previously captured message data */
+ env_free_captured(env);
/* Truncate existing stream and reposition to its
beginning */
@@ -2152,7 +2160,8 @@ env_capture_start(eval_environ_t env)
mu_stream_destroy(&env->stream,
mu_stream_get_owner(env->stream));
}
-
+ env->reposition = 0;
+
rc = mu_temp_file_stream_create(&env->stream, NULL);
if (rc) {
mu_error(_("%sCannot create temporary stream: %s"),
@@ -2189,12 +2198,27 @@ env_capture_count_lines(eval_environ_t env, const char *buf, size_t size)
int
env_capture_write(eval_environ_t env, const char *buf, size_t size)
{
+ int rc;
+
if (!env->stream)
return 1;
+
+ if (env->reposition) {
+ rc = mu_stream_seek(env->stream, 0, SEEK_END);
+ if (rc) {
+ mu_error(_("%sTemporary stream seek failed: %s"),
+ mailfromd_msgid(env->ctx),
+ mu_strerror(rc));
+ mu_stream_close(env->stream);
+ mu_stream_destroy(&env->stream,
+ mu_stream_get_owner(env->stream));
+ return rc;
+ }
+ env->reposition = 0;
+ }
env_capture_count_lines(env, buf, size);
while (size) {
- int rc;
size_t len = mem_search(buf, '\r', size);
rc = mu_stream_sequential_write(env->stream, buf, len);
if (rc) {
@@ -2253,6 +2277,7 @@ env_msgmod(eval_environ_t env, enum msgmod_opcode opcode,
struct builtin_priv { /* Built-in private data structure */
void *(*init)();
void (*destroy)(void*);
+ int (*free_capture)(void*);
};
static size_t builtin_priv_size;
@@ -2266,7 +2291,8 @@ builtin_priv_destroy(void *ptr)
}
int
-builtin_priv_register(void *(*init)(), void (*destroy)(void*))
+builtin_priv_register(void *(*init)(), void (*destroy)(void*),
+ void (*free_capture))
{
struct builtin_priv *p;
int desc;
@@ -2283,9 +2309,20 @@ builtin_priv_register(void *(*init)(), void (*destroy)(void*))
p = bi_priv + builtin_priv_count++;
p->init = init;
p->destroy = destroy ? destroy : builtin_priv_destroy;
+ p->free_capture = free_capture;
return desc;
}
+void
+env_free_captured(eval_environ_t env)
+{
+ int i;
+
+ for (i = 0; i < builtin_priv_count; i++)
+ if (bi_priv[i].free_capture && env->bi_priv_array[i])
+ bi_priv[i].free_capture(env->bi_priv_array[i]);
+}
+
void *
env_get_builtin_priv(eval_environ_t env, int id)
{
diff --git a/mfd/prog.h b/mfd/prog.h
index e8a14ef1..c0d4ffbc 100644
--- a/mfd/prog.h
+++ b/mfd/prog.h
@@ -55,7 +55,9 @@ STKVAL env_get_reg(eval_environ_t env);
char *env_vaptr(eval_environ_t env, size_t off);
void *env_get_builtin_priv(eval_environ_t env, int id);
-int builtin_priv_register(void *(*init)(void), void (*destroy)(void*));
+int builtin_priv_register(void *(*init)(void), void (*destroy)(void*),
+ void (*free_capture));
+void env_free_captured(eval_environ_t env);
void ensure_initialized_variable(const char *name, struct value *val);
diff --git a/mfd/snarf.m4 b/mfd/snarf.m4
index 7b8f2dd8..f6cf59ef 100644
--- a/mfd/snarf.m4
+++ b/mfd/snarf.m4
@@ -517,18 +517,20 @@ m4_define([<MF_VAR_SET_STRING>],[<
m4_define([<MF_VAR_INC>],[<m4_dnl
env_var_inc(env, $1_loc)>])
-/* MF_DECLARE_DATA(name, init [, destr]) - Declare private data for
+/* MF_DECLARE_DATA(name, init [, destr, freecap]) - Declare private data for
* the current module.
* NAME - data identifier.
* INIT - initialization function (void init(void))
* DESTR - destructor function (void destr(void*))
+ * FREECAP - free capture function (void freecap(void*))
*/
m4_define([<MF_DECLARE_DATA>],[<
m4_define([<__MF_PRIV_ID__>],$1_id)
static int __MF_PRIV_ID__;
m4_divert(1)m4_dnl
__MF_PRIV_ID__ = builtin_priv_register($2, m4_dnl
-m4_ifelse($3,,NULL,$3));
+m4_ifelse($3,,NULL,$3),
+m4_ifelse($4,,NULL,$4));
m4_divert(0)m4_dnl
>])
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 25118260..e68992ab 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -67,6 +67,14 @@ TESTSUITE_AT = \
greylist.at\
greylist-ct.at\
hasmx.at\
+ hdr-all.at\
+ hdr-cap.at\
+ hdr-count.at\
+ hdr-get.at\
+ hdr-gete.at\
+ hdr-getn.at\
+ hdr-itr.at\
+ hdr-mul.at\
hostname.at\
invip.at\
invip2.at\
diff --git a/tests/accept.at b/tests/accept.at
index c96a80ec..2f10e6e7 100644
--- a/tests/accept.at
+++ b/tests/accept.at
@@ -1,5 +1,5 @@
# This file is part of Mailfromd testsuite. -*- Autotest -*-
-# Copyright (C) 2007, 2008 Sergey Poznyakoff
+# Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
AT_SETUP([Accept action])
AT_KEYWORDS([actions accept])
-AT_MTA_TEST([accept.rc],
+AT_MTA_TEST_FILTER([accept.rc],
[
\E250
HELO localhost
diff --git a/tests/arg.at b/tests/arg.at
index 231eeb4a..dfc246f7 100644
--- a/tests/arg.at
+++ b/tests/arg.at
@@ -1,5 +1,5 @@
# This file is part of Mailfromd testsuite. -*- Autotest -*-
-# Copyright (C) 2007, 2008 Sergey Poznyakoff
+# Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
AT_SETUP([Function arguments])
AT_KEYWORDS([arg])
-AT_MTA_TEST([arg.rc],
+AT_MTA_TEST_FILTER([arg.rc],
[
\E250
HELO localhost
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 29ebba77..00f865ae 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -1,6 +1,6 @@
# @configure_input@ -*- shell-script -*-
# Configurable variable values for tar test suite.
-# Copyright (C) 2007, 2008 Sergey Poznyakoff
+# Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
PATH=@abs_builddir@:@abs_top_builddir@/mfd:@abs_top_builddir@/mtasim:@abs_top_srcdir@/build-aux:$top_srcdir:$srcdir:$PATH
@@ -23,6 +23,7 @@ cleanup() {
trap "cleanup; test -r $XFAILFILE && cat $XFAILFILE; exit $?" 1 2 13 15
MFOPTS="-I@abs_builddir@ -I@abs_builddir@/etc -I@abs_top_srcdir@/tests/etc -I@abs_top_srcdir@/mfd -I@abs_top_srcdir@/mflib --no-preprocess --no-site-rcfile --no-user-rcfile"
+TESTDIR=@abs_builddir@
ETCDIR=@abs_top_srcdir@/tests/etc
PORT="unix:$STATEDIR/socket"
diff --git a/tests/curmsg.at b/tests/curmsg.at
index b473e454..f7ee81d9 100644
--- a/tests/curmsg.at
+++ b/tests/curmsg.at
@@ -26,7 +26,7 @@ AT_SETUP([Working current_message])
AT_KEYWORDS([curmsg])
AT_WITH_MAILFROMD_OPTIONS([--stderr],[
-AT_MTA_TEST([size.rc],[
+AT_MTA_TEST_FILTER([size.rc],[
\E250
HELO localhost
\E250
diff --git a/tests/etc/Makefile.am b/tests/etc/Makefile.am
index f529f0bd..51a8fee1 100644
--- a/tests/etc/Makefile.am
+++ b/tests/etc/Makefile.am
@@ -46,7 +46,7 @@ RCFILES=\
var.rc
noinst_DATA = $(RCFILES) config.rc
-EXTRA_DIST=config.in relayed.list $(RCFILES)
+EXTRA_DIST=config.in relayed.list hdr.mts hdr2.mts $(RCFILES)
CLEANFILES = config.rc
$(RCFILES): Makefile
diff --git a/tests/etc/hdr.mts b/tests/etc/hdr.mts
new file mode 100644
index 00000000..34e4e196
--- /dev/null
+++ b/tests/etc/hdr.mts
@@ -0,0 +1,26 @@
+\E250
+HELO localhost
+\E250
+MAIL FROM:<gray@gnu.org.ua>
+\E250
+RCPT TO:<gray@localhost>
+\E354
+DATA
+Received: foo
+Received: bar
+From: Sergey Poznyakoff <gray@gnu.org.ua>
+To: gray@localhost
+Subject: Amsterdam (1)
+
+ Dans le port d'Amsterdam
+ Y a des marins qui chantent
+ Les rêves qui les hantent
+ Au large d'Amsterdam
+ Dans le port d'Amsterdam
+ Y a des marins qui dorment
+ Comme des oriflammes
+ Le long des berges mornes
+.
+\E221
+QUIT
+
diff --git a/tests/etc/hdr2.mts b/tests/etc/hdr2.mts
new file mode 100644
index 00000000..787502c5
--- /dev/null
+++ b/tests/etc/hdr2.mts
@@ -0,0 +1,48 @@
+\E250
+HELO localhost
+\E250
+MAIL FROM:<gray@gnu.org.ua>
+\E250
+RCPT TO:<gray@localhost>
+\E354
+DATA
+Received: foo
+Received: bar
+From: Sergey Poznyakoff <gray@gnu.org.ua>
+To: gray@localhost
+Subject: Amsterdam (1)
+
+ Dans le port d'Amsterdam
+ Y a des marins qui chantent
+ Les rêves qui les hantent
+ Au large d'Amsterdam
+ Dans le port d'Amsterdam
+ Y a des marins qui dorment
+ Comme des oriflammes
+ Le long des berges mornes
+.
+\E250
+MAIL FROM:<gray@gnu.org.ua>
+\E250
+RCPT TO:<gray@localhost>
+\E354
+DATA
+Received: foo
+Received: bar
+Received: quux
+From: Sergey Poznyakoff <gray@gnu.org.ua>
+To: gray@localhost
+Subject: Amsterdam (2)
+
+ Dans le port d'Amsterdam
+ Y a des marins qui meurent
+ Pleins de bière et de drames
+ Aux premières lueurs
+ Mais dans le port d'Amsterdam
+ Y a des marins qui naissent
+ Dans la chaleur épaisse
+ Des langueurs océanes
+.
+\E221
+QUIT
+
diff --git a/tests/hdr-all.at b/tests/hdr-all.at
new file mode 100644
index 00000000..ccb412cf
--- /dev/null
+++ b/tests/hdr-all.at
@@ -0,0 +1,47 @@
+# This file is part of Mailfromd testsuite. -*- Autotest -*-
+# Copyright (C) 2009 Sergey Poznyakoff
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP(current_header(name,ind) - iteration over all)
+AT_KEYWORDS([curhdr current_header_a])
+
+AT_WITH_MAILFROMD_OPTIONS([--stderr --gacopyz-log=err],[
+AT_MTA_TEST_SCRIPT([
+prog eoh
+do
+ number limit current_header_count()
+ loop for number i 1,
+ while %i <= %limit,
+ set i %i + 1
+ do
+ echo current_header_nth_name(%i) ": " current_header_nth_value(%i)
+ done
+done
+],
+[hdr.mts],
+[0],
+[],
+[mailfromd: mailfromd (AT_PACKAGE_TARNAME AT_PACKAGE_VERSION) started
+Received: foo
+Received: bar
+From: Sergey Poznyakoff <gray@gnu.org.ua>
+To: gray@localhost
+Subject: Amsterdam (1)
+mailfromd: mailfromd terminating
+])
+])
+
+AT_CLEANUP
+
diff --git a/tests/hdr-cap.at b/tests/hdr-cap.at
new file mode 100644
index 00000000..7cfbe7d8
--- /dev/null
+++ b/