]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch.c
notmuch_database_create/open: Fix to handle NULL as documented.
[notmuch] / notmuch.c
index e4b5dff6442fc686456410ee01871bcb858bff7e..dac19d8955ec231bf9177df2f2e358adfd24b587 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -30,7 +30,7 @@
 #include <dirent.h>
 #include <errno.h>
 
-#include <glib.h>
+#include <glib.h> /* GIOChannel */
 
 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
 
@@ -79,11 +79,9 @@ read_line (void)
 }
 
 typedef struct {
-    int messages_total;
+    int total_messages;
     int count;
-    int count_last;
     struct timeval tv_start;
-    struct timeval tv_last;
 } add_files_state_t;
 
 /* Compute the number of seconds elapsed from start to end. */
@@ -102,47 +100,37 @@ print_formatted_seconds (double seconds)
 
     if (seconds > 3600) {
        hours = (int) seconds / 3600;
-       printf ("%d:", hours);
+       printf ("%d", hours);
        seconds -= hours * 3600;
     }
 
-    if (seconds > 60)
+    if (seconds > 60) {
        minutes = (int) seconds / 60;
-    else
-       minutes = 0;
-
-    printf ("%02d:", minutes);
-    seconds -= minutes * 60;
+       printf ("%dm ", minutes);
+       seconds -= minutes * 60;
+    }
 
