]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch.c
TODO: Add several items.
[notmuch] / notmuch.c
index 66b615b2285605cd712852e3eb2060365028d43d..4158cc5f098bf13429168a389393beb1c42614dd 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -60,7 +60,7 @@
 
 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
 
-typedef int (*command_function_t) (int argc, char *argv[]);
+typedef int (*command_function_t) (void *ctx, int argc, char *argv[]);
 
 typedef struct command {
     const char *name;
@@ -471,7 +471,7 @@ count_files (const char *path, int *count)
 }
 
 static int
-setup_command (unused (int argc), unused (char *argv[]))
+setup_command (unused (void *ctx), unused (int argc), unused (char *argv[]))
 {
     notmuch_database_t *notmuch = NULL;
     char *default_path, *mail_directory = NULL;
@@ -629,7 +629,7 @@ tag_inbox_and_unread (notmuch_message_t *message)
 }
 
 static int
-new_command (unused (int argc), unused (char *argv[]))
+new_command (unused (void *ctx), unused (int argc), unused (char *argv[]))
 {
     notmuch_database_t *notmuch;
     const char *mail_directory;
@@ -733,16 +733,91 @@ query_string_from_args (void *ctx, int argc, char *argv[])
     return query_string;
 }
 
+/* Format a nice representation of 'time' relative to the current time.
+ *
+ * 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))
+ *     2008-06-30      (More than 180 days ago)
+ */
+#define MINUTE (60)
+#define HOUR (60 * MINUTE)
+#define DAY (24 * HOUR)
+#define RELATIVE_DATE_MAX 20
+static const char *
+_format_relative_date (void *ctx, time_t then)
+{
+    struct tm tm_now, tm_then;
+    time_t now = time(NULL);
+    time_t delta;
+    char *result;
+
+    localtime_r (&now, &tm_now);
+    localtime_r (&then, &tm_then);
+
+    result = talloc_zero_size (ctx, RELATIVE_DATE_MAX);
+    if (result == NULL)
+       return "when?";
+
+    if (then > now)
+       return "the future";
+
+    delta = now - then;
+
+    if (delta > 180 * DAY) {
+       strftime (result, RELATIVE_DATE_MAX,
+                 "%F", &tm_then); /* 2008-06-30 */
+       return result;
+    }
+
+    if (delta < 3600) {
+       snprintf (result, RELATIVE_DATE_MAX,
+                 "%d minutes ago", (int) (delta / 60));
+       return result;
+    }
+
+    if (delta <= 7 * DAY) {
+       if (tm_then.tm_wday == tm_now.tm_wday &&
+           delta < DAY)
+       {
+           strftime (result, RELATIVE_DATE_MAX,
+                     "%R", &tm_then); /* 12:30 */
+           return result;
+       } else if ((tm_now.tm_wday + 7 - tm_then.tm_wday) % 7 == 1) {
+           return "Yesterday";
+       } else {
+           if (tm_then.tm_wday != tm_now.tm_wday) {
+               strftime (result, RELATIVE_DATE_MAX,
+                         "%A", &tm_then); /* Monday */
+               return result;
+           }
+       }
+    }
+
+    strftime (result, RELATIVE_DATE_MAX,
+             "%b %d", &tm_then); /* Oct. 12 */
+    return result;
+}
+#undef MINUTE
+#undef HOUR
+#undef DAY
+
 static int
-search_command (int argc, char *argv[])
+search_command (void *ctx, int argc, char *argv[])
 {
-    void *local = talloc_new (NULL);
+    void *local = talloc_new (ctx);
     notmuch_database_t *notmuch = NULL;
     notmuch_query_t *query;
-    notmuch_thread_results_t *results;
+    notmuch_threads_t *threads;
     notmuch_thread_t *thread;
     notmuch_tags_t *tags;
     char *query_str;
+    const char *relative_date;
+    time_t date;
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
 
     notmuch = notmuch_database_open (NULL);
@@ -760,16 +835,20 @@ search_command (int argc, char *argv[])
        goto DONE;
     }
 
