Commit 326f5d74 326f5d74bc530df2f1b759f4131611b36be754fe by Sergey Poznyakoff

Imap4d: fix handling of nested message/rfc822 parts.

* imap4d/fetch.c (fetch_runtime_closure) <msglist>: New member.
(frt_register_message,frt_unregister_messages): New functions.
(fetch_get_part_rfc822): Look into encapsulated rfc822 messages.
(_frt_body_text,_frt_header)
(_frt_header_fields): Use frt_unregister_messages.
(imap4d_fetch0): Initialize all fields in struct fetch_runtime_closure.
Destroy msglist when finished using it.
* imap4d/tests/fetch.at: Add test cases for nested message/rfc822.
* testsuite/spool/msg.mbox: Add a message with nested message/rfc822 part.
1 parent 806f824c
......@@ -32,10 +32,11 @@
struct fetch_runtime_closure
{
int eltno;
size_t msgno;
mu_message_t msg;
char *err_text;
int eltno; /* Serial number of the last output FETCH element */
size_t msgno; /* Sequence number of the message being processed */
mu_message_t msg; /* The message itself */
mu_list_t msglist; /* A list of referenced messages. See KLUDGE below. */
char *err_text; /* On return: error description if failed. */
};
struct fetch_function_closure;
......@@ -662,7 +663,7 @@ set_seen (struct fetch_function_closure *ffc,
}
}
}
static mu_message_t
fetch_get_part (struct fetch_function_closure *ffc,
struct fetch_runtime_closure *frt)
......@@ -675,7 +676,50 @@ fetch_get_part (struct fetch_function_closure *ffc,
return NULL;
return msg;
}
/* FIXME: This is a KLUDGE.
There is so far no way to unref the MU elements being used to construct
a certain entity when this entity itself is being destroyed. In particular,
retrieving a nested message/rfc822 part involves creating several messages
while unencapsulating, which messages should be unreferenced when the
topmost one is destroyed.
A temporary solution used here is to keep a list of such messages and
unreference them together with the topmost one when no longer needed.
A message is added to the list by frt_register_message(). All messages
in the list are unreferenced by calling frt_unregister_messages().
The proper solution is of course providing a way for mu_message_t (and
other MU objects) to unreference its parent elements. This should be fixed
in later releases.
*/
static void
_unref_message_item (void *data)
{
mu_message_unref ((mu_message_t)data);
}
static int
frt_register_message (struct fetch_runtime_closure *frt, mu_message_t msg)
{
if (!frt->msglist)
{
int rc = mu_list_create (&frt->msglist);
if (rc)
return rc;
mu_list_set_destroy_item (frt->msglist, _unref_message_item);
}
return mu_list_append (frt->msglist, msg);
}
static void
frt_unregister_messages (struct fetch_runtime_closure *frt)
{
mu_list_clear (frt->msglist);
}
static mu_message_t
fetch_get_part_rfc822 (struct fetch_function_closure *ffc,
struct fetch_runtime_closure *frt)
......@@ -692,35 +736,46 @@ fetch_get_part_rfc822 (struct fetch_function_closure *ffc,
}
for (i = 0; i < ffc->nset; i++)
if (mu_message_get_part (msg, ffc->section_part[i], &msg))
return NULL;
{
if (mu_message_get_part (msg, ffc->section_part[i], &msg))
return NULL;
if (mu_message_get_header (msg, &header))
return NULL;
if (mu_message_get_header (msg, &header))
return NULL;
if (mu_header_sget_value (header, MU_HEADER_CONTENT_TYPE, &hval) == 0)
{
struct mu_wordsplit ws;
int rc;
ws.ws_delim = " \t\r\n;=";
ws.ws_alloc_die = imap4d_ws_alloc_die;
if (mu_wordsplit (hval, &ws, IMAP4D_WS_FLAGS))
if (mu_header_sget_value (header, MU_HEADER_CONTENT_TYPE, &hval) == 0)
{
mu_error (_("%s failed: %s"), "mu_wordsplit",
mu_wordsplit_strerror (&ws));
return NULL;
}
struct mu_wordsplit ws;
int rc;
ws.ws_delim = " \t\r\n;=";
ws.ws_alloc_die = imap4d_ws_alloc_die;
if (mu_wordsplit (hval, &ws, IMAP4D_WS_FLAGS))
{
mu_error (_("%s failed: %s"), "mu_wordsplit",
mu_wordsplit_strerror (&ws));
return NULL;
}
rc = mu_c_strcasecmp (ws.ws_wordv[0], "MESSAGE/RFC822");
mu_wordsplit_free (&ws);
rc = mu_c_strcasecmp (ws.ws_wordv[0], "MESSAGE/RFC822");
mu_wordsplit_free (&ws);
if (rc == 0)
{
rc = mu_message_unencapsulate (msg, &retmsg, NULL);
if (rc)
mu_error (_("%s failed: %s"), "mu_message_unencapsulate",
mu_strerror (rc));
if (rc == 0)
{
rc = mu_message_unencapsulate (msg, &retmsg, NULL);
if (rc)
{
mu_error (_("%s failed: %s"), "mu_message_unencapsulate",
mu_strerror (rc));
return NULL;
}
if (frt_register_message (frt, retmsg))
{
frt_unregister_messages (frt);
return NULL;
}
msg = retmsg;
}
}
}
......@@ -1042,7 +1097,7 @@ _frt_body_text (struct fetch_function_closure *ffc,
mu_body_get_streamref (body, &stream);
rc = fetch_io (stream, ffc->start, ffc->size, size + lines);
mu_stream_destroy (&stream);
mu_message_unref (msg);
frt_unregister_messages (frt);
return rc;
}
......@@ -1087,7 +1142,7 @@ _frt_header (struct fetch_function_closure *ffc,
mu_header_get_streamref (header, &stream);
rc = fetch_io (stream, ffc->start, ffc->size, size + lines);
mu_stream_destroy (&stream);
mu_message_unref (msg);
frt_unregister_messages (frt);
return rc;
}
......@@ -1177,7 +1232,7 @@ _frt_header_fields (struct fetch_function_closure *ffc,
if (mu_message_get_header (msg, &header)
|| mu_header_get_iterator (header, &itr))
{
mu_message_unref (msg);
frt_unregister_messages (frt);
io_sendf (" NIL");
return RESP_OK;
}
......@@ -1216,7 +1271,7 @@ _frt_header_fields (struct fetch_function_closure *ffc,
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
status = fetch_io (stream, ffc->start, ffc->size, size + lines);
mu_stream_destroy (&stream);
mu_message_unref (msg);
frt_unregister_messages (frt);
return status;
}
......@@ -1783,7 +1838,8 @@ imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
{
size_t i;
struct fetch_runtime_closure frc;
memset (&frc, 0, sizeof (frc));
/* Prepare status code. It will be replaced if an error occurs in the
loop below */
frc.err_text = "Completed";
......@@ -1801,7 +1857,8 @@ imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
io_sendf (")\n");
}
}
}
mu_list_destroy (&frc.msglist);
}
mu_list_destroy (&pclos.fnlist);
free (pclos.set);
......
......@@ -363,10 +363,40 @@ TO: <gray@example.com>
)],
[msg.mbox])
FETCH_CHECK([nested message/rfc822],[fetch-nested fetch21],
[2 BODY[[2.2.TEXT]]],
[* 2 FETCH (FLAGS (\Seen) BODY[[2.2.TEXT]] {451}
5.2.1. RFC822 Subtype
A media type of "message/rfc822" indicates that the body contains an
encapsulated message, with the syntax of an RFC 822 message.
However, unlike top-level RFC 822 messages, the restriction that each
"message/rfc822" body must include a "From", "Date", and at least one
destination header is removed and replaced with the requirement that
at least one of "From", "Subject", or "Date" must be present.
)],
[msg.mbox])
FETCH_CHECK([nested multipart + message/rfc822],[fetch-nested fetch22],
[2 BODY[[2.2.TEXT]]],
[* 2 FETCH (FLAGS (\Seen) BODY[[2.2.TEXT]] {451}
5.2.1. RFC822 Subtype
A media type of "message/rfc822" indicates that the body contains an
encapsulated message, with the syntax of an RFC 822 message.
However, unlike top-level RFC 822 messages, the restriction that each
"message/rfc822" body must include a "From", "Date", and at least one
destination header is removed and replaced with the requirement that
at least one of "From", "Subject", or "Date" must be present.
)],
[msg.mbox])
# BODY.PEEK[<section>]<<partial>>
# An alternate form of BODY[<section>] that does not
# implicitly set the \Seen flag.
FETCH_CHECK([BODY.PEEK[[HEADER]]],[fetch-body-peek-header fetch21],
FETCH_CHECK([BODY.PEEK[[HEADER]]],[fetch-body-peek-header fetch23],
[1 BODY.PEEK[[HEADER]]],
[* 1 FETCH (BODY[[HEADER]] {326}
Received: (from foobar@nonexistent.net)
......@@ -384,7 +414,7 @@ Subject: Jabberwocky
# syntax of the resulting untagged FETCH data (RFC822
# is returned).
FETCH_CHECK([RFC822],[fetch-rfc822 fetch22],
FETCH_CHECK([RFC822],[fetch-rfc822 fetch24],
[1 RFC822],
[* 1 FETCH (FLAGS (\Seen) RFC822 {1298}
Received: (from foobar@nonexistent.net)
......@@ -437,7 +467,7 @@ And the mome raths outgrabe.
# differing in the syntax of the resulting untagged
# FETCH data (RFC822.HEADER is returned).
# FIXME: Should it set \Seen flag?
FETCH_CHECK([RFC822.HEADER],[fetch-rfc822-header fetch23],
FETCH_CHECK([RFC822.HEADER],[fetch-rfc822-header fetch25],
[2 RFC822.HEADER],
[* 2 FETCH (RFC822.HEADER {328}
Received: (from bar@dontmailme.org)
......@@ -453,14 +483,14 @@ Subject: Re: Jabberwocky
# RFC822.SIZE The [RFC-822] size of the message.
FETCH_CHECK([RFC822.SIZE],[fetch-rfc822-size fetch24],
FETCH_CHECK([RFC822.SIZE],[fetch-rfc822-size fetch26],
[3 RFC822.SIZE],
[* 3 FETCH (RFC822.SIZE 1611)])
# RFC822.TEXT Functionally equivalent to BODY[TEXT], differing in
# the syntax of the resulting untagged FETCH data
# (RFC822.TEXT is returned).
FETCH_CHECK([RFC822.TEXT],[fetch-rfc822-text fetch25],
FETCH_CHECK([RFC822.TEXT],[fetch-rfc822-text fetch27],
[2 RFC822.TEXT],
[* 2 FETCH (FLAGS (\Seen) RFC822.TEXT {219}
It seems very pretty, but it's *rather* hard to understand!'
......@@ -472,7 +502,7 @@ that's clear, at any rate...
# FAST Macro equivalent to: (FLAGS INTERNALDATE
# RFC822.SIZE)
FETCH_CHECK([FAST],[fetch-fast fetch26],
FETCH_CHECK([FAST],[fetch-fast fetch28],
[1 FAST],
[* 1 FETCH (FLAGS (\Recent) INTERNALDATE "28-Dec-2001 22:18:09 +0000" RFC822.SIZE 1298)],
[],
......@@ -481,7 +511,7 @@ FETCH_CHECK([FAST],[fetch-fast fetch26],
# FULL Macro equivalent to: (FLAGS INTERNALDATE
# RFC822.SIZE ENVELOPE BODY)
FETCH_CHECK([FULL],[fetch-full fetch27],
FETCH_CHECK([FULL],[fetch-full fetch29],
[4 FULL],
[* 4 FETCH (FLAGS (\Recent) INTERNALDATE "13-Jul-2002 00:50:58 +0000" RFC822.SIZE 3483 ENVELOPE ("Sat, 13 Jul 2002 00:50:58 +0300" "Nested MIME" (("Sergey Poznyakoff" NIL "gray" "example.net")) (("Sergey Poznyakoff" NIL "gray" "example.net")) (("Sergey Poznyakoff" NIL "gray" "example.net")) (("Foo Bar" NIL "foobar" "nonexistent.net")) NIL NIL NIL "<200207122150.g6CLowb05126@example.net>") BODY (("text" "plain" ("name" "msg.21" "charset" "us-ascii") "<5122.1026510654.2@example.net>" "Father William Part I" "7BIT" 351 10)(("application" "octet-stream" ("name" "msg.22") "<5122.1026510654.4@example.net>" "Father William Part II" "base64" 486)(("application" "octet-stream" ("name" "msg.23") "<5122.1026510654.6@example.net>" "Father William Part III" "base64" 490)("application" "octet-stream" ("name" "msg.24") "<5122.1026510654.7@example.net>" "Father William Part IV" "base64" 502) "mixed" NIL NIL NIL) "mixed" NIL NIL NIL) "mixed" NIL NIL NIL))],
[],
......
......@@ -42,3 +42,232 @@ X-Envelope-Sender: gray@example.org
--1595057156-1322340286=:8528--
From gray@example.org Tue Nov 29 09:42:53 2011
Message-ID: <20111129114253.10123@host.example.org>
From: "Sergey Poznyakoff" <gray@example.org>
Date: Tue, 29 Nov 2011 11:42:53 +0200
To: <root@example.com>
Subject: nested message
Content-Type: multipart/mixed; boundary="1727955616-1322559692=:10106"
MIME-Version: 1.0
--1727955616-1322559692=:10106
Content-ID: <20111129114132.10106.1@host.example.org>
Content-Type: text/plain
An example of nested message/rfc822
--1727955616-1322559692=:10106
Content-Transfer-Encoding: 7bit
Content-Description:
Content-ID: <20111129114132.10106.1@host.example.org>
Content-Type: message/rfc822; name="msg.mbox"
Date: Sat, 26 Nov 2011 22:45:20 +0200
From: Sergey Poznyakoff <gray@example.org>
To: <root@example.com>
Subject: rfc2046
Content-Type: multipart/mixed; boundary="1595057156-1322340286=:8528"
MIME-Version: 1.0
Status: OR
--1595057156-1322340286=:8528
Content-ID: <20111126224446.8528.1@host.example.org>
Content-Type: text/plain
An excerpt from RFC 2046 regarding message/rfc822.
--1595057156-1322340286=:8528
Content-Transfer-Encoding: 7bit
Content-Description:
Content-ID: <20111126224446.8528.1@host.example.org>
Content-Type: message/rfc822; name="1.msg"
Message-ID: <20111123103317.27412@host.example.org>
Date: Wed, 23 Nov 2011 10:33:17 +0200
From: Sergey Poznyakoff <gray@example.org>
To: <gray@example.com>
Subject: Re: RFC822 Subtype
In-reply-to: Your message of Wed, 23 Nov 2011 08:48:16 +0100
<87wrar6zzz@example.com>
References: <87wrar6zzz@example.com>
X-Envelope-Date: Wed Nov 23 08:33:17 2011
X-Envelope-Sender: gray@example.org
5.2.1. RFC822 Subtype
A media type of "message/rfc822" indicates that the body contains an
encapsulated message, with the syntax of an RFC 822 message.
However, unlike top-level RFC 822 messages, the restriction that each
"message/rfc822" body must include a "From", "Date", and at least one
destination header is removed and replaced with the requirement that
at least one of "From", "Subject", or "Date" must be present.
--1595057156-1322340286=:8528--
--1727955616-1322559692=:10106--
From gray@example.org Tue Nov 29 13:16:16 2011
To: gray@example.com
Subject: nested multipart + message/rfc822.
Content-Type: multipart/mixed; boundary="2059362778-1322566623=:4927"
MIME-Version: 1.0
Status: OR
--2059362778-1322566623=:4927
Content-ID: <20111129133703.4927.1@host.example.org>
Content-Type: text/plain
The following multipart attachment contains a message/rfc822 as one of
its parts.
--2059362778-1322566623=:4927
Content-Type: multipart/mixed; boundary="1110782568-1322566623=:4927"
MIME-Version: 1.0
--1110782568-1322566623=:4927
Content-ID: <20111129133703.4927.2@host.example.org>
Content-Type: text/plain
Introductory text
--1110782568-1322566623=:4927
Content-Transfer-Encoding: 7bit
Content-Description: Nested message
Content-ID: <20111129133703.4927.2@host.example.org>
Content-Type: message/rfc822; name="1.msg"
Date: Sat, 26 Nov 2011 22:45:20 +0200
From: Sergey Poznyakoff <gray@example.org>
To: <root@example.com>
Subject: rfc2046
Content-Type: multipart/mixed; boundary="1595057156-1322340286=:8528"
MIME-Version: 1.0
Status: OR
--1595057156-1322340286=:8528
Content-ID: <20111126224446.8528.1@host.example.org>
Content-Type: text/plain
An excerpt from RFC 2046 regarding message/rfc822.
--1595057156-1322340286=:8528
Content-Transfer-Encoding: 7bit
Content-Description:
Content-ID: <20111126224446.8528.1@host.example.org>
Content-Type: message/rfc822; name="1.msg"
Message-ID: <20111123103317.27412@host.example.org>
Date: Wed, 23 Nov 2011 10:33:17 +0200
From: Sergey Poznyakoff <gray@example.org>
To: <gray@example.com>
Subject: Re: RFC822 Subtype
In-reply-to: Your message of Wed, 23 Nov 2011 08:48:16 +0100
<87wrar6zzz@example.com>
References: <87wrar6zzz@example.com>
X-Envelope-Date: Wed Nov 23 08:33:17 2011
X-Envelope-Sender: gray@example.org
5.2.1. RFC822 Subtype
A media type of "message/rfc822" indicates that the body contains an
encapsulated message, with the syntax of an RFC 822 message.
However, unlike top-level RFC 822 messages, the restriction that each
"message/rfc822" body must include a "From", "Date", and at least one
destination header is removed and replaced with the requirement that
at least one of "From", "Subject", or "Date" must be present.
--1595057156-1322340286=:8528--
--1110782568-1322566623=:4927--
--2059362778-1322566623=:4927--
From gray@example.org Tue Nov 29 13:16:16 2011
To: gray@example.com
Subject: nested multipart + message/rfc822.
Content-Type: multipart/mixed; boundary="2059362778-1322566623=:4927"
MIME-Version: 1.0
X-IMAPbase: 1322575861 2
Status: OR
X-UID: 1
--2059362778-1322566623=:4927
Content-ID: <20111129133703.4927.1@host.example.org>
Content-Type: text/plain
The following multipart attachment contains a message/rfc822 as one of
its parts.
--2059362778-1322566623=:4927
Content-Type: multipart/mixed; boundary="1110782568-1322566623=:4927"
MIME-Version: 1.0
--1110782568-1322566623=:4927
Content-ID: <20111129133703.4927.2@host.example.org>
Content-Type: text/plain
Introductory text
--1110782568-1322566623=:4927
Content-Transfer-Encoding: 7bit
Content-Description: Nested message
Content-ID: <20111129133703.4927.2@host.example.org>
Content-Type: message/rfc822; name="1.msg"
Date: Sat, 26 Nov 2011 22:45:20 +0200
From: Sergey Poznyakoff <gray@example.org>
To: <root@example.com>
Subject: rfc2046
Content-Type: multipart/mixed; boundary="1595057156-1322340286=:8528"
MIME-Version: 1.0
Status: OR
--1595057156-1322340286=:8528
Content-ID: <20111126224446.8528.1@host.example.org>
Content-Type: text/plain
An excerpt from RFC 2046 regarding message/rfc822.
--1595057156-1322340286=:8528
Content-Transfer-Encoding: 7bit
Content-Description:
Content-ID: <20111126224446.8528.1@host.example.org>
Content-Type: message/rfc822; name="1.msg"
Message-ID: <20111123103317.27412@host.example.org>
Date: Wed, 23 Nov 2011 10:33:17 +0200
From: Sergey Poznyakoff <gray@example.org>
To: <gray@example.com>
Subject: Re: RFC822 Subtype
In-reply-to: Your message of Wed, 23 Nov 2011 08:48:16 +0100
<87wrar6zzz@example.com>
References: <87wrar6zzz@example.com>
X-Envelope-Date: Wed Nov 23 08:33:17 2011
X-Envelope-Sender: gray@example.org
5.2.1. RFC822 Subtype
A media type of "message/rfc822" indicates that the body contains an
encapsulated message, with the syntax of an RFC 822 message.
However, unlike top-level RFC 822 messages, the restriction that each
"message/rfc822" body must include a "From", "Date", and at least one
destination header is removed and replaced with the requirement that
at least one of "From", "Subject", or "Date" must be present.
--1595057156-1322340286=:8528--
--1110782568-1322566623=:4927--
--2059362778-1322566623=:4927--
......