]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch.c
Update notmuch man page with recently-added documentation.
[notmuch] / notmuch.c
index 0d08a54687ca97466aec96a01bcea1bf50842b27..b20b4065005630dfc3c5bc2d374516a819f77c33 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -739,11 +739,11 @@ query_string_from_args (void *ctx, int argc, char *argv[])
  *
  * 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)
@@ -778,7 +778,7 @@ _format_relative_date (void *ctx, time_t then)
 
     if (delta < 3600) {
        snprintf (result, RELATIVE_DATE_MAX,
-                 "%d minutes ago", (int) (delta / 60));
+                 "%d mins. ago", (int) (delta / 60));
        return result;
     }
 
@@ -787,21 +787,23 @@ _format_relative_date (void *ctx, time_t then)
            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
@@ -848,7 +850,7 @@ search_command (void *ctx, int argc, char *argv[])
        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));
@@ -878,6 +880,32 @@ search_command (void *ctx, int argc, char *argv[])
     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)
@@ -886,6 +914,7 @@ _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");
 
@@ -894,18 +923,22 @@ _get_one_line_summary (void *ctx, notmuch_message_t *message)
 
     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);
        int i;
@@ -918,7 +951,8 @@ show_message_part (GMimeObject *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;
     }
@@ -928,7 +962,8 @@ show_message_part (GMimeObject *part)
 
        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;
     }
@@ -946,30 +981,41 @@ show_message_part (GMimeObject *part)
        const char *filename = g_mime_part_get_filename (GMIME_PART (part));
        content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
 
-       printf ("%%attachment{ Content-type: %s\n",
+       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 ("%s\n", filename);
-       printf ("%%attachment}\n");
+       printf ("\fattachment}\n");
 
        return;
     }
 
-    /* Stream the MIME part out to stdout. */
     content_type = g_mime_object_get_content_type (GMIME_OBJECT (part));
 
-    printf ("%%part{ Content-type: %s\n",
+    printf ("\fpart{ ID: %d, Content-type: %s\n",
+           *part_count,
            g_mime_content_type_to_string (content_type));
 
-    stream = g_mime_stream_file_new (stdout);
-    g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
+    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);
+       wrapper = g_mime_part_get_content_object (GMIME_PART (part));
+       if (wrapper)
+           g_mime_data_wrapper_write_to_stream (wrapper, stream);
 
-    printf ("%%part}\n");
+       g_object_unref (stream);
+    }
+    else
+    {
+       printf ("Non-text part: %s\n",
+               g_mime_content_type_to_string (content_type));
+    }
 
-    g_object_unref (stream);
+    printf ("\fpart}\n");
 }
 
 static notmuch_status_t
@@ -981,6 +1027,7 @@ show_message_body (const char *filename)
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
     static int initialized = 0;
     FILE *file = NULL;
+    int part_count = 0;
 
     if (! initialized) {
        g_mime_init (0);
@@ -1001,7 +1048,8 @@ show_message_body (const char *filename)
 
     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)
@@ -1036,19 +1084,13 @@ show_command (void *ctx, unused (int argc), unused (char *argv[]))
     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;
@@ -1068,9 +1110,11 @@ show_command (void *ctx, unused (int argc), unused (char *argv[]))
     {
        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));
 
@@ -1081,11 +1125,14 @@ show_command (void *ctx, unused (int argc), unused (char *argv[]))
                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);
     }
@@ -1420,11 +1467,24 @@ command_t commands[] = {
       "\t\tNote that the individual mail messages will be matched\n"
       "\t\tagainst the search terms, but the results will be the\n"
       "\t\tthreads containing the matched messages.\n\n"
-      "\t\tCurrently, the supported search terms are as follows, (where\n"
-      "\t\t<brackets> indicate user-supplied values):\n\n"
+      "\t\tCurrently, in addition to free text (and quoted phrases)\n"
+      "\t\twhich match terms appearing anywhere within an email,\n"
+      "\t\tthe following prefixes can be used to search specific\n"
+      "\t\tportions of an email, (where <brackets> indicate user-\n"
+      "\t\tsupplied values):\n\n"
+      "\t\t\tfrom:<name-or-address>\n"
+      "\t\t\tto:<name-or-address>\n"
+      "\t\t\tsubject:<word-or-quoted-phrase>\n"
       "\t\t\ttag:<tag>\n"
       "\t\t\tid:<message-id>\n"
       "\t\t\tthread:<thread-id>\n\n"
+      "\t\tThe from: prefix is used to match the name or address of\n"
+      "\t\tthe sender of an email message.\n\n"
+      "\t\tThe to: prefix is used to match the names or addresses of\n"
+      "\t\tany recipient of an email message, (whether To, Cc, or Bcc).\n\n"
+      "\t\tAny term prefixed with subject: will match only text from\n"
+      "\t\tthe subject of an email. Quoted phrases are supported when\n"
+      "\t\tsearching with: subject:\"this is a phrase\".\n\n"
       "\t\tValid tag values include \"inbox\" and \"unread\" by default\n"
       "\t\tfor new messages added by \"notmuch new\" as well as any other\n"
       "\t\ttag values added manually with \"notmuch tag\".\n\n"
@@ -1443,11 +1503,22 @@ command_t commands[] = {
       "\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.",