-    for (results = notmuch_query_search_threads (query);
-        notmuch_thread_results_has_more (results);
-        notmuch_thread_results_advance (results))
+    for (threads = notmuch_query_search_threads (query);
+        notmuch_threads_has_more (threads);
+        notmuch_threads_advance (threads))
     {
        int first = 1;
 
-       thread = notmuch_thread_results_get (results);
+       thread = notmuch_threads_get (threads);
 
-       printf ("%s %s",
+       date = notmuch_thread_get_oldest_date (thread);
+       relative_date = _format_relative_date (local, date);
+
+       printf ("%s (%s) %s",
                notmuch_thread_get_thread_id (thread),
+               relative_date,
                notmuch_thread_get_subject (thread));
 
        printf (" (");
@@ -797,16 +876,45 @@ search_command (int argc, char *argv[])
     return ret;
 }
 
+/* Get a nice, single-line summary of message. */
+static const char *
+_get_one_line_summary (void *ctx, notmuch_message_t *message)
+{
+    const char *from;
+    time_t date;
+    const char *relative_date;
+    const char *subject;
+
+    from = notmuch_message_get_header (message, "from");
+
+    date = notmuch_message_get_date (message);
+    relative_date = _format_relative_date (ctx, date);
+
+    subject = notmuch_message_get_header (message, "subject");
+
+    return talloc_asprintf (ctx, "%s (%s) %s",
+                           from, relative_date, subject);
+}
+
 static int
-show_command (unused (int argc), unused (char *argv[]))
+show_command (void *ctx, unused (int argc), unused (char *argv[]))
 {
-    void *local = talloc_new (NULL);
+    void *local = talloc_new (ctx);
     char *query_string;
     notmuch_database_t *notmuch = NULL;
     notmuch_query_t *query = NULL;
-    notmuch_message_results_t *messages;
+    notmuch_messages_t *messages;
     notmuch_message_t *message;
+    const char *filename;
+    FILE *file;
     int ret = 0;
+    int c;
+
+    const char *headers[] = {
+       "Subject", "From", "To", "Cc", "Bcc", "Date"
+    };
+    const char *name, *value;
+    unsigned int i;
 
     if (argc != 1) {
        fprintf (stderr, "Error: \"notmuch show\" requires exactly one thread-ID argument.\n");
@@ -835,18 +943,41 @@ show_command (unused (int argc), unused (char *argv[]))
     }
 
     for (messages = notmuch_query_search_messages (query);
-        notmuch_message_results_has_more (messages);
-        notmuch_message_results_advance (messages))
+        notmuch_messages_has_more (messages);
+        notmuch_messages_advance (messages))
     {
-       message = notmuch_message_results_get (messages);
+       message = notmuch_messages_get (messages);
 
        printf ("%%message{\n");
 
        printf ("%%header{\n");
 
-       printf ("%s", notmuch_message_get_all_headers (message));
+       printf ("%s\n", _get_one_line_summary (local, message));
+
+       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);
+       }
 
        printf ("%%header}\n");
+
+       filename = notmuch_message_get_filename (message);
+
+       file = fopen (filename, "r");
+       if (file) {
+           size_t header_size = notmuch_message_get_header_size (message);
+           fseek (file, header_size + 1, SEEK_SET);
+           while (1) {
+               c = fgetc (file);
+               if (c == EOF)
+                   break;
+               putchar (c);
+           }
+       }
+       fclose (file);
+
        printf ("%%message}\n");
 
        notmuch_message_destroy (message);
@@ -866,7 +997,7 @@ show_command (unused (int argc), unused (char *argv[]))
 }
 
 static int
