diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-08-07 17:29:30 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-08-07 17:51:48 +0300 |
commit | b8553fee2f6da26406b7571e5dcfd2f4d604fe57 (patch) | |
tree | b8d285178e8dbadf9fb606dd4b3150a25a33e4ae | |
parent | 5fe88d71121bd4a5c3afb83b5ed1b8d775429fa4 (diff) | |
download | mailutils-b8553fee2f6da26406b7571e5dcfd2f4d604fe57.tar.gz mailutils-b8553fee2f6da26406b7571e5dcfd2f4d604fe57.tar.bz2 |
stream API: remove the readdelim method
The method is superfluous as the API itself provides the necessary
functionality. Besides, it interacted poorly with positioning in
buffered streams.
* include/mailutils/sys/stream.h (struct _mu_stream): Remove
the readdelim method.
* libmailutils/stream/stream.c (mu_stream_readdelim)
(mu_stream_getdelim): Remove uses of the readdelim method.
* libmailutils/tests/.gitignore: Update.
* libmailutils/tests/Makefile.am: Add new test.
* libmailutils/tests/testsuite.at: Likewise.
* libmailutils/tests/getdelim.at: New test.
* libmailutils/tests/stream-getdelim.c: New test program.
* libmailutils/base/amd.c: Remove readdelim implementation.
* libmailutils/mailbox/msgstream.c: Likewise.
* libmailutils/stream/iostream.c: Likewise.
* libmailutils/stream/streamref.c: Likewise.
* libmailutils/stream/xscript-stream.c: Likewise.
* libproto/pop/pop3_stream.c: Likewise.
* mail/decode.c (mime_descend): Handle errors from mu_message_unencapsulate
graciously. On failure, treat message/rfc822 as text/plain.
-rw-r--r-- | include/mailutils/sys/stream.h | 1 | ||||
-rw-r--r-- | libmailutils/base/amd.c | 62 | ||||
-rw-r--r-- | libmailutils/mailbox/msgstream.c | 32 | ||||
-rw-r--r-- | libmailutils/stream/iostream.c | 14 | ||||
-rw-r--r-- | libmailutils/stream/stream.c | 21 | ||||
-rw-r--r-- | libmailutils/stream/streamref.c | 36 | ||||
-rw-r--r-- | libmailutils/stream/xscript-stream.c | 10 | ||||
-rw-r--r-- | libmailutils/tests/.gitignore | 1 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/tests/getdelim.at | 12 | ||||
-rw-r--r-- | libmailutils/tests/stream-getdelim.c | 218 | ||||
-rw-r--r-- | libmailutils/tests/testsuite.at | 1 | ||||
-rw-r--r-- | libproto/pop/pop3_stream.c | 26 | ||||
-rw-r--r-- | mail/decode.c | 59 |
14 files changed, 297 insertions, 198 deletions
diff --git a/include/mailutils/sys/stream.h b/include/mailutils/sys/stream.h index 203ddf64e..44349bddd 100644 --- a/include/mailutils/sys/stream.h +++ b/include/mailutils/sys/stream.h @@ -53,7 +53,6 @@ struct _mu_stream int last_err; int (*read) (struct _mu_stream *, char *, size_t, size_t *); - int (*readdelim) (struct _mu_stream *, char *, size_t, int, size_t *); int (*write) (struct _mu_stream *, const char *, size_t, size_t *); int (*flush) (struct _mu_stream *); int (*open) (struct _mu_stream *); diff --git a/libmailutils/base/amd.c b/libmailutils/base/amd.c index 115f9e73d..04a373160 100644 --- a/libmailutils/base/amd.c +++ b/libmailutils/base/amd.c @@ -111,10 +111,6 @@ static int amd_remove_mbox (mu_mailbox_t mailbox); static int amd_body_stream_read (mu_stream_t str, char *buffer, size_t buflen, size_t *pnread); -static int amd_body_stream_readdelim (mu_stream_t is, - char *buffer, size_t buflen, - int delim, - size_t *pnread); static int amd_body_stream_size (mu_stream_t str, mu_off_t *psize); static int amd_body_stream_seek (mu_stream_t str, mu_off_t off, mu_off_t *presult); @@ -617,7 +613,6 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm, return ENOMEM; } str->stream.read = amd_body_stream_read; - str->stream.readdelim = amd_body_stream_readdelim; str->stream.size = amd_body_stream_size; str->stream.seek = amd_body_stream_seek; mu_body_set_stream (body, (mu_stream_t) str, msg); @@ -1921,63 +1916,6 @@ amd_body_stream_read (mu_stream_t is, char *buffer, size_t buflen, } static int -amd_body_stream_readdelim (mu_stream_t is, char *buffer, size_t buflen, - int delim, - size_t *pnread) -{ - struct _amd_body_stream *amdstr = (struct _amd_body_stream *)is; - mu_body_t body = amdstr->body; - mu_message_t msg = mu_body_get_owner (body); - struct _amd_message *mhm = mu_message_get_owner (msg); - int status = 0; - - status = amd_pool_open (mhm); - if (status) - return status; - - if (buffer == NULL || buflen == 0) - { - if (pnread) - *pnread = 0; - return 0; - } - - mu_monitor_rdlock (mhm->amd->mailbox->monitor); -#ifdef WITH_PTHREAD - /* read() is cancellation point since we're doing a potentially - long operation. Lets make sure we clean the state. */ - pthread_cleanup_push (amd_cleanup, (void *)mhm->amd->mailbox); -#endif - - status = mu_stream_seek (mhm->stream, mhm->body_start + amdstr->off, - MU_SEEK_SET, NULL); - if (status == 0) - { - size_t nread = 0; - size_t ln; - - ln = mhm->body_end - (mhm->body_start + amdstr->off) + 1; - if (ln > 0) - { - size_t rdsize = ((size_t)ln < buflen) ? (size_t)ln : buflen; - status = mu_stream_readdelim (mhm->stream, buffer, rdsize, - delim, &nread); - amdstr->off += nread; - } - - if (pnread) - *pnread = nread; - } - - mu_monitor_unlock (mhm->amd->mailbox->monitor); -#ifdef WITH_PTHREAD - pthread_cleanup_pop (0); -#endif - - return status; -} - -static int amd_body_stream_seek (mu_stream_t str, mu_off_t off, mu_off_t *presult) { int rc; diff --git a/libmailutils/mailbox/msgstream.c b/libmailutils/mailbox/msgstream.c index a1cf4825b..f43d765cd 100644 --- a/libmailutils/mailbox/msgstream.c +++ b/libmailutils/mailbox/msgstream.c @@ -206,37 +206,6 @@ _message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize, return rc; } -static int -_message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, - int delim, size_t *pnread) -{ - struct _mu_message_stream *sp = (struct _mu_message_stream *)str; - size_t nread = 0; - int rc; - - while (bufsize) - { - size_t n; - rc = _check_stream_state (sp); - if (rc) - break; - if (sp->state == _mss_eof) - break; - rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n); - if (rc) - break; - if (n == 0) - continue; - nread += n; - if (buf[n-1] == delim) - break; - buf += n; - bufsize -= n; - } - *pnread = nread; - return rc; -} - #if 0 static int _message_stream_write (struct _mu_stream *str, @@ -262,7 +231,6 @@ _message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags) return ENOMEM; sp->stream.read = _message_stream_read; - sp->stream.readdelim = _message_stream_readdelim; /* FIXME: Write is not defined */ /* sp->stream.write = _message_stream_write;*/ sp->stream.done = _message_stream_done; diff --git a/libmailutils/stream/iostream.c b/libmailutils/stream/iostream.c index 7045bb508..4a4647480 100644 --- a/libmailutils/stream/iostream.c +++ b/libmailutils/stream/iostream.c @@ -43,18 +43,6 @@ _iostream_read (struct _mu_stream *str, char *buf, size_t bufsize, } static int -_iostream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, - int delim, size_t *pnread) -{ - struct _mu_iostream *sp = (struct _mu_iostream *)str; - int rc = mu_stream_readdelim (sp->transport[_MU_STREAM_INPUT], buf, - bufsize, delim, pnread); - if (rc) - sp->last_err_str = _MU_STREAM_INPUT; - return rc; -} - -static int _iostream_write (struct _mu_stream *str, const char *buf, size_t bufsize, size_t *pnwrite) { @@ -275,8 +263,6 @@ mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out) sp->stream.flags |= _MU_STR_OPEN; sp->stream.read = _iostream_read; - if (in->readdelim) - sp->stream.readdelim = _iostream_readdelim; sp->stream.write = _iostream_write; sp->stream.flush = _iostream_flush; sp->stream.open = _iostream_open; diff --git a/libmailutils/stream/stream.c b/libmailutils/stream/stream.c index 97af34054..0131e3b52 100644 --- a/libmailutils/stream/stream.c +++ b/libmailutils/stream/stream.c @@ -864,16 +864,7 @@ mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size, if (stream->buftype == mu_buffer_none) { - if (stream->readdelim) - { - size_t nread; - rc = stream->readdelim (stream, buf, size, delim, &nread); - if (pread) - *pread = nread; - stream->offset += nread; - } - else - rc = _stream_readdelim (stream, buf, size, delim, pread); + rc = _stream_readdelim (stream, buf, size, delim, pread); } else { @@ -952,14 +943,12 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, n = needed; } - if (stream->readdelim) - rc = stream->readdelim (stream, lineptr + cur_len, n - cur_len, delim, - &rdn); - else if (stream->buftype != mu_buffer_none) + if (stream->buftype == mu_buffer_none) + rc = _stream_readdelim (stream, lineptr + cur_len, n - cur_len, delim, + &rdn); + else rc = _stream_scandelim (stream, lineptr + cur_len, n - cur_len, delim, &rdn); - else - rc = mu_stream_read (stream, lineptr + cur_len, 1, &rdn); if (rc || rdn == 0) break; diff --git a/libmailutils/stream/streamref.c b/libmailutils/stream/streamref.c index 74a5f5f92..65a3b9ed2 100644 --- a/libmailutils/stream/streamref.c +++ b/libmailutils/stream/streamref.c @@ -59,40 +59,6 @@ _streamref_read (struct _mu_stream *str, char *buf, size_t bufsize, } static int -_streamref_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, - int delim, size_t *pnread) -{ - struct _mu_streamref *sp = (struct _mu_streamref *)str; - int rc; - size_t nread; - mu_off_t off; - - rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, &off); - if (rc == 0) - { - rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &nread); - if (rc == 0) - { - if (sp->end) - { - size_t size = sp->end - off + 1; - if (nread > size) - nread = size; - } - sp->offset += nread; - *pnread = nread; - } - } - else if (rc == ESPIPE) - { - *pnread = 0; - mu_stream_clearerr (sp->transport); - return 0; - } - return rc; -} - -static int _streamref_write (struct _mu_stream *str, const char *buf, size_t bufsize, size_t *pnwrite) { @@ -274,8 +240,6 @@ mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str, mu_stream_ref (str); sp->stream.read = _streamref_read; - if (str->readdelim) - sp->stream.readdelim = _streamref_readdelim; sp->stream.write = _streamref_write; sp->stream.flush = _streamref_flush; sp->stream.open = _streamref_open; diff --git a/libmailutils/stream/xscript-stream.c b/libmailutils/stream/xscript-stream.c index 581110d70..3a3f09598 100644 --- a/libmailutils/stream/xscript-stream.c +++ b/libmailutils/stream/xscript-stream.c @@ -310,14 +310,6 @@ _xscript_read (struct _mu_stream *str, char *buf, size_t bufsize, } static int -_xscript_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, - int delim, size_t *pnread) -{ - struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; - return mu_stream_readdelim (sp->transport, buf, bufsize, delim, pnread); -} - -static int _xscript_write (struct _mu_stream *str, const char *buf, size_t bufsize, size_t *pnwrite) { @@ -582,8 +574,6 @@ mu_xscript_stream_create (mu_stream_t *pref, mu_stream_t transport, return ENOMEM; sp->stream.read = _xscript_read; - if (transport->readdelim) - sp->stream.readdelim = _xscript_readdelim; sp->stream.write = _xscript_write; sp->stream.flush = _xscript_flush; sp->stream.open = _xscript_open; diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore index 6b4229a6b..591f9befd 100644 --- a/libmailutils/tests/.gitignore +++ b/libmailutils/tests/.gitignore @@ -55,3 +55,4 @@ t1-stream t-streamshift recenv readmesg +stream-getdelim diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index bd0b781c0..cdaec679f 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -59,6 +59,7 @@ noinst_PROGRAMS = \ readmesg\ recenv\ scantime\ + stream-getdelim\ strftime\ strin\ strout\ @@ -108,6 +109,7 @@ TESTSUITE_AT += \ fsfolder02.at\ fsfolder03.at\ fsfolder04.at\ + getdelim.at\ hdrcpy.at\ hdrflt.at\ htmlent.at\ diff --git a/libmailutils/tests/getdelim.at b/libmailutils/tests/getdelim.at new file mode 100644 index 000000000..493412e64 --- /dev/null +++ b/libmailutils/tests/getdelim.at @@ -0,0 +1,12 @@ +AT_SETUP([getdelim]) +AT_CHECK([stream-getdelim], +[0], +[0: No buffering +1: Linear buffering +2: Linear buffering (small buffer) +3: Full buffering (big buffer) +4: Full buffering (moderate buffer) +5: Full buffering (small buffer) +]) +AT_CLEANUP + diff --git a/libmailutils/tests/stream-getdelim.c b/libmailutils/tests/stream-getdelim.c new file mode 100644 index 000000000..075afa9f9 --- /dev/null +++ b/libmailutils/tests/stream-getdelim.c @@ -0,0 +1,218 @@ +/* +NAME + stream-getdelim - test the mu_stream_getdelim function. + +DESCRIPTION + This implements a simple memory-based stream implementation and + tests mu_stream_getdelim on a predefined stream content with various + combinations of buffering type and buffer size settings. + + On success, returns 0. On error, prints diagnostics on stderr and + exits with a non-0 code or aborts. + + Before running each test, its short description is printed on stdout. + + For obvious reasons, libc functions are used for output. + +LICENSE + This file is part of GNU mailutils. + Copyright (C) 2020 Free Software Foundation, Inc. + + 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/>. +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <mailutils/types.h> +#include <mailutils/debug.h> +#include <mailutils/errno.h> +#include <mailutils/stream.h> +#include <mailutils/sys/stream.h> + +char content[] = + "AB\n" + "\n" + "\n" + "CDEFG\n" + "H\n" + "IJ\n" + "KLMNOPQRST\n" + "UVWXYZ"; + +struct test_stream +{ + struct _mu_stream stream; + char *ptr; + size_t size; + mu_off_t offset; +}; + +static int +ts_open (mu_stream_t stream) +{ + struct test_stream *ts = (struct test_stream *) stream; + ts->ptr = content; + ts->size = strlen (content); + ts->offset = 0; + return 0; +} + +static int +ts_read (mu_stream_t stream, char *optr, size_t osize, size_t *nbytes) +{ + struct test_stream *ts = (struct test_stream *) stream; + size_t n = 0; + if (ts->ptr != NULL && ((size_t)ts->offset <= ts->size)) + { + n = ts->size - ts->offset; + if (n > osize) + n = osize; + memcpy (optr, ts->ptr + ts->offset, n); + ts->offset += n; + } + if (nbytes) + *nbytes = n; + return 0; +} + +static int +ts_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult) +{ + struct test_stream *ts = (struct test_stream *) stream; + + if (off < 0) + return ESPIPE; + ts->offset = off; + *presult = off; + return 0; +} + +static int +ts_size (mu_stream_t stream, mu_off_t *psize) +{ + struct test_stream *ts = (struct test_stream *) stream; + *psize = ts->size; + return 0; +} + +int +test_stream_create (mu_stream_t *pstream) +{ + int rc; + mu_stream_t stream; + + stream = _mu_stream_create (sizeof (struct test_stream), MU_STREAM_READ|MU_STREAM_SEEK); + assert (stream != NULL); + + stream->open = ts_open; + stream->read = ts_read; + stream->size = ts_size; + stream->seek = ts_seek; + + rc = mu_stream_open (stream); + if (rc) + mu_stream_destroy (&stream); + else + *pstream = stream; + + return rc; +} + +void +runtest (mu_stream_t str) +{ + char *buf = NULL; + size_t size = 0; + mu_off_t off; + size_t n; + int rc; + unsigned long start = 0; + + MU_ASSERT (mu_stream_seek (str, 0, MU_SEEK_SET, NULL)); + + while ((rc = mu_stream_getdelim (str, &buf, &size, '\n', &n)) == 0 + && n > 0) + { + size_t blen = strlen (buf); + size_t len = strcspn (content + start, "\n"); + if (content[start+len] == '\n') + len++; + if (len != blen || memcmp (content + start, buf, len)) + { + fprintf (stderr, "at %lu: expected:\n", start); + fwrite (content + start, blen, 1, stderr); + fprintf (stderr, "\nfound:\n"); + fwrite (buf, blen, 1, stderr); + fputc ('\n', stderr); + exit (1); + } + start += len; + + MU_ASSERT (mu_stream_seek (str, 0, MU_SEEK_CUR, &off)); + if (off != start) + { + fprintf (stderr, "wrong offset reported (%lu, expected %lu\n", + (unsigned long)off, (unsigned long)start); + exit (2); + } + } + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_getline", NULL, rc); + exit (1); + } + free (buf); +} + +#define TESTBUFSIZE 512 + +static struct test +{ + char *name; + enum mu_buffer_type type; + size_t size; +} testtab[] = { + { "No buffering", mu_buffer_none, 0 }, + { "Linear buffering", mu_buffer_line, TESTBUFSIZE }, + { "Linear buffering (small buffer)", mu_buffer_line, 1 }, + { "Full buffering (big buffer)", mu_buffer_full, TESTBUFSIZE }, + { "Full buffering (moderate buffer)", mu_buffer_full, sizeof(content)/2 }, + { "Full buffering (small buffer)", mu_buffer_full, 1 }, + { NULL } +}; + +int +main (int argc, char **argv) +{ + mu_stream_t str; + int i; + + MU_ASSERT (test_stream_create (&str)); + + for (i = 0; testtab[i].name; i++) + { + printf ("%d: %s\n", i, testtab[i].name); + MU_ASSERT (mu_stream_set_buffer (str, testtab[i].type, testtab[i].size)); + runtest (str); + } + + mu_stream_destroy (&str); + return 0; +} diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at index 01bdfc33e..2ca2f7386 100644 --- a/libmailutils/tests/testsuite.at +++ b/libmailutils/tests/testsuite.at @@ -102,6 +102,7 @@ AT_BANNER([Basic streams]) m4_include([t0-stream.at]) m4_include([t1-stream.at]) m4_include([streamshift.at]) +m4_include([getdelim.at]) AT_BANNER([Conversions]) m4_include([strtoc.at]) diff --git a/libproto/pop/pop3_stream.c b/libproto/pop/pop3_stream.c index 3a2b0e4d2..3b58ca6ae 100644 --- a/libproto/pop/pop3_stream.c +++ b/libproto/pop/pop3_stream.c @@ -127,31 +127,6 @@ _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize, } static int -_mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, - int delim, size_t *pnread) -{ - struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str; - mu_pop3_t pop3 = sp->pop3; - size_t nread; - int status = 0; - - if (sp->flags & _POP3F_DONE) - nread = 0; - else - { - status = mu_stream_readdelim (pop3->carrier, buf, bufsize, delim, - &nread); - if (status == 0 && nread == 0) - { - pop3->state = MU_POP3_NO_STATE; - sp->flags |= _POP3F_DONE; - } - } - *pnread = nread; - return status; -} - -static int _mu_pop3_flush (struct _mu_stream *str) { struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str; @@ -180,7 +155,6 @@ mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream) if (!sp) return ENOMEM; sp->stream.read = _mu_pop3_read; - sp->stream.readdelim = _mu_pop3_readdelim; sp->stream.flush = _mu_pop3_flush; sp->stream.wait = _mu_pop3_wait; diff --git a/mail/decode.c b/mail/decode.c index 4f06a0dce..6b3f71b42 100644 --- a/mail/decode.c +++ b/mail/decode.c @@ -207,12 +207,69 @@ mime_descend (struct mime_descend_closure *closure, { mu_message_t submsg = NULL; - if (mu_message_unencapsulate (closure->message, &submsg, NULL) == 0) + switch (mu_message_unencapsulate (closure->message, &submsg, NULL)) { + case 0: subclosure.hints = MDHINT_SELECTED_HEADERS; subclosure.msgset = closure->msgset; subclosure.message = submsg; status = mime_descend (&subclosure, fun, data); + break; + + case MU_ERR_INVALID_EMAIL: + /* + * The mu_message_unencapsulate function returns this code + * if it was unable to parse the message body as a RFC822 + * message (this code is propagated from mu_stream_to_message, + * which does the actual work). + * + * If the enclosing messgae(part) is of message/digest type, it + * is possible that messages are packed into it without MIME + * headers. That violates RFC 1341, but such digests are + * reported to exist (re. email conversation with Karl on + * 2020-08-07, <202008070138.0771cfHn003390@freefriends.org>). + * + * Try to see whether the part has one of the normal RFC822 headers + * and if so treat it as the message. Otherwise, treat it as + * text/plain. + * + * FIXME: Do all this only if the upper-level message is of + * message/digest type. + */ + { + char *names[] = { "From", "To", "Subject" }; + mu_header_t hdr; + + if (mu_message_get_header (closure->message, &hdr) == 0 && + mu_header_sget_firstof (hdr, names, NULL, NULL) == 0) + { + mu_stream_t str; + if (mu_message_get_streamref (closure->message, &str) == 0) + { + status = mu_stream_to_message (str, &submsg); + mu_stream_unref (str); + if (status == 0) + { + mu_header_t subhdr; + if (mu_message_get_header (submsg, &subhdr) == 0) + { + mu_header_remove (subhdr, + MU_HEADER_CONTENT_TYPE, 1); + subclosure.hints = MDHINT_SELECTED_HEADERS; + subclosure.msgset = closure->msgset; + subclosure.message = submsg; + status = mime_descend (&subclosure, fun, data); + break; + } + } + } + } + } + /* FALLTHROUGH */ + + default: + /* Treat as text/plain */ + status = fun (closure, data); } } else |