diff options
-rw-r--r-- | Makefile.local | 5 | ||||
-rw-r--r-- | gmime-filter-reply.c | 208 | ||||
-rw-r--r-- | gmime-filter-reply.h | 66 | ||||
-rw-r--r-- | notmuch-client.h | 21 | ||||
-rw-r--r-- | notmuch-reply.c | 141 | ||||
-rw-r--r-- | notmuch-show.c | 101 | ||||
-rw-r--r-- | notmuch.1 | 19 | ||||
-rw-r--r-- | notmuch.c | 17 | ||||
-rw-r--r-- | show-message.c | 117 |
9 files changed, 592 insertions, 103 deletions
diff --git a/Makefile.local b/Makefile.local index ef437757..7c90d833 100644 --- a/Makefile.local +++ b/Makefile.local @@ -4,6 +4,7 @@ notmuch_client_srcs = \ notmuch.c \ notmuch-dump.c \ notmuch-new.c \ + notmuch-reply.c \ notmuch-restore.c \ notmuch-search.c \ notmuch-setup.c \ @@ -11,7 +12,9 @@ notmuch_client_srcs = \ notmuch-tag.c \ notmuch-time.c \ add-files.c \ - query-string.c + gmime-filter-reply.c \ + query-string.c \ + show-message.c notmuch_client_modules = $(notmuch_client_srcs:.c=.o) notmuch: $(notmuch_client_modules) lib/notmuch.a diff --git a/gmime-filter-reply.c b/gmime-filter-reply.c new file mode 100644 index 00000000..3e298e1b --- /dev/null +++ b/gmime-filter-reply.c @@ -0,0 +1,208 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "gmime-filter-reply.h" + +/** + * SECTION: gmime-filter-reply + * @title: GMimeFilterReply + * @short_description: Add/remove reply markers + * + * A #GMimeFilter for adding or removing reply markers + **/ + + +static void g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass); +static void g_mime_filter_reply_init (GMimeFilterReply *filter, GMimeFilterReplyClass *klass); +static void g_mime_filter_reply_finalize (GObject *object); + +static GMimeFilter *filter_copy (GMimeFilter *filter); +static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace); +static void filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace, + char **out, size_t *outlen, size_t *outprespace); +static void filter_reset (GMimeFilter *filter); + + +static GMimeFilterClass *parent_class = NULL; + +GType +g_mime_filter_reply_get_type (void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof (GMimeFilterReplyClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) g_mime_filter_reply_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GMimeFilterReply), + 0, /* n_preallocs */ + (GInstanceInitFunc) g_mime_filter_reply_init, + NULL /* value_table */ + }; + + type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterReply", &info, (GTypeFlags) 0); + } + + return type; +} + + +static void +g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass); + + parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER); + + object_class->finalize = g_mime_filter_reply_finalize; + + filter_class->copy = filter_copy; + filter_class->filter = filter_filter; + filter_class->complete = filter_complete; + filter_class->reset = filter_reset; +} + +static void +g_mime_filter_reply_init (GMimeFilterReply *filter, GMimeFilterReplyClass *klass) +{ + (void) klass; + filter->saw_nl = TRUE; + filter->saw_angle = FALSE; +} + +static void +g_mime_filter_reply_finalize (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static GMimeFilter * +filter_copy (GMimeFilter *filter) +{ + GMimeFilterReply *reply = (GMimeFilterReply *) filter; + + return g_mime_filter_reply_new (reply->encode); +} + +static void +filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace, + char **outbuf, size_t *outlen, size_t *outprespace) +{ + GMimeFilterReply *reply = (GMimeFilterReply *) filter; + register const char *inptr = inbuf; + const char *inend = inbuf + inlen; + char *outptr; + + (void) prespace; + if (reply->encode) { + g_mime_filter_set_size (filter, 3 * inlen, FALSE); + + outptr = filter->outbuf; + while (inptr < inend) { + if (reply->saw_nl) { + *outptr++ = '>'; + *outptr++ = ' '; + reply->saw_nl = FALSE; + } + if (*inptr == '\n') + reply->saw_nl = TRUE; + else + reply->saw_nl = FALSE; + + *outptr++ = *inptr++; + } + } else { + g_mime_filter_set_size (filter, inlen + 1, FALSE); + + outptr = filter->outbuf; + while (inptr < inend) { + if (reply->saw_nl) { + if (*inptr == '>') + reply->saw_angle = TRUE; + else + *outptr++ = *inptr; + reply->saw_nl = FALSE; + } else if (reply->saw_angle) { + if (*inptr == ' ') + ; + else + *outptr++ = *inptr; + reply->saw_angle = FALSE; + } else { + if (*inptr == '\n') + reply->saw_nl = TRUE; + *outptr++ = *inptr; + } + + inptr++; + } + } + + *outlen = outptr - filter->outbuf; + *outprespace = filter->outpre; + *outbuf = filter->outbuf; +} + +static void +filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace, + char **outbuf, size_t *outlen, size_t *outprespace) +{ + if (inbuf && inlen) + filter_filter (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace); +} + +static void +filter_reset (GMimeFilter *filter) +{ + GMimeFilterReply *reply = (GMimeFilterReply *) filter; + + reply->saw_nl = TRUE; + reply->saw_angle = FALSE; +} + + +/** + * g_mime_filter_reply_new: + * @encode: %TRUE if the filter should encode or %FALSE otherwise + * @dots: encode/decode dots (as for SMTP) + * + * Creates a new #GMimeFilterReply filter. + * + * If @encode is %TRUE, then all lines will be prefixed by "> ", + * otherwise any lines starting with "> " will have that removed + * + * Returns: a new #GMimeFilterReply filter. + **/ +GMimeFilter * +g_mime_filter_reply_new (gboolean encode) +{ + GMimeFilterReply *new_reply; + + new_reply = (GMimeFilterReply *) g_object_newv (GMIME_TYPE_FILTER_REPLY, 0, NULL); + new_reply->encode = encode; + + return (GMimeFilter *) new_reply; +} + diff --git a/gmime-filter-reply.h b/gmime-filter-reply.h new file mode 100644 index 00000000..41cbc134 --- /dev/null +++ b/gmime-filter-reply.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _GMIME_FILTER_REPLY_H_ +#define _GMIME_FILTER_REPLY_H_ + +#include <gmime/gmime-filter.h> + +G_BEGIN_DECLS + +#define GMIME_TYPE_FILTER_REPLY (g_mime_filter_reply_get_type ()) +#define GMIME_FILTER_REPLY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMIME_TYPE_FILTER_REPLY, GMimeFilterReply)) +#define GMIME_FILTER_REPLY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMIME_TYPE_FILTER_REPLY, GMimeFilterReplyClass)) +#define GMIME_IS_FILTER_REPLY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GMIME_TYPE_FILTER_REPLY)) +#define GMIME_IS_FILTER_REPLY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GMIME_TYPE_FILTER_REPLY)) +#define GMIME_FILTER_REPLY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMIME_TYPE_FILTER_REPLY, GMimeFilterReplyClass)) + +typedef struct _GMimeFilterReply GMimeFilterReply; +typedef struct _GMimeFilterReplyClass GMimeFilterReplyClass; + +/** + * GMimeFilterReply: + * @parent_object: parent #GMimeFilter + * @encode: encoding vs decoding reply markers + * @saw_nl: previous char was a \n + * @saw_angle: previous char was a > + * + * A filter to insert/remove reply markers (lines begining with >) + **/ +struct _GMimeFilterReply { + GMimeFilter parent_object; + + gboolean encode; + gboolean saw_nl; + gboolean saw_angle; +}; + +struct _GMimeFilterReplyClass { + GMimeFilterClass parent_class; + +}; + + +GType g_mime_filter_reply_get_type (void); + +GMimeFilter *g_mime_filter_reply_new (gboolean encode); + +G_END_DECLS + + +#endif /* _GMIME_FILTER_REPLY_H_ */ diff --git a/notmuch-client.h b/notmuch-client.h index 50f31fa1..f39900a9 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -103,6 +103,9 @@ int notmuch_new_command (void *ctx, int argc, char *argv[]); int +notmuch_reply_command (void *ctx, int argc, char *argv[]); + +int notmuch_restore_command (void *ctx, int argc, char *argv[]); int @@ -117,13 +120,6 @@ notmuch_show_command (void *ctx, int argc, char *argv[]); int notmuch_tag_command (void *ctx, int argc, char *argv[]); -notmuch_status_t -add_files (notmuch_database_t *notmuch, const char *path, - add_files_state_t *state); - -char * -query_string_from_args (void *ctx, int argc, char *argv[]); - const char * notmuch_time_relative_date (void *ctx, time_t then); @@ -133,4 +129,15 @@ notmuch_time_print_formatted_seconds (double seconds); double notmuch_time_elapsed (struct timeval start, struct timeval end); +notmuch_status_t +add_files (notmuch_database_t *notmuch, const char *path, + add_files_state_t *state); + +char * +query_string_from_args (void *ctx, int argc, char *argv[]); + +notmuch_status_t +show_message_body (const char *filename, + void (*show_part) (GMimeObject *part, int *part_count)); + #endif diff --git a/notmuch-reply.c b/notmuch-reply.c new file mode 100644 index 00000000..0c3ea13f --- /dev/null +++ b/notmuch-reply.c @@ -0,0 +1,141 @@ +/* notmuch - Not much of an email program, (just index and search) + * + * Copyright © 2009 Carl Worth + * Copyright © 2009 Keith Packard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Authors: Carl Worth <cworth@cworth.org> + * Keith Packard <keithp@keithp.com> + */ + +#include "notmuch-client.h" +#include "gmime-filter-reply.h" + +static void +reply_part(GMimeObject *part, int *part_count) +{ + GMimeContentDisposition *disposition; + GMimeContentType *content_type; + GMimeDataWrapper *wrapper; + + (void) part_count; + disposition = g_mime_object_get_content_disposition (part); + if (disposition && + strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) + { + const char *filename = g_mime_part_get_filename (GMIME_PART (part)); + content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); + + printf ("Attachment: %s (%s)\n", filename, + g_mime_content_type_to_string (content_type)); + return; + } + + content_type = g_mime_object_get_content_type (GMIME_OBJECT (part)); + + if (g_mime_content_type_is_type (content_type, "text", "*") && + !g_mime_content_type_is_type (content_type, "text", "html")) + { + GMimeStream *stream_stdout = NULL, *stream_filter = NULL; + stream_stdout = g_mime_stream_file_new (stdout); + if (stream_stdout) { + g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE); + stream_filter = g_mime_stream_filter_new(stream_stdout); + } + g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter), + g_mime_filter_reply_new(TRUE)); + wrapper = g_mime_part_get_content_object (GMIME_PART (part)); + if (wrapper && stream_filter) + g_mime_data_wrapper_write_to_stream (wrapper, stream_filter); + if (stream_filter) + g_object_unref(stream_filter); + if (stream_stdout) + g_object_unref(stream_stdout); + } + else + { + printf ("Non-text part: %s\n", + g_mime_content_type_to_string (content_type)); + } +} + +int +notmuch_reply_command (void *ctx, int argc, char *argv[]) +{ + void *local = talloc_new (ctx); + char *query_string; + notmuch_database_t *notmuch = NULL; + notmuch_query_t *query = NULL; + notmuch_messages_t *messages; + notmuch_message_t *message; + int ret = 0; + + const char *headers[] = { + "Subject", "From", "To", "Cc", "Bcc", "Date", + "In-Reply-To", "References" + }; + const char *name, *value; + unsigned int i; + + notmuch = notmuch_database_open (NULL); + if (notmuch == NULL) { + ret = 1; + goto DONE; + } + + query_string = query_string_from_args (local, argc, argv); + if (query_string == NULL) { + fprintf (stderr, "Out of memory\n"); + ret = 1; + goto DONE; + } + + query = notmuch_query_create (notmuch, query_string); + if (query == NULL) { + fprintf (stderr, "Out of memory\n"); + ret = 1; + goto DONE; + } + + for (messages = notmuch_query_search_messages (query); + notmuch_messages_has_more (messages); + notmuch_messages_advance (messages)) + { + message = notmuch_messages_get (messages); + + for (i = 0; i < ARRAY_SIZE (headers); i++) { + name = headers[i]; + value = notmuch_message_get_header (message, name); + if (value) + printf ("%s: %s\n", name, value); + } + + show_message_body (notmuch_message_get_filename (message), reply_part); + + notmuch_message_destroy (message); + } + + DONE: + if (local) + talloc_free (local); + + if (query) + notmuch_query_destroy (query); + + if (notmuch) + notmuch_database_close (notmuch); + + return ret; +} diff --git a/notmuch-show.c b/notmuch-show.c index 7647e9e4..b5db3df9 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -67,49 +67,11 @@ _get_one_line_summary (void *ctx, notmuch_message_t *message) } static void -show_message_part (GMimeObject *part, int *part_count) +show_part(GMimeObject *part, int *part_count) { - GMimeStream *stream; - GMimeDataWrapper *wrapper; GMimeContentDisposition *disposition; GMimeContentType *content_type; - - *part_count = *part_count + 1; - - if (GMIME_IS_MULTIPART (part)) { - GMimeMultipart *multipart = GMIME_MULTIPART (part); - int i; - - for (i = 0; i < g_mime_multipart_get_count (multipart); i++) { - if (GMIME_IS_MULTIPART_SIGNED (multipart)) { - /* Don't index the signature. */ - if (i == 1) - continue; - if (i > 1) - fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Continuing.\n"); - } - show_message_part (g_mime_multipart_get_part (multipart, i), - part_count); - } - return; - } - - if (GMIME_IS_MESSAGE_PART (part)) { - GMimeMessage *mime_message; - - mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part)); - - show_message_part (g_mime_message_get_mime_part (mime_message), - part_count); - - return; - } - - if (! (GMIME_IS_PART (part))) { - fprintf (stderr, "Warning: Not displaying unknown mime part: %s.\n", - g_type_name (G_OBJECT_TYPE (part))); - return; - } + GMimeDataWrapper *wrapper; disposition = g_mime_object_get_content_disposition (part); if (disposition && @@ -137,14 +99,14 @@ show_message_part (GMimeObject *part, int *part_count) if (g_mime_content_type_is_type (content_type, "text", "*") && !g_mime_content_type_is_type (content_type, "text", "html")) { - stream = g_mime_stream_file_new (stdout); + GMimeStream *stream = g_mime_stream_file_new (stdout); g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE); wrapper = g_mime_part_get_content_object (GMIME_PART (part)); - if (wrapper) + if (wrapper && stream) g_mime_data_wrapper_write_to_stream (wrapper, stream); - - g_object_unref (stream); + if (stream) + g_object_unref(stream); } else { @@ -155,55 +117,6 @@ show_message_part (GMimeObject *part, int *part_count) printf ("\fpart}\n"); } -static notmuch_status_t -show_message_body (const char *filename) -{ - GMimeStream *stream = NULL; - GMimeParser *parser = NULL; - GMimeMessage *mime_message = NULL; - notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; - static int initialized = 0; - FILE *file = NULL; - int part_count = 0; - - if (! initialized) { - g_mime_init (0); - initialized = 1; - } - - file = fopen (filename, "r"); - if (! file) { - fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno)); - ret = NOTMUCH_STATUS_FILE_ERROR; - goto DONE; - } - - stream = g_mime_stream_file_new (file); - g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE); - - parser = g_mime_parser_new_with_stream (stream); - - mime_message = g_mime_parser_construct_message (parser); - - show_message_part (g_mime_message_get_mime_part (mime_message), - &part_count); - - DONE: - if (mime_message) - g_object_unref (mime_message); - - if (parser) - g_object_unref (parser); - - if (stream) - g_object_unref (stream); - - if (file) - fclose (file); - - return ret; -} - int notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) { @@ -267,7 +180,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[])) printf ("\fheader}\n"); printf ("\fbody{\n"); - show_message_body (notmuch_message_get_filename (message)); + show_message_body (notmuch_message_get_filename (message), show_part); printf ("\fbody}\n"); @@ -167,6 +167,25 @@ operators, but will have to be protected from interpretation by the shell, (such as by putting quotation marks around any parenthesized expression). .TP +.BR reply " <search-term>..." + +Constructs a reply template for a set of messages. + +See the documentation of +.B search +for deatils of the supported syntax of search terms. + +To make replying to email easier, +.B notmuch reply +takes an existing set of messages and constructs a suitable mail +template, taking From: and To: messages and using those for the new +To: address; copying Cc: addresses, building a suitable new subject +including Re: at the front, adding the old message IDs to the +References list and setting the In-Reply-To: field correctly. + +The resulting message template is output to stdout. + +.TP .BR show " <search-term>..." Shows all messages matching the search terms. @@ -1,6 +1,7 @@ /* notmuch - Not much of an email program, (just index and search) * * Copyright © 2009 Carl Worth + * Copyright © 2009 Keith Packard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,7 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ . * - * Author: Carl Worth <cworth@cworth.org> + * Authors: Carl Worth <cworth@cworth.org> + * Keith Packard <keithp@keithp.com> */ #include "notmuch-client.h" @@ -82,6 +84,19 @@ command_t commands[] = { "\t\tthe Boolean operators, but will have to be protected from\n" "\t\tinterpretation by the shell, (such as by putting quotation\n" "\t\tmarks around any parenthesized expression)." }, + { "reply", notmuch_reply_command, + "<search-terms> [...]\n\n" + "\t\tFormats a reply from a set of existing messages.", + "\t\tConstructs a new message as a reply to a set of existing\n" + "\t\tmessages. The From: address is used as a To: address\n" + "\t\talong with all old To: addresses. All of the Cc: addresses\n" + "\t\tare copied as new Cc: addresses. An In-Reply-To: header\n" + "\t\twill be constructed from the name and date of the original\n" + "\t\tmessage, and the original Message-ID will be added to the\n" + "\t\tlist of References in the new message. The text of each\n" + "\t\tmessage (as described in the \"show\" command) will be\n" + "\t\tpresented, each line prefixed with \"> \" The resulting\n" + "\t\tmessage will be dumped to stdout." }, { "show", notmuch_show_command, "<search-terms> [...]\n\n" "\t\tShows all messages matching the search terms.", diff --git a/show-message.c b/show-message.c new file mode 100644 index 00000000..2d3189e3 --- /dev/null +++ b/show-message.c @@ -0,0 +1,117 @@ +/* notmuch - Not much of an email program, (just index and search) + * + * Copyright © 2009 Carl Worth + * Copyright © 2009 Keith Packard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Authors: Carl Worth <cworth@cworth.org> + * Keith Packard <keithp@keithp.com> + */ + +#include "notmuch-client.h" + +static void +show_message_part (GMimeObject *part, int *part_count, + void (*show_part) (GMimeObject *part, int *part_count)) +{ + *part_count = *part_count + 1; + + if (GMIME_IS_MULTIPART (part)) { + GMimeMultipart *multipart = GMIME_MULTIPART (part); + int i; + + for (i = 0; i < g_mime_multipart_get_count (multipart); i++) { + if (GMIME_IS_MULTIPART_SIGNED (multipart)) { + /* Don't index the signature. */ + if (i == 1) + continue; + if (i > 1) + fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Continuing.\n"); + } + show_message_part (g_mime_multipart_get_part (multipart, i), + part_count, show_part); + } + return; + } + + if (GMIME_IS_MESSAGE_PART (part)) { + GMimeMessage *mime_message; + + mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part)); + + show_message_part (g_mime_message_get_mime_part (mime_message), + part_count, show_part); + + return; + } + + if (! (GMIME_IS_PART (part))) { + fprintf (stderr, "Warning: Not displaying unknown mime part: %s.\n", + g_type_name (G_OBJECT_TYPE (part))); + return; + } + + (*show_part) (part, part_count); +} + +notmuch_status_t +show_message_body (const char *filename, + void (*show_part) (GMimeObject *part, int *part_count)) +{ + GMimeStream *stream = NULL; + GMimeParser *parser = NULL; + GMimeMessage *mime_message = NULL; + notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; + static int initialized = 0; + FILE *file = NULL; + int part_count = 0; + + if (! initialized) { + g_mime_init (0); + initialized = 1; + } + + file = fopen (filename, "r"); + if (! file) { + fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno)); + ret = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + stream = g_mime_stream_file_new (file); + g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE); + + parser = g_mime_parser_new_with_stream (stream); + + mime_message = g_mime_parser_construct_message (parser); + + show_message_part (g_mime_message_get_mime_part (mime_message), + &part_count, show_part); + + DONE: + if (mime_message) + g_object_unref (mime_message); + + if (parser) + g_object_unref (parser); + + if (stream) + g_object_unref (stream); + + if (file) + fclose (file); + + return ret; +} |