-tag_command (unused (int argc), unused (char *argv[]))
+tag_command (void *ctx, unused (int argc), unused (char *argv[]))
 {
     void *local;
     int *add_tags, *remove_tags;
@@ -875,12 +1006,12 @@ tag_command (unused (int argc), unused (char *argv[]))
     char *query_string;
     notmuch_database_t *notmuch = NULL;
     notmuch_query_t *query;
-    notmuch_message_results_t *results;
+    notmuch_messages_t *messages;
     notmuch_message_t *message;
     int ret = 0;
     int i;
 
-    local = talloc_new (NULL);
+    local = talloc_new (ctx);
     if (local == NULL) {
        ret = 1;
        goto DONE;
@@ -939,11 +1070,11 @@ tag_command (unused (int argc), unused (char *argv[]))
        goto DONE;
     }
 
-    for (results = notmuch_query_search_messages (query);
-        notmuch_message_results_has_more (results);
-        notmuch_message_results_advance (results))
+    for (messages = notmuch_query_search_messages (query);
+        notmuch_messages_has_more (messages);
+        notmuch_messages_advance (messages))
     {
-       message = notmuch_message_results_get (results);
+       message = notmuch_messages_get (messages);
 
        notmuch_message_freeze (message);
 
@@ -971,12 +1102,12 @@ tag_command (unused (int argc), unused (char *argv[]))
 }
 
 static int
-dump_command (int argc, char *argv[])
+dump_command (unused (void *ctx), int argc, char *argv[])
 {
     FILE *output = NULL;
     notmuch_database_t *notmuch = NULL;
     notmuch_query_t *query;
-    notmuch_message_results_t *results;
+    notmuch_messages_t *messages;
     notmuch_message_t *message;
     notmuch_tags_t *tags;
     int ret = 0;
@@ -1008,12 +1139,12 @@ dump_command (int argc, char *argv[])
 
     notmuch_query_set_sort (query, NOTMUCH_SORT_MESSAGE_ID);
 
-    for (results = notmuch_query_search_messages (query);
-        notmuch_message_results_has_more (results);
-        notmuch_message_results_advance (results))
+    for (messages = notmuch_query_search_messages (query);
+        notmuch_messages_has_more (messages);
+        notmuch_messages_advance (messages))
     {
        int first = 1;
-       message = notmuch_message_results_get (results);
+       message = notmuch_messages_get (messages);
 
        fprintf (output,
                 "%s (", notmuch_message_get_message_id (message));
@@ -1047,7 +1178,7 @@ dump_command (int argc, char *argv[])
 }
 
 static int
-restore_command (int argc, char *argv[])
+restore_command (unused (void *ctx), int argc, char *argv[])
 {
     FILE *input = NULL;
     notmuch_database_t *notmuch = NULL;
@@ -1156,7 +1287,7 @@ restore_command (int argc, char *argv[])
 }
 
 static int
-help_command (int argc, char *argv[]);
+help_command (void *ctx, int argc, char *argv[]);
 
 command_t commands[] = {
     { "setup", setup_command,
@@ -1174,7 +1305,7 @@ command_t commands[] = {
       "\t\t\"inbox\" and \"unread\".\n"
       "\n"
       "\t\tNote: \"notmuch new\" will skip any read-only directories,\n"
-      "\t\tso you can use that to mark tdirectories that will not\n"
+      "\t\tso you can use that to mark directories that will not\n"
       "\t\treceive any new mail (and make \"notmuch new\" faster)." },
     { "search", search_command,
       "<search-term> [...]\n\n"
@@ -1206,7 +1337,6 @@ command_t commands[] = {
       "\t\tmarks around any parenthesized expression)." },
     { "show", show_command,
       "<thread-id>\n\n"
-      "\t\tNote: The \"notmuch show\" command is not implemented yet.\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"
@@ -1274,7 +1404,7 @@ usage (void)
 }
 
 static int
-help_command (int argc, char *argv[])
+help_command (unused (void *ctx), int argc, char *argv[])
 {
     command_t *command;
     unsigned int i;
@@ -1305,23 +1435,26 @@ help_command (int argc, char *argv[])
 int
 main (int argc, char *argv[])
 {
+    void *local = talloc_new (NULL);
     command_t *command;
     unsigned int i;
 
     if (argc == 1)
-       return setup_command (0, NULL);
+       return setup_command (local, 0, NULL);
 
     for (i = 0; i < ARRAY_SIZE (commands); i++) {
        command = &commands[i];
 
        if (strcmp (argv[1], command->name) == 0)
-           return (command->function) (argc - 2, &argv[2]);
+           return (command->function) (local, argc - 2, &argv[2]);
     }
 
     /* Don't complain about "help" being an unknown command when we're
        about to provide exactly what's wanted anyway. */
-    fprintf (stderr, "Error: Unknown command '%s'\n\n", argv[1]);
-    usage ();
+    fprintf (stderr, "Error: Unknown command '%s' (see \"notmuch help\")\n",
+            argv[1]);
+
+    talloc_free (local);
 
     return 1;
 }