summaryrefslogtreecommitdiff
path: root/libmailutils
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-08-01 11:35:55 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-08-01 11:42:53 +0300
commit2843c4054207db33a1237a6991143564c086b3d2 (patch)
tree6df6529a91862b19809e5a781cd6cca61bcae3f9 /libmailutils
parent9bf6ea3758f5516f2c2b10945ffd345540698225 (diff)
downloadmailutils-2843c4054207db33a1237a6991143564c086b3d2.tar.gz
mailutils-2843c4054207db33a1237a6991143564c086b3d2.tar.bz2
New function for reconstructing the message envelope from its headers.
* libmailutils/address/parse822.c (mu_parse822_route_addr): Accept <local-part-only> if the default domain is set. * include/mailutils/message.h (mu_message_reconstruct_envelope): New prototype. * libmailutils/mailbox/msgenv.c (message_envelope_sender): Try each candidate header in turn until a valid email is extracted or run out of headers. In the latter case, use the current user login name as the email. (mu_message_reconstruct_envelope): New function. * libmailutils/tests/Makefile.am: Add new test. * libmailutils/tests/testsuite.at: Likewise. * libmailutils/tests/recenv.c: Test program for the mu_message_reconstruct_envelope function * libmailutils/tests/recenv.at: New test.
Diffstat (limited to 'libmailutils')
-rw-r--r--libmailutils/address/parse822.c23
-rw-r--r--libmailutils/mailbox/msgenv.c121
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am2
-rw-r--r--libmailutils/tests/recenv.at56
-rw-r--r--libmailutils/tests/recenv.c52
-rw-r--r--libmailutils/tests/testsuite.at1
7 files changed, 218 insertions, 38 deletions
diff --git a/libmailutils/address/parse822.c b/libmailutils/address/parse822.c
index 8094c5e87..ef37219dd 100644
--- a/libmailutils/address/parse822.c
+++ b/libmailutils/address/parse822.c
@@ -999,7 +999,26 @@ mu_parse822_route_addr (const char **p, const char *e, mu_address_t *a,
mu_parse822_route (p, e, &route);
- if ((rc = mu_parse822_addr_spec (p, e, a, hint, hflags)))
+ rc = mu_parse822_addr_spec (p, e, a, hint, hflags);
+ if (rc == EPARSE && (hflags & MU_ADDR_HINT_DOMAIN))
+ {
+ /*
+ * Although not allowed by RFC, a local part alone sometimes
+ * appears between '<' and '>' (notably, in the Return-Path
+ * header). Accept such addresses, if the default domain is
+ * set in hints.
+ */
+ char *local_part = NULL;
+ rc = mu_parse822_local_part (p, e, &local_part);
+ if (rc == EOK && (rc = mu_parse822_special (p, e, '>')) == EOK)
+ {
+ rc = fill_mb (a, 0, 0, local_part, NULL, hint, hflags);
+ if (rc == EOK)
+ return rc;
+ }
+ }
+
+ if (rc != EOK)
{
*p = save;
@@ -1107,7 +1126,7 @@ mu_parse822_addr_spec (const char **p, const char *e, mu_address_t *a,
if (!rc)
{
rc = mu_parse822_special (p, e, '@');
-
+
if (!rc)
{
rc = mu_parse822_domain (p, e, &domain);
diff --git a/libmailutils/mailbox/msgenv.c b/libmailutils/mailbox/msgenv.c
index 92bf1ed29..b26ffb156 100644
--- a/libmailutils/mailbox/msgenv.c
+++ b/libmailutils/mailbox/msgenv.c
@@ -74,7 +74,7 @@ get_received_date (mu_message_t msg, struct tm *tm, struct mu_timezone *tz)
return rc;
}
-
+
static int
message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
@@ -138,6 +138,21 @@ message_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
return rc;
}
+static inline void
+save_return (char const *value, char *buf, size_t len, size_t *pnwrite)
+{
+ size_t n = strlen (value);
+ if (buf && len > 0)
+ {
+ len--; /* One for the null. */
+ n = (n < len) ? n : len;
+ memcpy (buf, value, n);
+ buf[n] = '\0';
+ }
+ if (pnwrite)
+ *pnwrite = n;
+}
+
static int
message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
size_t *pnwrite)
@@ -146,7 +161,7 @@ message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
mu_header_t header;
int status;
const char *sender;
- struct mu_auth_data *auth = NULL;
+ struct mu_auth_data *auth;
static char *hdrnames[] = {
"Return-Path",
"X-Envelope-Sender",
@@ -155,7 +170,8 @@ message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
"From",
NULL
};
- mu_address_t address = NULL;
+ int i;
+ int save_i = -1;
if (msg == NULL)
return EINVAL;
@@ -164,43 +180,80 @@ message_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
status = mu_message_get_header (msg, &header);
if (status)
return status;
- status = mu_header_sget_firstof (header, hdrnames, &sender, NULL);
- if (status)
+
+ for (i = 0; hdrnames[i]; i++)
{
- auth = mu_get_auth_by_uid (getuid ());
- if (!auth)
- return MU_ERR_NOENT;
- sender = auth->name;
+ mu_address_t address;
+ status = mu_header_sget_value (header, hdrnames[i], &sender);
+ if (status == MU_ERR_NOENT)
+ continue;
+ else if (status)
+ {
+ mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
+ ("mu_header_sget_value(%s): %s",
+ hdrnames[i], mu_strerror (status)));
+ continue;
+ }
+
+ status = mu_address_create (&address, sender);
+ if (status == MU_ERR_INVALID_EMAIL)
+ {
+ if (save_i == -1)
+ save_i = i;
+ continue;
+ }
+ else if (status)
+ {
+ mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
+ ("mu_address_create(%s): %s",
+ sender, mu_strerror (status)));
+ continue;
+ }
+
+ status = mu_address_sget_email (address, 1, &sender);
+ if (status)
+ {
+ mu_debug (MU_DEBCAT_MESSAGE, MU_DEBUG_ERROR,
+ ("mu_address_sget_email(%s): %s",
+ address->printable, mu_strerror (status)));
+ mu_address_destroy (&address);
+ continue;
+ }
+ save_return (sender, buf, len, pnwrite);
+ mu_address_destroy (&address);
+ return 0;
}
- status = mu_address_create (&address, sender);
- if (status == 0)
+ if (save_i)
{
- status = mu_address_sget_email (address, 1, &sender);
+ status = mu_header_sget_value (header, hdrnames[save_i], &sender);
if (status == 0)
{
- if (sender == NULL)
- status = MU_ERR_NOENT;
- else
- {
- size_t n = strlen (sender);
- if (buf && len > 0)
- {
- len--; /* One for the null. */
- n = (n < len) ? n : len;
- memcpy (buf, sender, n);
- buf[n] = '\0';
- }
- if (pnwrite)
- *pnwrite = n;
- }
+ save_return (sender, buf, len, pnwrite);
+ return 0;
}
- mu_address_destroy (&address);
}
-
- if (auth)
- mu_auth_data_free (auth);
+ auth = mu_get_auth_by_uid (getuid ());
+ if (!auth)
+ return MU_ERR_NOENT;
+ save_return (auth->name, buf, len, pnwrite);
+ mu_auth_data_free (auth);
+
+ return 0;
+}
+
+int
+mu_message_reconstruct_envelope (mu_message_t msg, mu_envelope_t *penv)
+{
+ mu_envelope_t env;
+ int status = mu_envelope_create (&env, msg);
+ if (status == 0)
+ {
+ mu_envelope_set_sender (env, message_envelope_sender, msg);
+ mu_envelope_set_date (env, message_envelope_date, msg);
+ *penv = env;
+ }
return status;
}
@@ -214,13 +267,9 @@ mu_message_get_envelope (mu_message_t msg, mu_envelope_t *penvelope)
if (msg->envelope == NULL)
{
- mu_envelope_t envelope;
- int status = mu_envelope_create (&envelope, msg);
+ int status = mu_message_reconstruct_envelope (msg, &msg->envelope);
if (status != 0)
return status;
- mu_envelope_set_sender (envelope, message_envelope_sender, msg);
- mu_envelope_set_date (envelope, message_envelope_date, msg);
- msg->envelope = envelope;
}
*penvelope = msg->envelope;
return 0;
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index 9262a0bf9..82c19c765 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -53,3 +53,4 @@ xscript
t0-stream
t1-stream
t-streamshift
+recenv
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 4f69f2f66..7b8fb7a08 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -56,6 +56,7 @@ noinst_PROGRAMS = \
modmesg\
parseopt\
prop\
+ recenv\
scantime\
strftime\
strin\
@@ -167,6 +168,7 @@ TESTSUITE_AT += \
parseopt_help11.at\
parseopt_help12.at\
prop.at\
+ recenv.at\
scantime.at\
strftime.at\
streamshift.at\
diff --git a/libmailutils/tests/recenv.at b/libmailutils/tests/recenv.at
new file mode 100644
index 000000000..4d15ff87e
--- /dev/null
+++ b/libmailutils/tests/recenv.at
@@ -0,0 +1,56 @@
+# This file is part of GNU Mailutils. -*- Autotest -*-
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# GNU Mailutils 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.
+#
+# GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
+
+AT_BANNER([Reconstructed message envelope])
+dnl ------------------------------------------------------------
+dnl TESTENV(DESCR, MSG, [STATUS = `0'], [STDOUT = `'],
+dnl [STDERR = `'], [RUN-IF-FAIL], [RUN-IF-PASS])
+dnl
+m4_pushdef([TESTENV],
+[AT_SETUP([$1])
+AT_KEYWORDS([recenv])
+AT_DATA([input],[$2
+])
+AT_CHECK([recenv input],
+m4_shift(m4_shift($@)))
+AT_CLEANUP
+])
+
+TESTENV([From Return-Path],
+[Return-Path: <daemon@example.org>
+From: root@example.com
+To: gray@example.com
+Subject: reconstructed environment test
+
+content
+],
+[0],
+[daemon@example.org
+])
+
+TESTENV([Fall back to From if invalid Return-Path],
+[Return-Path: foo@bar@baz
+From: root@example.com
+To: gray@example.com
+Subject: reconstructed environment test
+
+content
+],
+[0],
+[root@example.com
+])
+
+m4_popdef([TESTENV])
diff --git a/libmailutils/tests/recenv.c b/libmailutils/tests/recenv.c
new file mode 100644
index 000000000..628b40bf7
--- /dev/null
+++ b/libmailutils/tests/recenv.c
@@ -0,0 +1,52 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ GNU Mailutils 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.
+
+ GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <mailutils/mailutils.h>
+
+int
+main (int argc, char **argv)
+{
+ mu_stream_t instr;
+ mu_message_t msg;
+ mu_envelope_t env;
+ char const *sender;
+
+ mu_set_program_name (argv[0]);
+ mu_cli_simple (argc, argv,
+ MU_CLI_OPTION_PROG_DOC, "Reads first message from FILE, "
+ "restores its envelope and prints the sender address.",
+ MU_CLI_OPTION_PROG_ARGS, "FILE",
+ MU_CLI_OPTION_RETURN_ARGC, &argc,
+ MU_CLI_OPTION_RETURN_ARGV, &argv,
+ MU_CLI_OPTION_END);
+
+ if (argc != 1)
+ {
+ mu_error ("required argument missing");
+ return 2;
+ }
+
+ mu_set_user_email_domain ("localhost");
+ MU_ASSERT (mu_file_stream_create (&instr, argv[0], MU_STREAM_READ));
+ MU_ASSERT (mu_stream_to_message (instr, &msg));
+ MU_ASSERT (mu_message_reconstruct_envelope (msg, &env));
+ MU_ASSERT (mu_envelope_sget_sender (env, &sender));
+ mu_printf ("%s\n", sender);
+ return 0;
+}
diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at
index a5e947356..2925bff9a 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -257,6 +257,7 @@ m4_include([globtest.at])
m4_include([linetrack.at])
+m4_include([recenv.at])
m4_popdef([MU_TEST_GROUP])
m4_popdef([MU_TEST_KEYWORDS])

Return to:

Send suggestions and report system problems to the System administrator.