1 /* notmuch - Not much of an email program, (just index and search)
3 * Copyright © 2009 Carl Worth
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see http://www.gnu.org/licenses/ .
18 * Author: Carl Worth <cworth@cworth.org>
21 #include "notmuch-client.h"
23 static notmuch_status_t
24 add_all_files (notmuch_database_t *notmuch,
25 const char *mail_directory,
28 add_files_state_t add_files_state;
30 struct timeval tv_now;
31 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
33 add_files_state.ignore_read_only_directories = FALSE;
34 add_files_state.saw_read_only_directory = FALSE;
35 add_files_state.total_files = num_files;
36 add_files_state.processed_files = 0;
37 add_files_state.added_messages = 0;
38 add_files_state.callback = NULL;
39 gettimeofday (&add_files_state.tv_start, NULL);
41 ret = add_files (notmuch, mail_directory, &add_files_state);
43 gettimeofday (&tv_now, NULL);
44 elapsed = notmuch_time_elapsed (add_files_state.tv_start,
46 printf ("Processed %d %s in ", add_files_state.processed_files,
47 add_files_state.processed_files == 1 ?
48 "file" : "total files");
49 notmuch_time_print_formatted_seconds (elapsed);
51 printf (" (%d files/sec.). \n",
52 (int) (add_files_state.processed_files / elapsed));
56 if (add_files_state.added_messages) {
57 printf ("Added %d %s to the database.\n\n",
58 add_files_state.added_messages,
59 add_files_state.added_messages == 1 ?
60 "message" : "unique messages");
67 /* XXX: This should be merged with the existing add_files function in
69 /* Recursively count all regular files in path and all sub-direcotries
70 * of path. The result is added to *count (which should be
71 * initialized to zero by the top-level caller before calling
74 count_files (const char *path, int *count)
77 struct dirent *e, *entry = NULL;
86 fprintf (stderr, "Warning: failed to open directory %s: %s\n",
87 path, strerror (errno));
91 entry_length = offsetof (struct dirent, d_name) +
92 pathconf (path, _PC_NAME_MAX) + 1;
93 entry = malloc (entry_length);
96 err = readdir_r (dir, entry, &e);
98 fprintf (stderr, "Error reading directory: %s\n",
107 /* Ignore special directories to avoid infinite recursion.
108 * Also ignore the .notmuch directory.
110 /* XXX: Eventually we'll want more sophistication to let the
111 * user specify files to be ignored. */
112 if (strcmp (entry->d_name, ".") == 0 ||
113 strcmp (entry->d_name, "..") == 0 ||
114 strcmp (entry->d_name, ".notmuch") == 0)
119 if (asprintf (&next, "%s/%s", path, entry->d_name) == -1) {
121 fprintf (stderr, "Error descending from %s to %s: Out of memory\n",
122 path, entry->d_name);
128 if (S_ISREG (st.st_mode)) {
130 if (*count % 1000 == 0) {
131 printf ("Found %d files so far.\r", *count);
134 } else if (S_ISDIR (st.st_mode)) {
135 count_files (next, count);
149 welcome_message (void)
152 "Welcome to notmuch!\n\n"
153 "The goal of notmuch is to help you manage and search your collection of\n"
154 "email, and to efficiently keep up with the flow of email as it comes in.\n\n"
155 "Notmuch needs to know the top-level directory of your email archive,\n"
156 "(where you already have mail stored and where messages will be delivered\n"
157 "in the future). This directory can contain any number of sub-directories\n"
158 "and primarily just files with indvidual email messages (eg. maildir or mh\n"
159 "archives are perfect). If there are other, non-email files (such as\n"
160 "indexes maintained by other email programs) then notmuch will do its\n"
161 "best to detect those and ignore them.\n\n"
162 "Mail storage that uses mbox format, (where one mbox file contains many\n"
163 "messages), will not work with notmuch. If that's how your mail is currently\n"
164 "stored, we recommend you first convert it to maildir format with a utility\n"
165 "such as mb2md. In that case, press Control-C now and run notmuch again\n"
166 "once the conversion is complete.\n\n");
170 prompt_user_for_mail_directory ()
172 char *default_path, *mail_directory = NULL;
175 default_path = notmuch_database_default_path ();
176 printf ("Top-level mail directory [%s]: ", default_path);
179 getline (&mail_directory, &line_size, stdin);
180 chomp_newline (mail_directory);
184 if (mail_directory == NULL || strlen (mail_directory) == 0) {
186 free (mail_directory);
187 mail_directory = default_path;
189 /* XXX: Instead of telling the user to use an environment
190 * variable here, we should really be writing out a configuration
191 * file and loading that on the next run. */
192 if (strcmp (mail_directory, default_path)) {
193 printf ("Note: Since you are not using the default path, you will want to set\n"
194 "the NOTMUCH_BASE environment variable to %s so that\n"
195 "future calls to notmuch commands will know where to find your mail.\n",
197 printf ("For example, if you are using bash for your shell, add:\n\n");
198 printf ("\texport NOTMUCH_BASE=%s\n\n", mail_directory);
199 printf ("to your ~/.bashrc file.\n\n");
204 /* Coerce the directory into an absolute directory name. */
205 if (*mail_directory != '/') {
206 char *cwd, *absolute_mail_directory;
208 cwd = getcwd (NULL, 0);
210 fprintf (stderr, "Out of memory.\n");
214 if (asprintf (&absolute_mail_directory, "%s/%s",
215 cwd, mail_directory) < 0)
217 fprintf (stderr, "Out of memory.\n");
222 free (mail_directory);
223 mail_directory = absolute_mail_directory;
226 return mail_directory;
230 notmuch_setup_command (unused (void *ctx),
231 unused (int argc), unused (char *argv[]))
233 notmuch_database_t *notmuch = NULL;
234 char *mail_directory = NULL;
236 notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
240 mail_directory = prompt_user_for_mail_directory ();
242 notmuch = notmuch_database_create (mail_directory);
243 if (notmuch == NULL) {
244 fprintf (stderr, "Failed to create new notmuch database at %s\n",
246 ret = NOTMUCH_STATUS_FILE_ERROR;
250 printf ("OK. Let's take a look at the mail we can find in the directory\n");
251 printf ("%s ...\n", mail_directory);
254 count_files (mail_directory, &count);
256 printf ("Found %d total files. That's not much mail.\n\n", count);
258 printf ("Next, we'll inspect the messages and create a database of threads:\n");
260 ret = add_all_files (notmuch, mail_directory, count);
262 printf ("When new mail is delivered to %s in the future,\n"
263 "run \"notmuch new\" to add it to the database.\n\n",
267 printf ("Note: At least one error was encountered: %s\n",
268 notmuch_status_to_string (ret));
273 free (mail_directory);
275 notmuch_database_close (notmuch);