*
* Examples include:
*
- * 5 minutes ago (For times less than 60 minutes ago)
- * 12:30 (For times >60 minutes but still today)
- * Yesterday
- * Monday (Before yesterday but fewer than 7 days ago)
- * Oct. 12 (Between 7 and 180 days ago (about 6 months))
+ * 5 mins. ago (For times less than 60 minutes ago)
+ * Today 12:30 (For times >60 minutes but still today)
+ * Yest. 12:30
+ * Mon. 12:30 (Before yesterday but fewer than 7 days ago)
+ * October 12 (Between 7 and 180 days ago (about 6 months))
* 2008-06-30 (More than 180 days ago)
*/
#define MINUTE (60)
if (delta < 3600) {
snprintf (result, RELATIVE_DATE_MAX,
- "%d minutes ago", (int) (delta / 60));
+ "%d mins. ago", (int) (delta / 60));
return result;
}
delta < DAY)
{
strftime (result, RELATIVE_DATE_MAX,
- "%R", &tm_then); /* 12:30 */
+ "Today %R", &tm_then); /* Today 12:30 */
return result;
} else if ((tm_now.tm_wday + 7 - tm_then.tm_wday) % 7 == 1) {
- return "Yesterday";
+ strftime (result, RELATIVE_DATE_MAX,
+ "Yest. %R", &tm_then); /* Yest. 12:30 */
+ return result;
} else {
if (tm_then.tm_wday != tm_now.tm_wday) {
strftime (result, RELATIVE_DATE_MAX,
- "%A", &tm_then); /* Monday */
+ "%a. %R", &tm_then); /* Mon. 12:30 */
return result;
}
}
}
strftime (result, RELATIVE_DATE_MAX,
- "%b %d", &tm_then); /* Oct. 12 */
+ "%B %d", &tm_then); /* October 12 */
return result;
}
#undef MINUTE
date = notmuch_thread_get_oldest_date (thread);
relative_date = _format_relative_date (local, date);
- printf ("%s (%s) %s",
+ printf ("thread:%s %12s %s",
notmuch_thread_get_thread_id (thread),
relative_date,
notmuch_thread_get_subject (thread));
return ret;
}
+static const char *
+_get_tags_as_string (void *ctx, notmuch_message_t *message)
+{
+ notmuch_tags_t *tags;
+ int first = 1;
+ const char *tag;
+ char *result;
+
+ result = talloc_strdup (ctx, "");
+ if (result == NULL)
+ return NULL;
+
+ for (tags = notmuch_message_get_tags (message);
+ notmuch_tags_has_more (tags);
+ notmuch_tags_advance (tags))
+ {
+ tag = notmuch_tags_get (tags);
+
+ result = talloc_asprintf_append (result, "%s%s",
+ first ? "" : " ", tag);
+ first = 0;
+ }
+
+ return result;
+}
+
/* Get a nice, single-line summary of message. */
static const char *
_get_one_line_summary (void *ctx, notmuch_message_t *message)
time_t date;
const char *relative_date;
const char *subject;
+ const char *tags;
from = notmuch_message_get_header (message, "from");
subject = notmuch_message_get_header (message, "subject");
- return talloc_asprintf (ctx, "%s (%s) %s",
- from, relative_date, subject);
+ tags = _get_tags_as_string (ctx, message);
+
+ return talloc_asprintf (ctx, "%s (%s) %s (%s)",
+ from, relative_date, subject, tags);
}
static void
-show_message_part (GMimeObject *part)
+show_message_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);
if (i > 1)
fprintf (stderr, "Warning: Unexpected extra parts of mutlipart/signed. Continuing.\n");
}
- show_message_part (g_mime_multipart_get_part (multipart, i));
+ show_message_part (g_mime_multipart_get_part (multipart, i),
+ part_count);
}
return;
}
mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part));
- show_message_part (g_mime_message_get_mime_part (mime_message));
+ show_message_part (g_mime_message_get_mime_part (mime_message),
+ part_count);
return;
}
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 ("\fattachment{ ID: %d, Content-type: %s\n",
+ *part_count,
+ g_mime_content_type_to_string (content_type));
+ printf ("Attachment: %s (%s)\n", filename,
+ g_mime_content_type_to_string (content_type));
+ printf ("\fattachment}\n");
- /* XXX: Need to print content type here as well. */
- printf ("%%attachment{ %s %%attachment}\n", filename);
return;
}
- /* Stream the MIME part out to stdout. */
- stream = g_mime_stream_file_new (stdout);
- g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
+ content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
- wrapper = g_mime_part_get_content_object (GMIME_PART (part));
- if (wrapper)
- g_mime_data_wrapper_write_to_stream (wrapper, stream);
+ printf ("\fpart{ ID: %d, Content-type: %s\n",
+ *part_count,
+ g_mime_content_type_to_string (content_type));
- g_object_unref (stream);
+ 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);
+ g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
+
+ wrapper = g_mime_part_get_content_object (GMIME_PART (part));
+ if (wrapper)
+ g_mime_data_wrapper_write_to_stream (wrapper, stream);
+
+ g_object_unref (stream);
+ }
+ else
+ {
+ printf ("Non-text part: %s\n",
+ g_mime_content_type_to_string (content_type));
+ }
+
+ printf ("\fpart}\n");
}
static notmuch_status_t
notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
static int initialized = 0;
FILE *file = NULL;
+ int part_count = 0;
if (! initialized) {
g_mime_init (0);
mime_message = g_mime_parser_construct_message (parser);
- show_message_part (g_mime_message_get_mime_part (mime_message));
+ show_message_part (g_mime_message_get_mime_part (mime_message),
+ &part_count);
DONE:
if (mime_message)
const char *name, *value;
unsigned int i;
- if (argc != 1) {
- fprintf (stderr, "Error: \"notmuch show\" requires exactly one thread-ID argument.\n");
- ret = 1;
- goto DONE;
- }
-
notmuch = notmuch_database_open (NULL);
if (notmuch == NULL) {
ret = 1;
goto DONE;
}
- query_string = talloc_asprintf (local, "thread:%s", argv[0]);
+ query_string = query_string_from_args (local, argc, argv);
if (query_string == NULL) {
fprintf (stderr, "Out of memory\n");
ret = 1;
{
message = notmuch_messages_get (messages);
- printf ("%%message{\n");
+ printf ("\fmessage{ id:%s filename:%s\n",
+ notmuch_message_get_message_id (message),
+ notmuch_message_get_filename (message));
- printf ("%%header{\n");
+ printf ("\fheader{\n");
printf ("%s\n", _get_one_line_summary (local, message));
printf ("%s: %s\n", name, value);
}
- printf ("%%header}\n");
+ printf ("\fheader}\n");
+ printf ("\fbody{\n");
show_message_body (notmuch_message_get_filename (message));
- printf ("%%message}\n");
+ printf ("\fbody}\n");
+
+ printf ("\fmessage}\n");
notmuch_message_destroy (message);
}
"\t\tinterpretation by the shell, (such as by putting quotation\n"
"\t\tmarks around any parenthesized expression)." },
{ "show", show_command,
- "<thread-id>\n\n"
- "\t\tShow the thread with the given thread ID (see 'search').",
- "\t\tThread ID values are given as the first column in the\n"
- "\t\toutput of the \"notmuch search\" command. These are the\n"
- "\t\trandom-looking strings of 32 characters." },
+ "<search-terms> [...]\n\n"
+ "\t\tShows all messages matching the search terms.",
+ "\t\tSee the documentation of \"notmuch search\" for details\n"
+ "\t\tof the supported syntax of search terms.\n\n"
+ "\t\tA common use of \"notmuch show\" is to display a single\n"
+ "\t\tthread of email messages. For this, use a search term of\n"
+ "\t\t\"thread:<thread-id>\" as can be seen in the first column\n"
+ "\t\tof output from the \"notmuch search\" command.\n\n"
+ "\t\tAll messages will be displayed in date order. The output\n"
+ "\t\tformat is plain-text, with all text-content MIME parts\n"
+ "\t\tdecoded. Various components in the output, ('message',\n"
+ "\t\t'header', 'body', 'attachment', and MIME 'part') will be\n"
+ "\t\tdelimited by easily-parsed markers. Each marker consists\n"
+ "\t\tof a Control-L character (ASCII decimal 12), the name of\n"
+ "\t\tthe marker, and then either an opening or closing brace,\n"
+ "\t\t'{' or '}' to either open or close the component."},
{ "tag", tag_command,
"+<tag>|-<tag> [...] [--] <search-term> [...]\n\n"
"\t\tAdd/remove tags for all messages matching the search terms.",