aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2012-08-05 15:53:35 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2012-08-05 15:53:35 +0300
commit60eed8fc3bddfd7728d6e8d147636f853c3e3859 (patch)
tree6f79bf55faefd8add94c55fd3f8f66ed035e9476 /src
parent365cd1ef4cde229e19bbcad3c26f47d4d700376b (diff)
downloadmailfromd-60eed8fc3bddfd7728d6e8d147636f853c3e3859.tar.gz
mailfromd-60eed8fc3bddfd7728d6e8d147636f853c3e3859.tar.bz2
Implement functions for modifying headers addressed by their number.
Improve header renaming functions. * NEWS: Updated. * doc/functions.texi: Updated. * mflib/header_rename.mf4: Rewrite from scratch. * src/builtin/curhdr.bi (get_current_header): Remove, use env_get_header instead. All uses changed. * src/builtin/header.bi (header_delete_nth) (header_replace_nth): New built-ins. * src/builtin/snarf.m4 (MF_CAPTURE): Accept opional argument. All uses updated. * src/builtin/vars.bi (sendmail_header_count): New variable. (get_sendmail_header_count) (set_sendmail_header_count): New functions. * src/engine.c (message_data) <hdrtrans,hdrcount>: New members. (test_message_data_init,priv_get): Initialize hdrtrans and hdrcount. (priv_store_msgmod_closure): Name can be NULL. (filter_cleanup): Free hdrtrans. (run_msgmod) <header_insert>: Adjust header number by the value of sendmail_header_count variable. Handle header_replace_nth and header_delete_nth opcodes. * src/gram.y (msgmod_opcode_str): Handle header_replace_nth and header_delete_nth opcodes. * src/mailfromd.h (msgmod_opcode) <header_delete_nth> <header_replace_nth>: New opcodes. (get_sendmail_header_count) (set_sendmail_header_count) (env_get_header): New protos. * src/prog.c (eval_environ) <header>: New member. (env_capture_start): Initialize header. (env_get_header): New function. (env_msgmod): Name can be NULL. (destroy_environment): Destroy the header.
Diffstat (limited to 'src')
-rw-r--r--src/builtin/curhdr.bi149
-rw-r--r--src/builtin/header.bi32
-rw-r--r--src/builtin/snarf.m414
-rw-r--r--src/builtin/vars.bi15
-rw-r--r--src/engine.c141
-rw-r--r--src/gram.y9
-rw-r--r--src/mailfromd.h9
-rw-r--r--src/prog.c82
8 files changed, 329 insertions, 122 deletions
diff --git a/src/builtin/curhdr.bi b/src/builtin/curhdr.bi
index b1776b77..01192bdb 100644
--- a/src/builtin/curhdr.bi
+++ b/src/builtin/curhdr.bi
@@ -16,109 +16,25 @@
#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);
- free(chdr);
-}
-
-static void
-free_header(void *data)
-{
- struct current_header *chdr = data;
- mu_header_destroy(&chdr->hdr);
-}
-
-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, NULL);
- MF_ASSERT(rc == 0,
- mfe_failure,
- "mu_stream_seek: %s",
- mu_strerror(rc));
-
- /* FIXME: Use "header" filter instead of this loop */
- for (total = 0; total < size;) {
- size_t nrd;
-
- rc = mu_stream_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.
-
- The same effect could have been achieved by using
- streamref, but this approach speeds up things a
- bit.
- */
- 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);
- 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(mstr)
+MF_CAPTURE
MF_DEFUN(current_header_count, NUMBER, OPTIONAL, STRING name)
{
- mu_header_t hdr = get_current_header(env, mstr);
+ mu_header_t hdr;
size_t total;
size_t count;
- int rc = mu_header_get_field_count(hdr, &total);
+ int rc;
+
+ rc = env_get_header(env, &hdr);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "env_get_header: %s",
+ mu_strerror(rc));
+
+ rc = mu_header_get_field_count(hdr, &total);
MF_ASSERT(rc == 0,
mfe_failure,
@@ -143,12 +59,20 @@ END
MF_STATE(eoh)
MF_STATE(body)
MF_STATE(eom)
-MF_CAPTURE(mstr)
+MF_CAPTURE
MF_DEFUN(current_header_nth_name, STRING, NUMBER index)
{
- mu_header_t hdr = get_current_header(env, mstr);
+ mu_header_t hdr;
const char *sptr;
- int rc = mu_header_sget_field_name(hdr, index, &sptr);
+ int rc;
+
+ rc = env_get_header(env, &hdr);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "env_get_header: %s",
+ mu_strerror(rc));
+
+ rc = mu_header_sget_field_name(hdr, index, &sptr);
if (rc == MU_ERR_NOENT)
MF_THROW(mfe_not_found,
@@ -166,12 +90,20 @@ END
MF_STATE(eoh)
MF_STATE(body)
MF_STATE(eom)
-MF_CAPTURE(mstr)
+MF_CAPTURE
MF_DEFUN(current_header_nth_value, STRING, NUMBER index)
{
- mu_header_t hdr = get_current_header(env, mstr);
+ mu_header_t hdr;
const char *sptr;
- int rc = mu_header_sget_field_value(hdr, index, &sptr);
+ int rc;
+
+ rc = env_get_header(env, &hdr);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "env_get_header: %s",
+ mu_strerror(rc));
+
+ rc = mu_header_sget_field_value(hdr, index, &sptr);
if (rc == MU_ERR_NOENT)
MF_THROW(mfe_not_found,
@@ -189,13 +121,20 @@ END
MF_STATE(eoh)
MF_STATE(body)
MF_STATE(eom)
-MF_CAPTURE(mstr)
+MF_CAPTURE
MF_DEFUN(current_header, STRING, STRING name, OPTIONAL, NUMBER index)
{
- mu_header_t hdr = get_current_header(env, mstr);
+ mu_header_t hdr;
const char *sptr;
- int rc = mu_header_sget_value_n(hdr, name, MF_OPTVAL(index, 1),
- &sptr);
+ int rc;
+
+ rc = env_get_header(env, &hdr);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "env_get_header: %s",
+ mu_strerror(rc));
+
+ rc = mu_header_sget_value_n(hdr, name, MF_OPTVAL(index, 1), &sptr);
if (rc == MU_ERR_NOENT)
MF_THROW(mfe_not_found,
diff --git a/src/builtin/header.bi b/src/builtin/header.bi
index 9e30800b..07fd530e 100644
--- a/src/builtin/header.bi
+++ b/src/builtin/header.bi
@@ -70,6 +70,22 @@ MF_DEFUN(header_delete, VOID, STRING name, OPTIONAL, NUMBER idx)
}
END
+MF_CAPTURE
+MF_DEFUN(header_delete_nth, VOID, NUMBER idx)
+{
+ struct locus locus;
+
+ env_get_locus(env, &locus);
+
+ trace("%s%s:%lu: %s %lu",
+ mailfromd_msgid(env_get_context(env)),
+ locus.file, locus.line,
+ msgmod_opcode_str(header_delete_nth),
+ idx);
+ env_msgmod(env, header_delete_nth, NULL, NULL, idx);
+}
+END
+
MF_DEFUN(header_replace, VOID, STRING name, STRING value, OPTIONAL, NUMBER idx)
{
struct locus locus;
@@ -85,4 +101,20 @@ MF_DEFUN(header_replace, VOID, STRING name, STRING value, OPTIONAL, NUMBER idx)
}
END
+MF_CAPTURE
+MF_DEFUN(header_replace_nth, VOID, NUMBER idx, STRING name, STRING value)
+{
+ struct locus locus;
+
+ env_get_locus(env, &locus);
+
+ trace("%s%s:%lu: %s \"%s: %s\" (%lu)",
+ mailfromd_msgid(env_get_context(env)),
+ locus.file, locus.line,
+ msgmod_opcode_str(header_replace_nth),
+ name, value, idx);
+ env_msgmod(env, header_replace_nth, name, value, idx);
+}
+END
+
MF_INIT
diff --git a/src/builtin/snarf.m4 b/src/builtin/snarf.m4
index 71bffd36..2c64a755 100644
--- a/src/builtin/snarf.m4
+++ b/src/builtin/snarf.m4
@@ -338,11 +338,14 @@ m4_define([<MF_STATE>],
[<m4_define([<__MF_STATE__>],__MF_STATE__[< | STATMASK(smtp_state_$1)>])>],m4_dnl
[<m4_define([<__MF_STATE__>],[<STATMASK(smtp_state_$1)>])>])>])
-/* MF_CAPTURE(str) - Declare next MF_DEFUN as requiring message capturing.
- Store a reference to the capture stream in STR.
+/* MF_CAPTURE([str]) - Declare next MF_DEFUN as requiring message capturing.
+ The form with the STR argument can be used only in MF_STATE(eom)
+ functions (FIXME: this should be enforced at compile time). In that
+ case a reference to the capture stream is stored in STR.
*/
-m4_define([<MF_CAPTURE>],
-[<m4_ifdef([<__MF_CAPTURE__>],,[<m4_define([<__MF_CAPTURE__>],[<$1>])>])>])
+m4_define([<MF_CAPTURE>],m4_dnl
+[<m4_define([<__MF_NEEDS_CAPTURE__>],1)m4_dnl
+m4_ifelse([<$1>],,,[<m4_define([<__MF_CAPTURE__>],[<$1>])>])>])
/* env_get_stream - prohibit the use of the library function of the same name.
*/
@@ -395,7 +398,7 @@ va_builtin_install_ex("$2", bi_$2,m4_dnl
__mf_argtype($3),m4_dnl
mf_argcount(m4_shift(m4_shift(m4_shift($@)))),m4_dnl
mf_optcount(m4_shift(m4_shift(m4_shift($@)))),m4_dnl
- m4_ifdef([<__MF_CAPTURE__>],[<MFD_BUILTIN_CAPTURE>],0)|$1,m4_dnl
+ m4_ifdef([<__MF_NEEDS_CAPTURE__>],[<MFD_BUILTIN_CAPTURE>],0)|$1,m4_dnl
mf_typelist(m4_shift(m4_shift(m4_shift($@)))));
m4_divert(2)m4_dnl
{m4_ifdef([<__MF_CAPTURE__>],[<
@@ -670,6 +673,7 @@ m4_popdef([<__MF_FUNCTION__>])m4_dnl
m4_popdef([<__MF_ARGLIST__>])m4_dnl
m4_popdef([<__MF_VARARGS__>])m4_dnl
m4_undefine([<__MF_CAPTURE__>])m4_dnl
+m4_undefine([<__MF_NEEDS_CAPTURE__>])m4_dnl
m4_undefine([<__MF_STATE__>])m4_dnl
m4_undefine([<__MF_ENDLAB__>])m4_dnl
m4_define([<__mf_dataseg>])m4_dnl
diff --git a/src/builtin/vars.bi b/src/builtin/vars.bi
index 8c23f292..60b3e12b 100644
--- a/src/builtin/vars.bi
+++ b/src/builtin/vars.bi
@@ -21,7 +21,8 @@ MF_VAR(milter_client_address, STRING, SYM_PRECIOUS);
MF_VAR(milter_server_family, NUMBER, SYM_PRECIOUS);
MF_VAR(milter_server_address, STRING, SYM_PRECIOUS);
MF_VAR(milter_server_id, STRING, SYM_PRECIOUS);
-
+MF_VAR(sendmail_header_count, NUMBER, SYM_PRECIOUS);
+
/* Functions to access %rcpt_count */
unsigned long
get_rcpt_count(eval_environ_t env)
@@ -41,6 +42,18 @@ incr_rcpt_count(eval_environ_t env)
MF_VAR_INC(rcpt_count);
}
+/* Same for sendmail_header_count */
+unsigned long
+get_sendmail_header_count(eval_environ_t env)
+{
+ return (long) MF_VAR_REF(sendmail_header_count);
+}
+
+void
+set_sendmail_header_count(eval_environ_t env, unsigned long v)
+{
+ MF_VAR_REF(sendmail_header_count, v);
+}
/* define_milter_address name */
m4_define([<define_milter_address>],[<
diff --git a/src/engine.c b/src/engine.c
index 424549cb..18b0b6b4 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -47,11 +47,25 @@ static void ctx_msgmod(void *data, struct msgmod_closure *cmd);
/* Per-message data */
+/* Header translation table is used to translate absolute header number
+ into Sendmail notation (name, idx), where name is the header name and
+ idx is 1-based number of occurrence of the header with that name.
+
+ This translation is needed for two functions provided by Mailfromd:
+ header_delete_nth and header_replace_nth.
+*/
+struct hdrtrans {
+ const char *name;
+ size_t idx;
+};
+
struct message_data {
eval_environ_t env; /* Evaluation environment */
mu_list_t mmq; /* Message Modification Queue */
char *helostr; /* Domain name obtained in HELO phase */
- char msgid[64]; /* Message ID */
+ char msgid[64]; /* Message ID */
+ struct hdrtrans *hdrtrans; /* Header translation table */
+ size_t hdrcount; /* No. of entries in hdrtrans */
};
static struct message_data *test_message_data;
@@ -63,6 +77,8 @@ test_message_data_init(eval_environ_t env)
test_message_data->mmq = NULL;
test_message_data->helostr = NULL;
test_message_data->msgid[0] = 0;
+ test_message_data->hdrtrans = NULL;
+ test_message_data->hdrcount = 0;
}
static struct message_data *
@@ -92,6 +108,8 @@ priv_get(SMFICTX *ctx)
md->mmq = NULL;
md->helostr = NULL;
md->msgid[0] = 0;
+ md->hdrtrans = NULL;
+ md->hdrcount = 0;
gacopyz_setpriv(ctx, md);
env_init(md->env);
if (gacopyz_server_sockname(ctx, &addr, &len) == 0)
@@ -156,7 +174,7 @@ priv_store_msgmod_closure(SMFICTX *ctx, struct msgmod_closure *cmd)
mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE5,
("adding msgmod_closure: %s \"%s\" %s %u",
msgmod_opcode_str(cmd->opcode),
- cmd->name, SP(cmd->value), cmd->idx));
+ SP(cmd->name), SP(cmd->value), cmd->idx));
mu_list_append(md->mmq, cmd);
return 0;
}
@@ -263,6 +281,7 @@ filter_cleanup(SMFICTX *ctx)
free(md->helostr);
destroy_environment(md->env);
mu_list_destroy(&md->mmq);
+ free(md->hdrtrans);
free(md);
gacopyz_setpriv(ctx, NULL);
}
@@ -597,15 +616,68 @@ xlate_and_replace_body(SMFICTX *ctx, const char *value, size_t size)
}
static int
+md_hdrtrans_fill(struct message_data *md)
+{
+ int rc;
+ mu_header_t hdr;
+ size_t count, i, j;
+
+ if (env_get_header(md->env, &hdr))
+ return 1;
+ rc = mu_header_get_field_count(hdr, &count);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR,
+ "mu_header_get_field_count",
+ NULL, rc);
+ return 1;
+ }
+ md->hdrtrans = xcalloc(count, sizeof(md->hdrtrans[0]));
+ for (i = 1; i <= count; i++) {
+ const char *s;
+ rc = mu_header_sget_field_name(hdr, i, &s);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR,
+ "mu_header_sget_field_name",
+ NULL, rc);
+ return 1;
+ }
+ md->hdrtrans[i-1].name = s;
+ md->hdrtrans[i-1].idx = 1;
+ for (j = i - 1; j > 0; j--)
+ if (mu_c_strcasecmp(md->hdrtrans[j-1].name, s) == 0) {
+ md->hdrtrans[i-1].idx =
+ md->hdrtrans[j-1].idx + 1;
+ break;
+ }
+ }
+ md->hdrcount = count;
+ return 0;
+}
+
+static int
+md_hdrtrans(struct message_data *md, struct msgmod_closure *hdr)
+{
+ if (!md->hdrtrans && md_hdrtrans_fill(md))
+ return -1;
+ if (hdr->idx == 0 || hdr->idx > md->hdrcount)
+ return 1;
+ hdr->name = (char*) md->hdrtrans[hdr->idx - 1].name;
+ hdr->idx = md->hdrtrans[hdr->idx - 1].idx;
+ return 0;
+}
+
+static int
run_msgmod(void *item, void *data)
{
- struct msgmod_closure *hdr = item;
+ struct msgmod_closure *hdr = item, thdr;
SMFICTX *ctx = data;
-
+ struct message_data *md;
+
mu_debug(MF_SOURCE_ENGINE, MU_DEBUG_TRACE6,
("%s %s: %s %u",
msgmod_opcode_str(hdr->opcode),
- hdr->name, SP(hdr->value), hdr->idx));
+ SP(hdr->name), SP(hdr->value), hdr->idx));
+
switch (hdr->opcode) {
case header_add:
gacopyz_add_header(ctx, hdr->name, hdr->value);
@@ -620,7 +692,25 @@ run_msgmod(void *item, void *data)
break;
case header_insert:
- gacopyz_insert_header(ctx, hdr->idx, hdr->name, hdr->value);
+ /* Note: The get_sendmail_header_count() call returns the
+ number of headers defined by Sendmail (or other MTA) itself.
+ I have found no reliable method allowing to determine
+ that number automatically. In the absence of such method,
+ the user has to define the header count explicitly, by
+ setting the sendmail_header_count variable. For Sendmail,
+ a good estimate is given by the following command:
+
+ grep -c ^H /etc/mail/sendmail.cf
+
+ Notice, however, that some of the headers may be defined
+ conditionally, see the section 5.5. "H -- Define Header",
+ in the Sendmail(tm) Installation and Operation Guide, for
+ more information.
+ */
+ md = priv_get(ctx);
+ gacopyz_insert_header(ctx,
+ hdr->idx + get_sendmail_header_count(md->env),
+ hdr->name, hdr->value);
break;
case rcpt_add:
@@ -637,6 +727,45 @@ run_msgmod(void *item, void *data)
case body_repl:
xlate_and_replace_body(ctx, hdr->value, strlen(hdr->value));
+ break;
+
+ case header_replace_nth:
+ md = priv_get(ctx);
+ thdr = *hdr;
+ switch (md_hdrtrans(md, &thdr)) {
+ case -1:
+ return 1;
+ case 1:
+ return 0;
+ default:
+ break;
+ }
+ /* Remove old header */
+ gacopyz_change_header(ctx, thdr.idx, thdr.name, NULL);
+ /* Insert the new one. For the meaning of
+ get_sendmail_header_count, see the comment to the
+ header_insert case above.
+ */
+ gacopyz_insert_header(ctx,
+ hdr->idx + get_sendmail_header_count(md->env),
+ hdr->name, hdr->value);
+ break;
+
+ case header_delete_nth:
+ thdr = *hdr;
+ switch (md_hdrtrans(priv_get(ctx), &thdr)) {
+ case -1:
+ return 1;
+ case 1:
+ return 0;
+ default:
+ break;
+ }
+ gacopyz_change_header(ctx, thdr.idx, thdr.name, NULL);
+ break;
+
+ default:
+ abort();
}
return 0;
}
diff --git a/src/gram.y b/src/gram.y
index 65ad9162..7e40daec 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -3243,6 +3243,13 @@ msgmod_opcode_str(enum msgmod_opcode opcode)
case body_repl:
return "REPLACE BODY";
+
+ case header_replace_nth:
+ return "REPLACE NTH HEADER";
+
+ case header_delete_nth:
+ return "DELETE NTH HEADER";
+
}
return "UNKNOWN HEADER COMMAND";
}
@@ -3268,7 +3275,7 @@ dbg_msgmod(void *data, struct msgmod_closure *clos)
printf("clearing msgmod list\n");
else
printf("%s %s: %s %u\n", msgmod_opcode_str(clos->opcode),
- clos->name, SP(clos->value), clos->idx);
+ SP(clos->name), SP(clos->value), clos->idx);
}
static const char *
diff --git a/src/mailfromd.h b/src/mailfromd.h
index df336cad..02307056 100644
--- a/src/mailfromd.h
+++ b/src/mailfromd.h
@@ -245,7 +245,9 @@ enum msgmod_opcode { /* Message modification operation */
rcpt_add, /* Add a recipient */
rcpt_delete, /* Delete a recipient */
quarantine, /* Quarantine a message */
- body_repl, /* Replace message body */
+ body_repl, /* Replace message body */
+ header_delete_nth, /* Delete Nth header */
+ header_replace_nth /* Replace Nth header */
};
struct msgmod_closure {
@@ -785,6 +787,10 @@ extern prog_counter_t entry_point[smtp_state_count];
unsigned long get_rcpt_count(eval_environ_t env);
void clear_rcpt_count(eval_environ_t env);
void incr_rcpt_count(eval_environ_t env);
+
+unsigned long get_sendmail_header_count(eval_environ_t env);
+void set_sendmail_header_count(eval_environ_t env, unsigned long v);
+
void set_last_poll_helo(eval_environ_t env, const char *text);
void set_last_poll_greeting(eval_environ_t env, const char *text);
void set_last_poll_host(eval_environ_t env, const char *host_addr);
@@ -852,6 +858,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);
int env_get_stream(eval_environ_t env, mu_stream_t *pstr);
+int env_get_header(eval_environ_t env, mu_header_t *hdr);
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);
diff --git a/src/prog.c b/src/prog.c
index ce7cbee3..6d527ca8 100644
--- a/src/prog.c
+++ b/src/prog.c
@@ -288,6 +288,8 @@ struct eval_environ {
size_t line_count; /* Number of lines in stream */
int reposition; /* When !0, stream must be repositioned to
its end before writing. */
+ mu_header_t header; /* Headers from stream, converted to a MU
+ object. */
/* Non-local exits */
struct exception_context *defcatch_ctx;
@@ -2420,7 +2422,7 @@ env_capture_start(eval_environ_t env)
if (env->stream) {
/* Drop any previously captured message data */
env_free_captured(env);
-
+ mu_header_destroy(&env->header);
/* Truncate existing stream and reposition to its
beginning */
rc = mu_stream_truncate(env->stream, 0);
@@ -2519,6 +2521,78 @@ env_capture_write_args(eval_environ_t env, ...)
return rc;
}
+int
+env_get_header(eval_environ_t env, mu_header_t *hdr)
+{
+ if (!env->header) {
+ char *text;
+ int rc;
+ mu_off_t size;
+ size_t total;
+ size_t start;
+
+ rc = mu_stream_size(env->stream, &size);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_size", NULL,
+ rc);
+ return rc;
+ }
+ text = xmalloc(size + 1);
+ rc = mu_stream_seek(env->stream, 0, SEEK_SET, NULL);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_seek",
+ NULL, rc);
+ free(text);
+ return rc;
+ }
+
+ /* FIXME: Use "header" filter instead of this loop */
+ for (total = 0; total < size;) {
+ size_t nrd;
+
+ rc = mu_stream_read(env->stream, text + total,
+ size - total, &nrd);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR,
+ "mu_stream_read",
+ NULL, rc);
+ free(text);
+ return rc;
+ }
+ if (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.
+
+ The same effect could have been achieved by using
+ streamref, but this approach speeds up things a
+ bit.
+ */
+ env_reposition(env);
+
+ if (memcmp (text, "From ", 5) == 0)
+ start = strcspn (text, "\n") + 1;
+ else
+ start = 0;
+ rc = mu_header_create(&env->header, text + start,
+ total - start);
+ free(text);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "mu_header_create",
+ NULL, rc);
+ return rc;
+ }
+ }
+ *hdr = env->header;
+ return 0;
+}
+
void
env_clear_msgmod(eval_environ_t env)
{
@@ -2536,10 +2610,11 @@ env_msgmod(eval_environ_t env, enum msgmod_opcode opcode,
if (PROG_TRACE_ENGINE)
prog_trace(env, "Registering %s \"%s\" \"%s\" %u",
- msgmod_opcode_str(opcode), name, SP(value), idx);
+ msgmod_opcode_str(opcode), SP(name), SP(value),
+ idx);
cp->opcode = opcode;
- cp->name = xstrdup(name);
+ cp->name = name ? xstrdup(name) : NULL;
cp->value = value ? xstrdup(value) : NULL;
cp->idx = idx;
env->msgmod(env->data, cp);
@@ -2694,6 +2769,7 @@ destroy_environment(eval_environ_t env)
free(env->dataseg);
free(env->matches);
mu_stream_destroy(&env->stream);
+ mu_header_destroy(&env->header);
mu_list_destroy(&env->cleanup_list);
env_builtin_priv_destroy(env);
free(env);

Return to:

Send suggestions and report system problems to the System administrator.