diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-05-27 23:00:10 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-05-29 12:12:05 +0300 |
commit | 55da31fa5954aaf2e41c27ba24b4300c32232d47 (patch) | |
tree | cec87f60375941299a07ccfece7db267dac27587 | |
parent | f9d6e59d678a540da08c8a7795f45621e9d49a9c (diff) | |
download | mailutils-55da31fa5954aaf2e41c27ba24b4300c32232d47.tar.gz mailutils-55da31fa5954aaf2e41c27ba24b4300c32232d47.tar.bz2 |
mail: write command operates on message parts as well as on messages
Messages or message parts are decoded before being written to a
disk file.
* include/mailutils/cstr.h (mu_mem_c_count): New proto.
* include/mailutils/stream.h (MU_STREAM_STAT_INLN)
(MU_STREAM_STAT_OUTLN): New constants.
* libmailutils/stream/stream.c (_stream_stat_incr)
(_stream_seek): Rewrite as inline functions.
(_stream_read, _stream_write): Rewrite as inline functions.
Optionally count number of lines read/written.
* libmailutils/string/strcount.c (mu_mem_c_count): New function.
* libmailutils/tests/fltst.c: Update.
* mail/decode.c (format_msgset): Remove. Use msgset_str
instead.
(print_message_body): New function.
* mail/mail.h (msgset_part_str)
(util_get_message_part): New protos.
(msgset_str): New function.
* mail/msgset.y: Change the message part syntax. Components are
separated by dots, instead of being enclosed in brackets. Old
syntax is still supported for compatibility.
* mail/struct.c (show_part): Use msgset_str.
* mail/testsuite/mail/read.exp: Fix expected strings.
* mail/util.c (util_get_message_part): New function.
* mail/write.c (mail_write): Write message part if requested.
Decode the body if the Content-Transfer-Encoding header is set.
-rw-r--r-- | NEWS | 29 | ||||
-rw-r--r-- | include/mailutils/cstr.h | 1 | ||||
-rw-r--r-- | include/mailutils/stream.h | 26 | ||||
-rw-r--r-- | libmailutils/stream/stream.c | 132 | ||||
-rw-r--r-- | libmailutils/string/strcount.c | 12 | ||||
-rw-r--r-- | libmailutils/tests/fltst.c | 9 | ||||
-rw-r--r-- | mail/decode.c | 114 | ||||
-rw-r--r-- | mail/mail.h | 12 | ||||
-rw-r--r-- | mail/msgset.y | 48 | ||||
-rw-r--r-- | mail/struct.c | 16 | ||||
-rw-r--r-- | mail/testsuite/mail/read.exp | 18 | ||||
-rw-r--r-- | mail/util.c | 46 | ||||
-rw-r--r-- | mail/write.c | 25 |
13 files changed, 362 insertions, 126 deletions
@@ -1,9 +1,36 @@ -GNU mailutils NEWS -- history of user-visible changes. 2020-03-13 +GNU mailutils NEWS -- history of user-visible changes. 2020-05-29 Copyright (C) 2002-2019 Free Software Foundation, Inc. See the end of file for copying conditions. Please send mailutils bug reports to <bug-mailutils@gnu.org>. +Version 3.9.90 (Git) + +* mail + +** Changed syntax for addressing MIME message part. + +The familiar dot notation is used. E.g. 1.2 extracts part 2 +from multipart message 1. + +** write command + +The write (Write) command operates on message parts as well as on +messages. Decoding is automatic. + +* imap4d: implement TLS in inetd mode + +* imap client code + +** Fix handling of [TRYCREATE] and similar imap responses. + +* Remove deprecated mailutils-config script + +* Bugfixes + +** Fix intermixed I/O in buffered streams. + + Version 3.9, 2020-03-13 * dotmail: fix mailbox opening in append-only mode diff --git a/include/mailutils/cstr.h b/include/mailutils/cstr.h index 5c3f942d5..860b44e0e 100644 --- a/include/mailutils/cstr.h +++ b/include/mailutils/cstr.h @@ -50,6 +50,7 @@ char *mu_str_stripws (char *string); int mu_string_split (const char *string, char *delim, mu_list_t list); size_t mu_str_count (char const *str, char const *chr, size_t *cnt); +size_t mu_mem_c_count (char const *str, int c, size_t len); int mu_c_str_escape (char const *str, char const *chr, char const *xtab, char **ret_str); diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index 1c67c4880..327493870 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -270,22 +270,30 @@ struct mu_buffer_query size_t bufsize; /* Buffer size */ }; -/* Statistics */ -#define MU_STREAM_STAT_IN 0 -#define MU_STREAM_STAT_OUT 1 -#define MU_STREAM_STAT_READS 2 -#define MU_STREAM_STAT_WRITES 3 -#define MU_STREAM_STAT_SEEKS 4 -#define _MU_STREAM_STAT_MAX 5 +/* Statistics */ +enum + { + MU_STREAM_STAT_IN, /* Bytes read */ + MU_STREAM_STAT_OUT, /* Bytes written */ + MU_STREAM_STAT_READS, /* Number of reads */ + MU_STREAM_STAT_WRITES, /* Number of writes */ + MU_STREAM_STAT_SEEKS, /* Number of seeks */ + MU_STREAM_STAT_INLN, /* Lines read */ + MU_STREAM_STAT_OUTLN, /* Lines written */ + _MU_STREAM_STAT_MAX + }; #define MU_STREAM_STAT_MASK(n) (1U<<(n+1)) + #define MU_STREAM_STAT_MASK_ALL \ (MU_STREAM_STAT_MASK (MU_STREAM_STAT_IN) | \ MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT) | \ MU_STREAM_STAT_MASK (MU_STREAM_STAT_READS) | \ MU_STREAM_STAT_MASK (MU_STREAM_STAT_WRITES) | \ - MU_STREAM_STAT_MASK (MU_STREAM_STAT_SEEKS)) - + MU_STREAM_STAT_MASK (MU_STREAM_STAT_SEEKS) | \ + MU_STREAM_STAT_MASK (MU_STREAM_STAT_INLN) | \ + MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUTLN)) + typedef mu_off_t mu_stream_stat_buffer[_MU_STREAM_STAT_MAX]; int mu_stream_set_stat (mu_stream_t stream, int statmask, mu_stream_stat_buffer statbuf); diff --git a/libmailutils/stream/stream.c b/libmailutils/stream/stream.c index 03956cfe7..d93faa7bb 100644 --- a/libmailutils/stream/stream.c +++ b/libmailutils/stream/stream.c @@ -30,44 +30,64 @@ #include <mailutils/errno.h> #include <mailutils/nls.h> #include <mailutils/stream.h> +#include <mailutils/cstr.h> #include <mailutils/sys/stream.h> size_t mu_stream_default_buffer_size = MU_STREAM_DEFBUFSIZ; -#define _stream_event(stream, code, n, p) \ - do \ - { \ - if ((stream)->event_cb && \ - ((stream)->event_mask & _MU_STR_EVMASK(code))) \ - (stream)->event_cb (stream, code, n, p); \ - } \ - while (0) - -#define _bootstrap_event(stream) \ - do \ - { \ - if ((stream)->event_cb && \ - ((stream)->event_mask & _MU_STR_EVMASK(_MU_STR_EVENT_BOOTSTRAP))) \ - { \ - (stream)->event_cb (stream, _MU_STR_EVENT_BOOTSTRAP, 0, NULL); \ - (stream)->event_mask &= ~_MU_STR_EVMASK(_MU_STR_EVENT_BOOTSTRAP); \ - } \ - } \ - while (0) - +static inline void +_stream_event (mu_stream_t str, int code, unsigned long n, void *p) +{ + if (str->event_cb && (str->event_mask & _MU_STR_EVMASK (code))) + str->event_cb (str, code, n, p); +} + +static inline void +_bootstrap_event (mu_stream_t str) +{ + if (str->event_cb && + (str->event_mask & _MU_STR_EVMASK (_MU_STR_EVENT_BOOTSTRAP))) + { + str->event_cb (str, _MU_STR_EVENT_BOOTSTRAP, 0, NULL); + str->event_mask &= ~_MU_STR_EVMASK (_MU_STR_EVENT_BOOTSTRAP); + } +} + +static inline void +_stream_stat_incr (mu_stream_t s, int k, size_t n) +{ + if (s->statmask & MU_STREAM_STAT_MASK (k)) + s->statbuf[k] += n; +} -#define _stream_stat_incr(s, k, n) \ - (((s)->statmask & MU_STREAM_STAT_MASK(k)) ? ((s)->statbuf[k] += n) : 0) +static inline int +_stream_read (mu_stream_t str, char *buf, size_t size, size_t *pbytes) +{ + int rc; + _stream_stat_incr (str, MU_STREAM_STAT_READS, 1); + rc = str->read (str, buf, size, pbytes); + if (rc == 0 && str->statmask & MU_STREAM_STAT_MASK (MU_STREAM_STAT_INLN)) + str->statbuf[MU_STREAM_STAT_INLN] += mu_mem_c_count (buf, '\n', *pbytes); + return rc; +} + +static inline int +_stream_write (mu_stream_t str, char const *buf, size_t size, size_t *pbytes) +{ + int rc; + _stream_stat_incr (str, MU_STREAM_STAT_WRITES, 1); + rc = str->write (str, buf, size, pbytes); + if (rc == 0 && str->statmask & MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUTLN)) + str->statbuf[MU_STREAM_STAT_OUTLN] += mu_mem_c_count (buf, '\n', *pbytes); + return rc; +} -#define _stream_read(str, buf, size, rdbytes) \ - (_stream_stat_incr ((str), MU_STREAM_STAT_READS, 1), \ - (str)->read (str, buf, size, rdbytes)) -#define _stream_write(str, buf, size, wrbytes) \ - (_stream_stat_incr ((str), MU_STREAM_STAT_WRITES, 1), \ - (str)->write (str, buf, size, wrbytes)) -#define _stream_seek(str, pos, poff) \ - (_stream_stat_incr ((str), MU_STREAM_STAT_SEEKS, 1), \ - (str)->seek (str, pos, poff)) +static inline int +_stream_seek (mu_stream_t str, mu_off_t pos, mu_off_t *poff) +{ + _stream_stat_incr (str, MU_STREAM_STAT_SEEKS, 1); + return str->seek (str, pos, poff); +} static int _stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, int full_read, size_t *pnread); @@ -75,14 +95,14 @@ static int _stream_write_unbuffered (mu_stream_t stream, const void *buf, size_t size, int full_write, size_t *pnwritten); -static void +static inline void _stream_setflag (struct _mu_stream *stream, int flag) { _stream_event (stream, _MU_STR_EVENT_SETFLAG, flag, NULL); stream->flags |= flag; } -static void +static inline void _stream_clrflag (struct _mu_stream *stream, int flag) { _stream_event (stream, _MU_STR_EVENT_CLRFLAG, flag, NULL); @@ -171,28 +191,6 @@ _stream_fill_buffer (struct _mu_stream *stream) return rc; } -/* Return 1 if no more data can be written to the current buffer. */ -static inline int -_stream_buffer_full_p (struct _mu_stream *stream) -{ - /* This function should be called only for buffered streams */ - if (stream->buftype == mu_buffer_none) - return 0; - - if (stream->bufsize == stream->pos) - /* No space left in buffer */ - return 1; - - /* For line buffering, the buffer is flushed immediately after - receiving a newline character. */ - if (stream->buftype == mu_buffer_line && - stream->pos > 0 && - memchr (stream->buffer, '\n', stream->pos) != NULL) - return 1; - - return 0; -} - enum { FLUSH_WRITE, /* Flush only modified data. Keep buffer level and position @@ -977,6 +975,28 @@ mu_stream_getline (mu_stream_t stream, char **pbuf, size_t *psize, return mu_stream_getdelim (stream, pbuf, psize, '\n', pread); } +/* Return 1 if no more data can be written to the current buffer. */ +static inline int +_stream_buffer_full_p (struct _mu_stream *stream) +{ + /* This function should be called only for buffered streams */ + if (stream->buftype == mu_buffer_none) + return 0; + + if (stream->bufsize == stream->pos) + /* No space left in buffer */ + return 1; + + /* For line buffering, the buffer is flushed immediately after + receiving a newline character. */ + if (stream->buftype == mu_buffer_line && + stream->pos > 0 && + memchr (stream->buffer, '\n', stream->pos) != NULL) + return 1; + + return 0; +} + int mu_stream_write (mu_stream_t stream, const void *buf, size_t size, size_t *pnwritten) diff --git a/libmailutils/string/strcount.c b/libmailutils/string/strcount.c index ccd50a988..c54a2e4a3 100644 --- a/libmailutils/string/strcount.c +++ b/libmailutils/string/strcount.c @@ -64,3 +64,15 @@ mu_str_count (char const *str, char const *chr, size_t *cnt) } return count; } + +/* Find the number of occurrences of character C in byte array + STR of length LEN. */ +size_t +mu_mem_c_count (char const *str, int c, size_t len) +{ + size_t n = 0; + while (len--) + if (*str++ == c) + n++; + return n; +} diff --git a/libmailutils/tests/fltst.c b/libmailutils/tests/fltst.c index 8cb11fe18..6b8417da5 100644 --- a/libmailutils/tests/fltst.c +++ b/libmailutils/tests/fltst.c @@ -190,6 +190,11 @@ main (int argc, char * argv []) (unsigned long) instat[MU_STREAM_STAT_IN]); fprintf (stderr, "Bytes out: %lu\n", (unsigned long) instat[MU_STREAM_STAT_OUT]); + fprintf (stderr, "Lines in: %lu\n", + (unsigned long) instat[MU_STREAM_STAT_INLN]); + fprintf (stderr, "Linees out: %lu\n", + (unsigned long) instat[MU_STREAM_STAT_OUTLN]); + fprintf (stderr, "Reads: %lu\n", (unsigned long) instat[MU_STREAM_STAT_READS]); fprintf (stderr, "Seeks: %lu\n", @@ -200,6 +205,10 @@ main (int argc, char * argv []) (unsigned long) outstat[MU_STREAM_STAT_IN]); fprintf (stderr, "Bytes out: %lu\n", (unsigned long) outstat[MU_STREAM_STAT_OUT]); + fprintf (stderr, "Lines in: %lu\n", + (unsigned long) outstat[MU_STREAM_STAT_INLN]); + fprintf (stderr, "Lines out: %lu\n", + (unsigned long) outstat[MU_STREAM_STAT_OUTLN]); fprintf (stderr, "Writes: %lu\n", (unsigned long) outstat[MU_STREAM_STAT_WRITES]); fprintf (stderr, "Seeks: %lu\n", diff --git a/mail/decode.c b/mail/decode.c index 5e33d3443..453889d7f 100644 --- a/mail/decode.c +++ b/mail/decode.c @@ -121,41 +121,22 @@ display_headers (mu_stream_t out, mu_message_t mesg, } } -void -format_msgset (mu_stream_t str, const msgset_t *msgset, size_t *count) -{ - int i; - mu_stream_stat_buffer stat; - - if (count) - mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), - stat); - mu_stream_printf (str, "%lu", (unsigned long) msgset->msg_part[0]); - for (i = 1; i < msgset->npart; i++) - mu_stream_printf (str, "[%lu", (unsigned long) msgset->msg_part[i]); - for (i = 1; i < msgset->npart; i++) - mu_stream_printf (str, "]"); - if (count) - { - *count = stat[MU_STREAM_STAT_OUT]; - mu_stream_set_stat (str, 0, NULL); - } -} - static void display_part_header (mu_stream_t str, const msgset_t *msgset, const char *type, const char *encoding) { int size = util_screen_columns () - 3; unsigned int i; - + char *msp; + mu_stream_printf (str, "+"); for (i = 0; (int)i <= size; i++) mu_stream_printf (str, "-"); mu_stream_printf (str, "+"); mu_stream_printf (str, "\n"); - mu_stream_printf (str, "%s", _("| Message=")); - format_msgset (str, msgset, NULL); + msp = msgset_str (msgset); + mu_stream_printf (str, _("| Message=%s"), msp); + free (msp); mu_stream_printf (str, "\n"); mu_stream_printf (str, _("| Type=%s\n"), type); @@ -449,3 +430,88 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg) sigaction (SIGQUIT, &savequit, NULL); sigprocmask (SIG_SETMASK, &savemask, NULL); } + +/* print_message_body(msg, out, stat) + * + * Prints the body of the message MSG to the output stream OUT. If + * the Content-Transfer-Encoding header is set, the body is decoded. + * If stat is not NULL, it must point to an array of two size_t. + * Upon return stat[0] will contain the number of bytes and stat[0] + * the number of newline characters written to the output. + */ +int +print_message_body (mu_message_t msg, mu_stream_t out, size_t *stat) +{ + int rc; + mu_header_t hdr; + mu_body_t body; + mu_stream_t d_stream; + mu_stream_t stream; + char *encoding = NULL; + mu_stream_stat_buffer sb; + + rc = mu_message_get_header (msg, &hdr); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_header", + NULL, rc); + return rc; + } + + rc = mu_message_get_body (msg, &body); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_body", + NULL, rc); + return rc; + } + + rc = mu_body_get_streamref (body, &stream); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_body_get_streamref", + NULL, rc); + return rc; + } + + util_get_hdr_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &encoding); + if (encoding == NULL || *encoding == '\0') + /* No need to filter */; + else if ((rc = mu_filter_create (&d_stream, stream, encoding, + MU_FILTER_DECODE, MU_STREAM_READ)) == 0) + { + mu_stream_unref (stream); + stream = d_stream; + } + else + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_body", + encoding, rc); + /* FIXME: continue anyway? */ + } + + if (stat) + { + mu_stream_set_stat (stream, + MU_STREAM_STAT_MASK (MU_STREAM_STAT_IN) | + MU_STREAM_STAT_MASK (MU_STREAM_STAT_INLN), + sb); + } + rc = mu_stream_copy (out, stream, 0, NULL); + + mu_stream_destroy (&stream); + free (encoding); + + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_copy", + encoding, rc); + } + else if (stat) + { + stat[0] = sb[MU_STREAM_STAT_IN]; + stat[1] = sb[MU_STREAM_STAT_INLN]; + } + + return rc; +} diff --git a/mail/mail.h b/mail/mail.h index 386bcc610..50f87394b 100644 --- a/mail/mail.h +++ b/mail/mail.h @@ -402,6 +402,12 @@ int msgset_parse (const int argc, char **argv, int flags, msgset_t **mset); int msgset_member (msgset_t *set, size_t n); msgset_t *msgset_negate (msgset_t *set); size_t msgset_count (msgset_t *set); +char *msgset_part_str (msgset_t const *msgset, size_t npart); +static inline char * +msgset_str (const msgset_t *msgset) +{ + return msgset_part_str (msgset, msgset->npart); +} #define MDHINT_SELECTED_HEADERS 0x1 @@ -490,6 +496,9 @@ void util_get_hdr_value (mu_header_t hdr, const char *name, char **value); int util_merge_addresses (char **addr_str, const char *value); int util_header_expand (mu_header_t *hdr); int util_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *msg); +int util_get_message_part (mu_mailbox_t mbox, msgset_t *msgset, + mu_message_t *ret_msg); + void util_cache_command (mu_list_t *list, const char *fmt, ...) MU_PRINTFLIKE(2,3); void util_run_cached_commands (mu_list_t *list); @@ -503,7 +512,8 @@ const char *util_url_to_string (mu_url_t url); mu_stream_t open_pager (size_t lines); -void format_msgset (mu_stream_t str, const msgset_t *msgset, size_t *count); +int print_message_body (mu_message_t msg, mu_stream_t out, size_t *stat); + char *sender_string (mu_message_t msg); int is_address_field (const char *name); diff --git a/mail/msgset.y b/mail/msgset.y index 17c96299c..6ab60c1ba 100644 --- a/mail/msgset.y +++ b/mail/msgset.y @@ -133,6 +133,12 @@ msgexpr : msgspec ; msgspec : msg + | msg '.' rangeset + { + $$ = msgset_expand ($1, $3); + msgset_free ($1); + msgset_free ($3); + } | msg '[' rangeset ']' { $$ = msgset_expand ($1, $3); @@ -237,6 +243,12 @@ range : number number : partno { } + | partno '.' rangeset + { + $$ = msgset_expand ($1, $3); + msgset_free ($1); + msgset_free ($3); + } | partno '[' rangeset ']' { $$ = msgset_expand ($1, $3); @@ -942,6 +954,42 @@ check_set (msgset_t **pset) return rc; } +char * +msgset_part_str (const msgset_t *msgset, size_t npart) +{ + size_t len = 0; + size_t i; + char *result, *p; + + for (i = 0; i < npart; i++) + { + size_t n = msgset->msg_part[i]; + do + len++; + while (n /= 10); + len++; + } + + result = malloc (len); + p = result; + + for (i = 0; i < npart; i++) + { + size_t n = msgset->msg_part[i]; + if (i) + *p++ = '.'; + do + { + unsigned x = n % 10; + *p++ = x + '0'; + } + while (n /= 10); + } + *p = 0; + + return result; +} + #if 0 void msgset_print (msgset_t *mset) diff --git a/mail/struct.c b/mail/struct.c index 31f7eb91f..42d76a2b1 100644 --- a/mail/struct.c +++ b/mail/struct.c @@ -16,20 +16,16 @@ #include "mail.h" -#define PART_WIDTH 8 - static int show_part (struct mime_descend_closure *closure, void *data) { - size_t width; - size_t size = 0; + char *msp; + size_t size; + + msp = msgset_str (closure->msgset); + mu_printf ("%-16s %-25s", msp, closure->type); + free (msp); - format_msgset (mu_strout, closure->msgset, &width); - for (; width < 5; width++) - mu_stream_write (mu_strout, " ", 1, NULL); - - mu_printf (" %-25s", closure->type); - mu_message_size (closure->message, &size); if (size < 1024) mu_printf (" %4lu", (unsigned long) size); diff --git a/mail/testsuite/mail/read.exp b/mail/testsuite/mail/read.exp index 25c044dc7..d9108c5b8 100644 --- a/mail/testsuite/mail/read.exp +++ b/mail/testsuite/mail/read.exp @@ -240,7 +240,7 @@ mail_test -message "print (2)" "print 2"\ mail_test -message "decoding simple MIME messages" \ "decode 3" \ "+------------------------------------------------------------------------------+"\ -"| Message=3\[1\]"\ +"| Message=3.1"\ "| Type=text/plain; name=\"msg.1\"; charset=\"us-ascii\""\ "| Encoding=7bit"\ "+------------------------------------------------------------------------------+"\ @@ -258,7 +258,7 @@ mail_test -message "decoding simple MIME messages" \ "And welcome little fishes in"\ "With gently smiling jaws!"\ "+------------------------------------------------------------------------------+"\ -"| Message=3\[2\]"\ +"| Message=3.2"\ "| Type=application/octet-stream; name=\"msg.21\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ @@ -280,7 +280,7 @@ mail_test -message "decoding simple MIME messages" \ mail_test -message "decoding nested MIME messages" \ "decode 4" \ "+------------------------------------------------------------------------------+"\ -"| Message=4\[1\]"\ +"| Message=4.1"\ "| Type=text/plain; name=\"msg.21\"; charset=\"us-ascii\""\ "| Encoding=7bit"\ "+------------------------------------------------------------------------------+"\ @@ -299,7 +299,7 @@ mail_test -message "decoding nested MIME messages" \ "Why, I do it again and again.'"\ ""\ "+------------------------------------------------------------------------------+"\ -"| Message=4\[2\[1\]\]"\ +"| Message=4.2.1"\ "| Type=application/octet-stream; name=\"msg.22\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ @@ -318,7 +318,7 @@ mail_test -message "decoding nested MIME messages" \ "By the use of this ointment--one shilling the box--"\ "Allow me to sell you a couple?'"\ "+------------------------------------------------------------------------------+"\ -"| Message=4\[2\[2\[1\]\]\]"\ +"| Message=4.2.2.1"\ "| Type=application/octet-stream; name=\"msg.23\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ @@ -337,7 +337,7 @@ mail_test -message "decoding nested MIME messages" \ "And the muscular strength, which it gave to my jaw,"\ "Has lasted the rest of my life.'"\ "+------------------------------------------------------------------------------+"\ -"| Message=4\[2\[2\[2\]\]\]"\ +"| Message=4.2.2.2"\ "| Type=application/octet-stream; name=\"msg.24\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ @@ -359,7 +359,7 @@ mail_test -message "decoding nested MIME messages" \ mail_test -message "Addressing parts of a MIME message" \ "decode 4\[2\[2\[1\]\]\]" \ "+------------------------------------------------------------------------------+"\ -"| Message=4\[2\[2\[1\]\]\]"\ +"| Message=4.2.2.1"\ "| Type=application/octet-stream; name=\"msg.23\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ @@ -381,7 +381,7 @@ mail_test -message "Addressing parts of a MIME message" \ mail_test -message "Addressing parts of a MIME message (2)" \ "decode 4\[2\[2\[1,2\]\]\]"\ "+------------------------------------------------------------------------------+"\ -"| Message=4\[2\[2\[1\]\]\]"\ +"| Message=4.2.2.1"\ "| Type=application/octet-stream; name=\"msg.23\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ @@ -400,7 +400,7 @@ mail_test -message "Addressing parts of a MIME message (2)" \ "And the muscular strength, which it gave to my jaw,"\ "Has lasted the rest of my life.'"\ "+------------------------------------------------------------------------------+"\ -"| Message=4\[2\[2\[2\]\]\]"\ +"| Message=4.2.2.2"\ "| Type=application/octet-stream; name=\"msg.24\""\ "| Encoding=base64"\ "+------------------------------------------------------------------------------+"\ diff --git a/mail/util.c b/mail/util.c index a07c84451..7ebf2e1ca 100644 --- a/mail/util.c +++ b/mail/util.c @@ -1008,6 +1008,52 @@ util_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *msg) } int +util_get_message_part (mu_mailbox_t mbox, msgset_t *msgset, + mu_message_t *ret_msg) +{ + int status, ismime; + mu_message_t msg; + size_t i; + + status = mu_mailbox_get_message (mbox, msgset->msg_part[0], &msg); + if (status) + { + mu_error (_("Cannot get message %lu: %s"), + (unsigned long) msgset->msg_part[0], mu_strerror (status)); + return status; + } + + for (i = 1; i < msgset->npart; i++) + { + status = mu_message_is_multipart (msg, &ismime); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_is_multipart", + NULL, status); + return status; + } + + if (!ismime) + { + char *s = msgset_part_str (msgset, i); + mu_error (_("%s: not a multipart message"), s); + free (s); + return status; + } + + status = mu_message_get_part (msg, msgset->msg_part[i], &msg); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_part", + NULL, status); + return status; + } + } + *ret_msg = msg; + return 0; +} + +int util_error_range (size_t msgno) { mu_error (_("%lu: invalid message number"), (unsigned long) msgno); diff --git a/mail/write.c b/mail/write.c index 7d5dac031..abac9617f 100644 --- a/mail/write.c +++ b/mail/write.c @@ -30,7 +30,7 @@ mail_write (int argc, char **argv) char *filename = NULL; msgset_t *msglist = NULL, *mp; int sender = 0; - size_t total_size = 0, total_lines = 0, size; + size_t total_size = 0, total_lines = 0; if (mu_isupper (argv[0][0])) sender = 1; @@ -80,28 +80,21 @@ mail_write (int argc, char **argv) for (mp = msglist; mp; mp = mp->next) { mu_message_t msg; - mu_body_t body; - mu_stream_t stream; mu_attribute_t attr; - - if (util_get_message (mbox, mp->msg_part[0], &msg)) + size_t stat[2]; + + if (util_get_message_part (mbox, mp, &msg)) continue; - mu_message_get_body (msg, &body); - - mu_body_get_streamref (body, &stream); - rc = mu_stream_copy (output, stream, 0, NULL); - mu_stream_destroy (&stream); - + rc = print_message_body (msg, output, &stat); if (rc == 0) { - mu_body_size (body, &size); - total_size += size; - mu_body_lines (body, &size); - total_lines += size; + total_size += stat[0]; + total_lines += stat[1]; /* mark as saved. */ - + if (mp->npart > 1) + util_get_message (mbox, mp->msg_part[0], &msg); mu_message_get_attribute (msg, &attr); mu_attribute_set_userflag (attr, MAIL_ATTRIBUTE_SAVED); } |