+typedef struct {
+ int total_messages;
+ int count;
+ struct timeval tv_start;
+} add_files_state_t;
+
+/* Compute the number of seconds elapsed from start to end. */
+double
+tv_elapsed (struct timeval start, struct timeval end)
+{
+ return ((end.tv_sec - start.tv_sec) +
+ (end.tv_usec - start.tv_usec) / 1e6);
+}
+
+void
+print_formatted_seconds (double seconds)
+{
+ int hours;
+ int minutes;
+
+ if (seconds > 3600) {
+ hours = (int) seconds / 3600;
+ printf ("%dh ", hours);
+ seconds -= hours * 3600;
+ }
+
+ if (seconds > 60) {
+ minutes = (int) seconds / 60;
+ printf ("%dm ", minutes);
+ seconds -= minutes * 60;
+ }
+
+ printf ("%02ds", (int) seconds);
+}
+
+void
+add_files_print_progress (add_files_state_t *state)
+{
+ struct timeval tv_now;
+ double elapsed_overall, rate_overall;
+
+ gettimeofday (&tv_now, NULL);
+
+ elapsed_overall = tv_elapsed (state->tv_start, tv_now);
+ rate_overall = (state->count) / elapsed_overall;
+
+ 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);
+}
+
+/* Recursively find all regular files in 'path' and add them to the
+ * database. */
+void
+add_files (notmuch_database_t *notmuch, const char *path,
+ add_files_state_t *state)
+{
+ DIR *dir;
+ struct dirent *entry, *e;
+ int entry_length;
+ int err;
+ char *next;
+ struct stat st;
+ notmuch_status_t status;
+
+ dir = opendir (path);
+
+ if (dir == NULL) {
+ fprintf (stderr, "Warning: failed to open directory %s: %s\n",
+ path, strerror (errno));
+ return;
+ }
+
+ entry_length = offsetof (struct dirent, d_name) +
+ pathconf (path, _PC_NAME_MAX) + 1;
+ entry = malloc (entry_length);
+
+ while (1) {
+ err = readdir_r (dir, entry, &e);
+ if (err) {
+ fprintf (stderr, "Error reading directory: %s\n",
+ strerror (errno));
+ free (entry);
+ return;
+ }
+
+ if (e == NULL)
+ break;
+
+ /* Ignore special directories to avoid infinite recursion.
+ * Also ignore the .notmuch directory.
+ */
+ /* XXX: Eventually we'll want more sophistication to let the
+ * user specify files to be ignored. */
+ if (strcmp (entry->d_name, ".") == 0 ||
+ strcmp (entry->d_name, "..") == 0 ||
+ strcmp (entry->d_name, ".notmuch") ==0)
+ {
+ continue;
+ }
+
+ next = g_strdup_printf ("%s/%s", path, entry->d_name);
+
+ stat (next, &st);
+
+ if (S_ISREG (st.st_mode)) {
+ 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)) {
+ add_files (notmuch, next, state);
+ }
+
+ free (next);
+ }
+
+ free (entry);
+
+ closedir (dir);
+}
+