From d39d0e55f09d8cc2ba9683ec5622068bb7373f2a Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Fri, 22 Oct 2010 11:28:03 +0200 Subject: [PATCH] Add 'cat' subcommand This command outputs a raw message matched by search term to the standard output. It allows MUAs to access the messages for piping, attachment manipulation, etc. by running notmuch cat rather then directly access the file. This will simplify the MUAs when they need to operate on a remote database. Edited-by: Carl Worth : Remove trailing whitespace, add missing "test_done" to new test script to avoid "Unexpected exit" error. --- notmuch-client.h | 3 ++ notmuch-show.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++ notmuch.1 | 4 +++ notmuch.c | 4 +++ test/cat | 40 +++++++++++++++++++++++ test/notmuch-test | 2 +- 6 files changed, 135 insertions(+), 1 deletion(-) create mode 100755 test/cat diff --git a/notmuch-client.h b/notmuch-client.h index d530578a..fdfb94ad 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -110,6 +110,9 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]); int notmuch_search_tags_command (void *ctx, int argc, char *argv[]); +int +notmuch_cat_command (void *ctx, int argc, char *argv[]); + int notmuch_part_command (void *ctx, int argc, char *argv[]); diff --git a/notmuch-show.c b/notmuch-show.c index ea465dec..f46e0c82 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -631,6 +631,89 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) return 0; } +int +notmuch_cat_command (void *ctx, unused (int argc), unused (char *argv[])) +{ + notmuch_config_t *config; + notmuch_database_t *notmuch; + notmuch_query_t *query; + notmuch_messages_t *messages; + notmuch_message_t *message; + char *query_string; + int i; + const char *filename; + FILE *file; + size_t size; + char buf[4096]; + + for (i = 0; i < argc && argv[i][0] == '-'; i++) { + fprintf (stderr, "Unrecognized option: %s\n", argv[i]); + return 1; + } + + config = notmuch_config_open (ctx, NULL, NULL); + if (config == NULL) + return 1; + + query_string = query_string_from_args (ctx, argc, argv); + if (query_string == NULL) { + fprintf (stderr, "Out of memory\n"); + return 1; + } + + if (*query_string == '\0') { + fprintf (stderr, "Error: notmuch cat requires at least one search term.\n"); + return 1; + } + + notmuch = notmuch_database_open (notmuch_config_get_database_path (config), + NOTMUCH_DATABASE_MODE_READ_ONLY); + if (notmuch == NULL) + return 1; + + query = notmuch_query_create (notmuch, query_string); + if (query == NULL) { + fprintf (stderr, "Error: Out of memory\n"); + return 1; + } + + if (notmuch_query_count_messages (query) != 1) { + fprintf (stderr, "Error: search term did not match precisely one message.\n"); + return 1; + } + + messages = notmuch_query_search_messages (query); + message = notmuch_messages_get (messages); + + if (message == NULL) { + fprintf (stderr, "Error: Cannot find matching message.\n"); + return 1; + } + + filename = notmuch_message_get_filename (message); + if (filename == NULL) { + fprintf (stderr, "Error: Cannot message filename.\n"); + return 1; + } + + file = fopen (filename, "r"); + if (file == NULL) { + fprintf (stderr, "Error: Cannot open file %s: %s\n", filename, strerror (errno)); + return 1; + } + + while (!feof (file)) { + size = fread (buf, 1, sizeof (buf), file); + fwrite (buf, size, 1, stdout); + } + + fclose (file); + notmuch_query_destroy (query); + notmuch_database_close (notmuch); + + return 0; +} + int notmuch_part_command (void *ctx, unused (int argc), unused (char *argv[])) { diff --git a/notmuch.1 b/notmuch.1 index e4eed60f..853b5eaf 100644 --- a/notmuch.1 +++ b/notmuch.1 @@ -300,6 +300,10 @@ See the section below for details of the supported syntax for . .RE .TP +.BR cat " ..." + +Output raw content of a single message matched by the search term. +.TP .BR count " ..." Count messages matching the search terms. diff --git a/notmuch.c b/notmuch.c index 030e4942..0eba89a3 100644 --- a/notmuch.c +++ b/notmuch.c @@ -343,6 +343,10 @@ command_t commands[] = { "\tcontain tags only from messages that match the search-term(s).\n" "\n" "\tIn both cases the list will be alphabetically sorted." }, + { "cat", notmuch_cat_command, + "", + "Output raw content of a single message matched by the search term.", + "" }, { "part", notmuch_part_command, "--part= ", "Output a single MIME part of a message.", diff --git a/test/cat b/test/cat new file mode 100755 index 00000000..c2cfedb8 --- /dev/null +++ b/test/cat @@ -0,0 +1,40 @@ +#!/bin/bash + +test_description='notmuch cat' +. ./test-lib.sh + +test_begin_subtest "Generate some messages" +generate_message +generate_message +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "Added 2 new messages to the database." + +test_begin_subtest "Without arguments" +output=$(notmuch cat 2>&1) +test_expect_equal "$output" "Error: notmuch cat requires at least one search term." + +test_begin_subtest "Attempt to cat multiple messages" +output=$(notmuch cat "*" 2>&1) +test_expect_equal "$output" "Error: search term did not match precisely one message." + +test_begin_subtest "Cat a message" +output=$(notmuch cat id:msg-001@notmuch-test-suite) +test_expect_equal "$output" "From: Notmuch Test Suite +To: Notmuch Test Suite +Message-Id: +Subject: Test message #1 +Date: Tue, 05 Jan 2001 15:43:57 -0000 + +This is just a test message (#1)" + +test_begin_subtest "Cat another message" +output=$(notmuch cat id:msg-002@notmuch-test-suite) +test_expect_equal "$output" "From: Notmuch Test Suite +To: Notmuch Test Suite +Message-Id: +Subject: Test message #2 +Date: Tue, 05 Jan 2001 15:43:57 -0000 + +This is just a test message (#2)" + +test_done diff --git a/test/notmuch-test b/test/notmuch-test index 60c3ecbc..6b894090 100755 --- a/test/notmuch-test +++ b/test/notmuch-test @@ -16,7 +16,7 @@ fi cd $(dirname "$0") -TESTS="basic new search json thread-naming reply dump-restore uuencode thread-order author-order from-guessing long-id encoding emacs" +TESTS="basic new search json thread-naming reply cat dump-restore uuencode thread-order author-order from-guessing long-id encoding emacs" # Clean up any results from a previous run rm -r test-results >/dev/null 2>/dev/null