diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-08-01 11:35:55 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-08-01 11:42:53 +0300 |
commit | 2843c4054207db33a1237a6991143564c086b3d2 (patch) | |
tree | 6df6529a91862b19809e5a781cd6cca61bcae3f9 /libmailutils | |
parent | 9bf6ea3758f5516f2c2b10945ffd345540698225 (diff) | |
download | mailutils-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.c | 23 | ||||
-rw-r--r-- | libmailutils/mailbox/msgenv.c | 121 | ||||
-rw-r--r-- | libmailutils/tests/.gitignore | 1 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/tests/recenv.at | 56 | ||||
-rw-r--r-- | libmailutils/tests/recenv.c | 52 | ||||
-rw-r--r-- | libmailutils/tests/testsuite.at | 1 |
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]) |