summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-05-27 23:00:10 +0300
committerSergey Poznyakoff <gray@gnu.org>2020-05-29 12:12:05 +0300
commit55da31fa5954aaf2e41c27ba24b4300c32232d47 (patch)
treecec87f60375941299a07ccfece7db267dac27587
parentf9d6e59d678a540da08c8a7795f45621e9d49a9c (diff)
downloadmailutils-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--NEWS29
-rw-r--r--include/mailutils/cstr.h1
-rw-r--r--include/mailutils/stream.h26
-rw-r--r--libmailutils/stream/stream.c132
-rw-r--r--libmailutils/string/strcount.c12
-rw-r--r--libmailutils/tests/fltst.c9
-rw-r--r--mail/decode.c114
-rw-r--r--mail/mail.h12
-rw-r--r--mail/msgset.y48
-rw-r--r--mail/struct.c16
-rw-r--r--mail/testsuite/mail/read.exp18
-rw-r--r--mail/util.c46
-rw-r--r--mail/write.c25
13 files changed, 362 insertions, 126 deletions
diff --git a/NEWS b/NEWS
index ad82e46c3..74bdece61 100644
--- a/NEWS
+++ b/NEWS
@@ -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);
}

Return to:

Send suggestions and report system problems to the System administrator.