-    printf ("%02d", (int) seconds);
+    printf ("%02ds", (int) seconds);
 }
 
 void
 add_files_print_progress (add_files_state_t *state)
 {
     struct timeval tv_now;
-    double ratio_complete;
-    double elapsed_current, rate_current;
-    double elapsed_overall;
+    double elapsed_overall, rate_overall;
 
     gettimeofday (&tv_now, NULL);
 
-    ratio_complete = (double) state->count / state->messages_total;
-    elapsed_current = tv_elapsed (state->tv_last, tv_now);
-    rate_current = (state->count - state->count_last) / elapsed_current;
     elapsed_overall = tv_elapsed (state->tv_start, tv_now);
+    rate_overall = (state->count) / elapsed_overall;
 
-    printf ("Added %d messages at %d messages/sec. ",
-           state->count, (int) rate_current);
-    print_formatted_seconds (elapsed_overall);
-    printf ("/");
-    print_formatted_seconds (elapsed_overall / ratio_complete);
-    printf (" elapsed (%.2f%%).     \r", 100 * ratio_complete);
+    printf ("Added %d of %d messages (",
+           state->count, state->total_messages);
+    print_formatted_seconds ((state->total_messages - state->count) /
+                            rate_overall);
+    printf (" remaining).\r");
 
     fflush (stdout);
-
-    state->tv_last = tv_now;
-    state->count_last = state->count;
 }
 
 /* Recursively find all regular files in 'path' and add them to the
@@ -157,6 +145,7 @@ add_files (notmuch_database_t *notmuch, const char *path,
     int err;
     char *next;
     struct stat st;
+    notmuch_status_t status;
 
     dir = opendir (path);
 
@@ -199,8 +188,13 @@ add_files (notmuch_database_t *notmuch, const char *path,
        stat (next, &st);
 
        if (S_ISREG (st.st_mode)) {
-           notmuch_database_add_message (notmuch, next);
-           state->count++;
+           status = notmuch_database_add_message (notmuch, next);
+           if (status == NOTMUCH_STATUS_FILE_NOT_EMAIL) {
+               fprintf (stderr, "Note: Ignoring non-mail file: %s\n",
+                        next);
+           } else {
+               state->count++;
+           }
            if (state->count % 1000 == 0)
                add_files_print_progress (state);
        } else if (S_ISDIR (st.st_mode)) {
@@ -295,6 +289,7 @@ setup_command (int argc, char *argv[])
     int count;
     add_files_state_t add_files_state;
     double elapsed;
+    struct timeval tv_now;
 
     printf ("Welcome to notmuch!\n\n");
 
@@ -304,9 +299,10 @@ setup_command (int argc, char *argv[])
     printf ("Notmuch needs to know the top-level directory of your email archive,\n"
            "(where you already have mail stored and where messages will be delivered\n"
            "in the future). This directory can contain any number of sub-directories\n"
-           "but the only files it contains should be individual email messages.\n"
-           "Either maildir or mh format directories are fine, but you will want to\n"
-           "move away any auxiliary files maintained by other email programs.\n\n");
+           "and primarily just files with indvidual email messages (eg. maildir or mh\n"
+           "archives are perfect). If there are other, non-email files (such as\n"
+           "indexes maintained by other email programs) then notmuch will do its\n"
+           "best to detect those and ignore them.\n\n");
 
     printf ("Mail storage that uses mbox format, (where one mbox file contains many\n"
            "messages), will not work with notmuch. If that's how your mail is currently\n"
@@ -314,25 +310,19 @@ setup_command (int argc, char *argv[])
            "such as mb2md. In that case, press Control-C now and run notmuch again\n"
            "once the conversion is complete.\n\n");
 
-    printf ("Top-level mail directory [~/mail]: ");
-    fflush (stdout);
+    {
+       char *default_path = notmuch_database_default_path ();
+       printf ("Top-level mail directory [%s]: ", default_path);
+       free (default_path);
+       fflush (stdout);
+    }
 
     mail_directory = read_line ();
 
     if (mail_directory == NULL || strlen (mail_directory) == 0) {
-       char *home;
-
        if (mail_directory)
            free (mail_directory);
-
-       home = getenv ("HOME");
-       if (!home) {
-           fprintf (stderr, "Error: No mail directory provided HOME environment variable is not set.\n");
-           fprintf (stderr, "Cowardly refusing to just guess where your mail might be.\n");
-           exit (1);
-       }
-
-       mail_directory = g_strdup_printf ("%s/mail", home);
+       mail_directory = notmuch_database_default_path ();
     }
 
     notmuch = notmuch_database_create (mail_directory);
@@ -353,17 +343,15 @@ setup_command (int argc, char *argv[])
 
     printf ("Next, we'll inspect the messages and create a database of threads:\n");
 
-    add_files_state.messages_total = count;
+    add_files_state.total_messages = count;
     add_files_state.count = 0;
-    add_files_state.count_last = 0;
     gettimeofday (&add_files_state.tv_start, NULL);
-    add_files_state.tv_last = add_files_state.tv_start;
 
     add_files (notmuch, mail_directory, &add_files_state);
 
-    gettimeofday (&add_files_state.tv_last, NULL);
+    gettimeofday (&tv_now, NULL);
     elapsed = tv_elapsed (add_files_state.tv_start,
-                         add_files_state.tv_last);
+                         tv_now);
     printf ("Added %d total messages in ", add_files_state.count);
     print_formatted_seconds (elapsed);
     printf (" (%d messages/sec.).                 \n", (int) (add_files_state.count / elapsed));
@@ -385,19 +373,49 @@ search_command (int argc, char *argv[])
 int
 show_command (int argc, char *argv[])
 {
-    fprintf (stderr, "Error: show-thread is not implemented yet.\n");
+    fprintf (stderr, "Error: show is not implemented yet.\n");
+    return 1;
+}
+
+int
+dump_command (int argc, char *argv[])
+{
+    fprintf (stderr, "Error: dump is not implemented yet.\n");
+    return 1;
+}
+
+int
+restore_command (int argc, char *argv[])
+{
+    fprintf (stderr, "Error: restore is not implemented yet.\n");
     return 1;
 }
 
 command_t commands[] = {
     { "setup", setup_command,
-      "Interactively setup notmuch for first use (no arguments).\n"
+      "Interactively setup notmuch for first use.\n"
       "\t\tInvoking notmuch with no command argument will run setup if\n"
-      "\t\the setup command has not previously been completed." },
+      "\t\tthe setup command has not previously been completed." },
     { "search", search_command,
-      "Search for threads matching the given search terms." },
+      "<search-term> [...]\n\n"
+      "\t\tSearch for threads matching the given search terms.\n"
+      "\t\tOnce we actually implement search we'll document the\n"
+      "\t\tsyntax here." },
     { "show", show_command,
-      "Show the thread with the given thread ID (see 'search')." }
+      "<thread-id>\n\n"
+      "\t\tShow the thread with the given thread ID (see 'search')." },
+    { "dump", dump_command,
+      "[<filename>]\n\n"
+      "\t\tCreate a plain-text dump of the tags for each message\n"
+      "\t\twriting to the given filename, if any, or to stdout.\n"
+      "\t\tThese tags are the only data in the notmuch database\n"
+      "\t\tthat can't be recreated from the messages themselves.\n"
+      "\t\tThe output of notmuch dump is therefore the only\n"
+      "\t\tcritical thing to backup (and much more friendly to\n"
+      "\t\tincremental backup than the native database files." },
+    { "restore", restore_command,
+      "<filename>\n\n"
+      "\t\tRestore the tags from the given dump file (see 'dump')." }
 };
 
 void
@@ -408,7 +426,7 @@ usage (void)
 
     fprintf (stderr, "Usage: notmuch <command> [args...]\n");
     fprintf (stderr, "\n");
-    fprintf (stderr, "Where <command> is one of the following:\n");
+    fprintf (stderr, "Where <command> and [args...] are as follows:\n");
     fprintf (stderr, "\n");
 
     for (i = 0; i < ARRAY_SIZE (commands); i++) {
@@ -434,7 +452,15 @@ main (int argc, char *argv[])
            return (command->function) (argc - 2, &argv[2]);
     }
 
-    fprintf (stderr, "Error: Unknown command '%s'\n\n", argv[1]);
+    /* Don't complain about "help" being an unknown command when we're
+       about to provide exactly what's wanted anyway. */
+    if (strcmp (argv[1], "help") == 0 ||
+       strcmp (argv[1], "--help") == 0)
+    {
+       fprintf (stderr, "The notmuch mail system.\n\n");
+    } else {
+       fprintf (stderr, "Error: Unknown command '%s'\n\n", argv[1]);
+    }
     usage ();
     exit (1);