diff --git a/mime-node.c b/mime-node.c index cd3db67d..e33336bb 100644 --- a/mime-node.c +++ b/mime-node.c @@ -21,13 +21,16 @@ * Austin Clements */ +#include +#include +#include + #include "notmuch-client.h" /* Context that gets inherited from the root node. */ typedef struct mime_node_context { /* Per-message resources. These are allocated internally and must * be destroyed. */ - FILE *file; GMimeStream *stream; GMimeParser *parser; GMimeMessage *mime_message; @@ -48,9 +51,6 @@ _mime_node_context_free (mime_node_context_t *res) if (res->stream) g_object_unref (res->stream); - if (res->file) - fclose (res->file); - return 0; } @@ -62,6 +62,7 @@ mime_node_open (const void *ctx, notmuch_message_t *message, mime_node_context_t *mctx; mime_node_t *root; notmuch_status_t status; + int fd; root = talloc_zero (ctx, mime_node_t); if (root == NULL) { @@ -80,8 +81,8 @@ mime_node_open (const void *ctx, notmuch_message_t *message, talloc_set_destructor (mctx, _mime_node_context_free); /* Fast path */ - mctx->file = fopen (filename, "r"); - if (! mctx->file) { + fd = open (filename, O_RDONLY); + if (fd == -1) { /* Slow path - for some reason the first file in the list is * not available anymore. This is clearly a problem in the * database, but we are not going to let this problem be a @@ -92,13 +93,13 @@ mime_node_open (const void *ctx, notmuch_message_t *message, notmuch_filenames_move_to_next (filenames)) { filename = notmuch_filenames_get (filenames); - mctx->file = fopen (filename, "r"); - if (mctx->file) + fd = open (filename, O_RDONLY); + if (fd != -1) break; } talloc_free (filenames); - if (! mctx->file) { + if (fd == -1) { /* Give up */ fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno)); status = NOTMUCH_STATUS_FILE_ERROR; @@ -106,13 +107,12 @@ mime_node_open (const void *ctx, notmuch_message_t *message, } } - mctx->stream = g_mime_stream_file_new (mctx->file); + mctx->stream = g_mime_stream_gzfile_new (fd); if (!mctx->stream) { fprintf (stderr, "Out of memory.\n"); status = NOTMUCH_STATUS_OUT_OF_MEMORY; goto DONE; } - g_mime_stream_file_set_owner (GMIME_STREAM_FILE (mctx->stream), false); mctx->parser = g_mime_parser_new_with_stream (mctx->stream); if (!mctx->parser) { diff --git a/notmuch-show.c b/notmuch-show.c index 65167c2f..b95fc389 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -21,6 +21,7 @@ #include "notmuch-client.h" #include "gmime-filter-reply.h" #include "sprinter.h" +#include "zlib-extra.h" static const char * _get_tags_as_string (const void *ctx, notmuch_message_t *message) @@ -758,7 +759,7 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, notmuch_message_t *message = node->envelope_file; const char *filename; - FILE *file; + gzFile file; const char *from; time_t date; @@ -766,14 +767,14 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, char date_asctime[26]; char *line = NULL; - size_t line_size; + ssize_t line_size; ssize_t line_len; if (!message) INTERNAL_ERROR ("format_part_mbox requires a root part"); filename = notmuch_message_get_filename (message); - file = fopen (filename, "r"); + file = gzopen (filename, "r"); if (file == NULL) { fprintf (stderr, "Failed to open %s: %s\n", filename, strerror (errno)); @@ -789,7 +790,7 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, printf ("From %s %s", from, date_asctime); - while ((line_len = getline (&line, &line_size, file)) != -1 ) { + while ((line_len = gz_getline (message, &line, &line_size, file)) != UTIL_EOF ) { if (_is_from_line (line)) putchar ('>'); printf ("%s", line); @@ -797,7 +798,7 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node, printf ("\n"); - fclose (file); + gzclose (file); return NOTMUCH_STATUS_SUCCESS; } @@ -810,39 +811,44 @@ format_part_raw (unused (const void *ctx), unused (sprinter_t *sp), if (node->envelope_file) { /* Special case the entire message to avoid MIME parsing. */ const char *filename; - FILE *file; - size_t size; + GMimeStream *stream = NULL; + ssize_t ssize; char buf[4096]; + notmuch_status_t ret = NOTMUCH_STATUS_FILE_ERROR; filename = notmuch_message_get_filename (node->envelope_file); if (filename == NULL) { fprintf (stderr, "Error: Cannot get message filename.\n"); - return NOTMUCH_STATUS_FILE_ERROR; + goto DONE; } - file = fopen (filename, "r"); - if (file == NULL) { + stream = g_mime_stream_gzfile_open (filename); + if (stream == NULL) { fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno)); - return NOTMUCH_STATUS_FILE_ERROR; + goto DONE; } - while (!feof (file)) { - size = fread (buf, 1, sizeof (buf), file); - if (ferror (file)) { + while (! g_mime_stream_eos (stream)) { + ssize = g_mime_stream_read (stream, buf, sizeof(buf)); + if (ssize < 0) { fprintf (stderr, "Error: Read failed from %s\n", filename); - fclose (file); - return NOTMUCH_STATUS_FILE_ERROR; + goto DONE; } - if (fwrite (buf, size, 1, stdout) != 1) { - fprintf (stderr, "Error: Write failed\n"); - fclose (file); - return NOTMUCH_STATUS_FILE_ERROR; + if (ssize > 0 && fwrite (buf, ssize, 1, stdout) != 1) { + fprintf (stderr, "Error: Write %ld chars to stdout failed\n", ssize); + goto DONE; } } - fclose (file); - return NOTMUCH_STATUS_SUCCESS; + ret = NOTMUCH_STATUS_SUCCESS; + + /* XXX This DONE is just for the special case of a node in a single file */ + DONE: + if (stream) + g_object_unref (stream); + + return ret; } GMimeStream *stream_filter = g_mime_stream_filter_new (params->out_stream); diff --git a/test/T750-gzip.sh b/test/T750-gzip.sh index 96464956..5b678fa1 100755 --- a/test/T750-gzip.sh +++ b/test/T750-gzip.sh @@ -91,8 +91,35 @@ This is just a test message (#6) EOF test_expect_equal_file EXPECTED OUTPUT +test_begin_subtest "show un-gzipped message (format mbox)" +notmuch show --format=mbox id:msg-006@notmuch-test-suite | notmuch_show_sanitize > OUTPUT +cat < EXPECTED +From test_suite@notmuchmail.org Fri Jan 5 15:43:51 2001 +From: Notmuch Test Suite +To: Notmuch Test Suite +Message-Id: +Subject: Multiple new messages, one gzipped (full-scan) +Date: Fri, 05 Jan 2001 15:43:51 +0000 + +This is just a test message (#6) + +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "show un-gzipped message (format raw)" +notmuch show --format=raw id:msg-006@notmuch-test-suite | notmuch_show_sanitize > OUTPUT +cat < EXPECTED +From: Notmuch Test Suite +To: Notmuch Test Suite +Message-Id: +Subject: Multiple new messages, one gzipped (full-scan) +Date: Fri, 05 Jan 2001 15:43:51 +0000 + +This is just a test message (#6) +EOF +test_expect_equal_file EXPECTED OUTPUT + test_begin_subtest "show gzipped message" -test_subtest_known_broken notmuch show id:msg-007@notmuch-test-suite | notmuch_show_sanitize > OUTPUT cat < EXPECTED message{ id:msg-007@notmuch-test-suite depth:0 match:1 excluded:0 filename:/XXX/mail/msg-007.gz @@ -112,4 +139,32 @@ This is just a test message (#7) EOF test_expect_equal_file EXPECTED OUTPUT +test_begin_subtest "show gzipped message (mbox)" +notmuch show --format=mbox id:msg-007@notmuch-test-suite | notmuch_show_sanitize > OUTPUT +cat < EXPECTED +From test_suite@notmuchmail.org Fri Jan 5 15:43:50 2001 +From: Notmuch Test Suite +To: Notmuch Test Suite +Message-Id: +Subject: Renamed (gzipped) message +Date: Fri, 05 Jan 2001 15:43:50 +0000 + +This is just a test message (#7) + +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "show gzipped message (raw)" +notmuch show --format=raw id:msg-007@notmuch-test-suite | notmuch_show_sanitize > OUTPUT +cat < EXPECTED +From: Notmuch Test Suite +To: Notmuch Test Suite +Message-Id: +Subject: Renamed (gzipped) message +Date: Fri, 05 Jan 2001 15:43:50 +0000 + +This is just a test message (#7) +EOF +test_expect_equal_file EXPECTED OUTPUT + test_done