mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-21 18:38:08 +01:00
cli/notmuch-show: support gzipped files
This drops "file" from mime_node_context and just uses a local variable. It also uses the new gzip aware utility routines recently added to util/gmime-extra.c. The use of gzopen / gzfile in addition is a bit icky, but the choice is between that, and providing yet another readline implimentation that understands GMime streams.
This commit is contained in:
parent
852167479f
commit
103c11822e
3 changed files with 95 additions and 34 deletions
22
mime-node.c
22
mime-node.c
|
@ -21,13 +21,16 @@
|
||||||
* Austin Clements <aclements@csail.mit.edu>
|
* Austin Clements <aclements@csail.mit.edu>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "notmuch-client.h"
|
#include "notmuch-client.h"
|
||||||
|
|
||||||
/* Context that gets inherited from the root node. */
|
/* Context that gets inherited from the root node. */
|
||||||
typedef struct mime_node_context {
|
typedef struct mime_node_context {
|
||||||
/* Per-message resources. These are allocated internally and must
|
/* Per-message resources. These are allocated internally and must
|
||||||
* be destroyed. */
|
* be destroyed. */
|
||||||
FILE *file;
|
|
||||||
GMimeStream *stream;
|
GMimeStream *stream;
|
||||||
GMimeParser *parser;
|
GMimeParser *parser;
|
||||||
GMimeMessage *mime_message;
|
GMimeMessage *mime_message;
|
||||||
|
@ -48,9 +51,6 @@ _mime_node_context_free (mime_node_context_t *res)
|
||||||
if (res->stream)
|
if (res->stream)
|
||||||
g_object_unref (res->stream);
|
g_object_unref (res->stream);
|
||||||
|
|
||||||
if (res->file)
|
|
||||||
fclose (res->file);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ mime_node_open (const void *ctx, notmuch_message_t *message,
|
||||||
mime_node_context_t *mctx;
|
mime_node_context_t *mctx;
|
||||||
mime_node_t *root;
|
mime_node_t *root;
|
||||||
notmuch_status_t status;
|
notmuch_status_t status;
|
||||||
|
int fd;
|
||||||
|
|
||||||
root = talloc_zero (ctx, mime_node_t);
|
root = talloc_zero (ctx, mime_node_t);
|
||||||
if (root == NULL) {
|
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);
|
talloc_set_destructor (mctx, _mime_node_context_free);
|
||||||
|
|
||||||
/* Fast path */
|
/* Fast path */
|
||||||
mctx->file = fopen (filename, "r");
|
fd = open (filename, O_RDONLY);
|
||||||
if (! mctx->file) {
|
if (fd == -1) {
|
||||||
/* Slow path - for some reason the first file in the list is
|
/* Slow path - for some reason the first file in the list is
|
||||||
* not available anymore. This is clearly a problem in the
|
* not available anymore. This is clearly a problem in the
|
||||||
* database, but we are not going to let this problem be a
|
* 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))
|
notmuch_filenames_move_to_next (filenames))
|
||||||
{
|
{
|
||||||
filename = notmuch_filenames_get (filenames);
|
filename = notmuch_filenames_get (filenames);
|
||||||
mctx->file = fopen (filename, "r");
|
fd = open (filename, O_RDONLY);
|
||||||
if (mctx->file)
|
if (fd != -1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
talloc_free (filenames);
|
talloc_free (filenames);
|
||||||
if (! mctx->file) {
|
if (fd == -1) {
|
||||||
/* Give up */
|
/* Give up */
|
||||||
fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
|
fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
|
||||||
status = NOTMUCH_STATUS_FILE_ERROR;
|
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) {
|
if (!mctx->stream) {
|
||||||
fprintf (stderr, "Out of memory.\n");
|
fprintf (stderr, "Out of memory.\n");
|
||||||
status = NOTMUCH_STATUS_OUT_OF_MEMORY;
|
status = NOTMUCH_STATUS_OUT_OF_MEMORY;
|
||||||
goto DONE;
|
goto DONE;
|
||||||
}
|
}
|
||||||
g_mime_stream_file_set_owner (GMIME_STREAM_FILE (mctx->stream), false);
|
|
||||||
|
|
||||||
mctx->parser = g_mime_parser_new_with_stream (mctx->stream);
|
mctx->parser = g_mime_parser_new_with_stream (mctx->stream);
|
||||||
if (!mctx->parser) {
|
if (!mctx->parser) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "notmuch-client.h"
|
#include "notmuch-client.h"
|
||||||
#include "gmime-filter-reply.h"
|
#include "gmime-filter-reply.h"
|
||||||
#include "sprinter.h"
|
#include "sprinter.h"
|
||||||
|
#include "zlib-extra.h"
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
_get_tags_as_string (const void *ctx, notmuch_message_t *message)
|
_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;
|
notmuch_message_t *message = node->envelope_file;
|
||||||
|
|
||||||
const char *filename;
|
const char *filename;
|
||||||
FILE *file;
|
gzFile file;
|
||||||
const char *from;
|
const char *from;
|
||||||
|
|
||||||
time_t date;
|
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 date_asctime[26];
|
||||||
|
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t line_size;
|
ssize_t line_size;
|
||||||
ssize_t line_len;
|
ssize_t line_len;
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
INTERNAL_ERROR ("format_part_mbox requires a root part");
|
INTERNAL_ERROR ("format_part_mbox requires a root part");
|
||||||
|
|
||||||
filename = notmuch_message_get_filename (message);
|
filename = notmuch_message_get_filename (message);
|
||||||
file = fopen (filename, "r");
|
file = gzopen (filename, "r");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
fprintf (stderr, "Failed to open %s: %s\n",
|
fprintf (stderr, "Failed to open %s: %s\n",
|
||||||
filename, strerror (errno));
|
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);
|
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))
|
if (_is_from_line (line))
|
||||||
putchar ('>');
|
putchar ('>');
|
||||||
printf ("%s", line);
|
printf ("%s", line);
|
||||||
|
@ -797,7 +798,7 @@ format_part_mbox (const void *ctx, unused (sprinter_t *sp), mime_node_t *node,
|
||||||
|
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
|
|
||||||
fclose (file);
|
gzclose (file);
|
||||||
|
|
||||||
return NOTMUCH_STATUS_SUCCESS;
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -810,39 +811,44 @@ format_part_raw (unused (const void *ctx), unused (sprinter_t *sp),
|
||||||
if (node->envelope_file) {
|
if (node->envelope_file) {
|
||||||
/* Special case the entire message to avoid MIME parsing. */
|
/* Special case the entire message to avoid MIME parsing. */
|
||||||
const char *filename;
|
const char *filename;
|
||||||
FILE *file;
|
GMimeStream *stream = NULL;
|
||||||
size_t size;
|
ssize_t ssize;
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
notmuch_status_t ret = NOTMUCH_STATUS_FILE_ERROR;
|
||||||
|
|
||||||
filename = notmuch_message_get_filename (node->envelope_file);
|
filename = notmuch_message_get_filename (node->envelope_file);
|
||||||
if (filename == NULL) {
|
if (filename == NULL) {
|
||||||
fprintf (stderr, "Error: Cannot get message filename.\n");
|
fprintf (stderr, "Error: Cannot get message filename.\n");
|
||||||
return NOTMUCH_STATUS_FILE_ERROR;
|
goto DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = fopen (filename, "r");
|
stream = g_mime_stream_gzfile_open (filename);
|
||||||
if (file == NULL) {
|
if (stream == NULL) {
|
||||||
fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno));
|
fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno));
|
||||||
return NOTMUCH_STATUS_FILE_ERROR;
|
goto DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!feof (file)) {
|
while (! g_mime_stream_eos (stream)) {
|
||||||
size = fread (buf, 1, sizeof (buf), file);
|
ssize = g_mime_stream_read (stream, buf, sizeof(buf));
|
||||||
if (ferror (file)) {
|
if (ssize < 0) {
|
||||||
fprintf (stderr, "Error: Read failed from %s\n", filename);
|
fprintf (stderr, "Error: Read failed from %s\n", filename);
|
||||||
fclose (file);
|
goto DONE;
|
||||||
return NOTMUCH_STATUS_FILE_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite (buf, size, 1, stdout) != 1) {
|
if (ssize > 0 && fwrite (buf, ssize, 1, stdout) != 1) {
|
||||||
fprintf (stderr, "Error: Write failed\n");
|
fprintf (stderr, "Error: Write %ld chars to stdout failed\n", ssize);
|
||||||
fclose (file);
|
goto DONE;
|
||||||
return NOTMUCH_STATUS_FILE_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose (file);
|
ret = NOTMUCH_STATUS_SUCCESS;
|
||||||
return 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);
|
GMimeStream *stream_filter = g_mime_stream_filter_new (params->out_stream);
|
||||||
|
|
|
@ -91,8 +91,35 @@ This is just a test message (#6)
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
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 <<EOF > EXPECTED
|
||||||
|
From test_suite@notmuchmail.org Fri Jan 5 15:43:51 2001
|
||||||
|
From: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
To: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
Message-Id: <msg-006@notmuch-test-suite>
|
||||||
|
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 <<EOF > EXPECTED
|
||||||
|
From: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
To: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
Message-Id: <msg-006@notmuch-test-suite>
|
||||||
|
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_begin_subtest "show gzipped message"
|
||||||
test_subtest_known_broken
|
|
||||||
notmuch show id:msg-007@notmuch-test-suite | notmuch_show_sanitize > OUTPUT
|
notmuch show id:msg-007@notmuch-test-suite | notmuch_show_sanitize > OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
message{ id:msg-007@notmuch-test-suite depth:0 match:1 excluded:0 filename:/XXX/mail/msg-007.gz
|
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
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
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 <<EOF > EXPECTED
|
||||||
|
From test_suite@notmuchmail.org Fri Jan 5 15:43:50 2001
|
||||||
|
From: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
To: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
Message-Id: <msg-007@notmuch-test-suite>
|
||||||
|
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 <<EOF > EXPECTED
|
||||||
|
From: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
To: Notmuch Test Suite <test_suite@notmuchmail.org>
|
||||||
|
Message-Id: <msg-007@notmuch-test-suite>
|
||||||
|
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
|
test_done
|
||||||
|
|
Loading…
Reference in a new issue