static notmuch_bool_t
sync_dir (const char *dir)
{
- notmuch_bool_t ret;
- int fd;
+ int fd, r;
fd = open (dir, O_RDONLY);
if (fd == -1) {
- fprintf (stderr, "Error: open() dir failed: %s\n", strerror (errno));
+ fprintf (stderr, "Error: open %s: %s\n", dir, strerror (errno));
return FALSE;
}
- ret = (fsync (fd) == 0);
- if (! ret) {
- fprintf (stderr, "Error: fsync() dir failed: %s\n", strerror (errno));
- }
+
+ r = fsync (fd);
+ if (r)
+ fprintf (stderr, "Error: fsync %s: %s\n", dir, strerror (errno));
+
close (fd);
- return ret;
+
+ return r == 0;
}
-/* Check the specified folder name does not contain a directory
- * component ".." to prevent writes outside of the Maildir hierarchy. */
+/*
+ * Check the specified folder name does not contain a directory
+ * component ".." to prevent writes outside of the Maildir
+ * hierarchy. Return TRUE on valid folder name, FALSE otherwise.
+ */
static notmuch_bool_t
-check_folder_name (const char *folder)
+is_valid_folder_name (const char *folder)
{
const char *p = folder;
return fd;
}
-/* Copy the contents of standard input (fdin) into fdout.
- * Returns TRUE if a non-empty file was written successfully.
- * Otherwise, return FALSE. */
+/*
+ * Copy fdin to fdout, return TRUE on success, and FALSE on errors and
+ * empty input.
+ */
static notmuch_bool_t
-copy_stdin (int fdin, int fdout)
+copy_fd (int fdout, int fdin)
{
notmuch_bool_t empty = TRUE;
return (!interrupted && !empty);
}
+static notmuch_bool_t
+write_message (void *ctx, int fdin, const char *dir, char **newpath)
+{
+ char *tmppath;
+ char *newdir;
+ char *cleanup_path;
+ int fdout;
+
+ fdout = maildir_open_tmp_file (ctx, dir, &tmppath, newpath, &newdir);
+ if (fdout < 0)
+ return FALSE;
+
+ cleanup_path = tmppath;
+
+ if (! copy_fd (fdout, fdin))
+ goto FAIL;
+
+ if (fsync (fdout) != 0) {
+ fprintf (stderr, "Error: fsync failed: %s\n", strerror (errno));
+ goto FAIL;
+ }
+
+ close (fdout);
+ fdout = -1;
+
+ /* Atomically move the new message file from the Maildir 'tmp' directory
+ * to the 'new' directory. We follow the Dovecot recommendation to
+ * simply use rename() instead of link() and unlink().
+ * See also: http://wiki.dovecot.org/MailboxFormat/Maildir#Mail_delivery
+ */
+ if (rename (tmppath, *newpath) != 0) {
+ fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));
+ goto FAIL;
+ }
+
+ cleanup_path = *newpath;
+
+ if (! sync_dir (newdir))
+ goto FAIL;
+
+ return TRUE;
+
+ FAIL:
+ if (fdout >= 0)
+ close (fdout);
+ unlink (cleanup_path);
+ return FALSE;
+}
+
/* Add the specified message file to the notmuch database, applying tags.
* The file is renamed to encode notmuch tags as maildir flags. */
static void
notmuch_message_destroy (message);
}
-static notmuch_bool_t
-insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
- const char *dir, tag_op_list_t *tag_ops,
- notmuch_bool_t synchronize_flags)
-{
- char *tmppath;
- char *newpath;
- char *newdir;
- int fdout;
- char *cleanup_path;
-
- fdout = maildir_open_tmp_file (ctx, dir, &tmppath, &newpath, &newdir);
- if (fdout < 0)
- return FALSE;
-
- cleanup_path = tmppath;
-
- if (! copy_stdin (fdin, fdout))
- goto FAIL;
-
- if (fsync (fdout) != 0) {
- fprintf (stderr, "Error: fsync failed: %s\n", strerror (errno));
- goto FAIL;
- }
-
- close (fdout);
- fdout = -1;
-
- /* Atomically move the new message file from the Maildir 'tmp' directory
- * to the 'new' directory. We follow the Dovecot recommendation to
- * simply use rename() instead of link() and unlink().
- * See also: http://wiki.dovecot.org/MailboxFormat/Maildir#Mail_delivery
- */
- if (rename (tmppath, newpath) != 0) {
- fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));
- goto FAIL;
- }
-
- cleanup_path = newpath;
-
- if (! sync_dir (newdir))
- goto FAIL;
-
- /* Even if adding the message to the notmuch database fails,
- * the message is on disk and we consider the delivery completed. */
- add_file_to_database (notmuch, newpath, tag_ops, synchronize_flags);
-
- return TRUE;
-
- FAIL:
- if (fdout >= 0)
- close (fdout);
- unlink (cleanup_path);
- return FALSE;
-}
-
int
notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
{
notmuch_bool_t create_folder = FALSE;
notmuch_bool_t synchronize_flags;
const char *maildir;
+ char *newpath;
int opt_index;
unsigned int i;
- notmuch_bool_t ret;
notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, &folder, "folder", 0, 0 },
};
opt_index = parse_arguments (argc, argv, options, 1);
-
- if (opt_index < 0) {
- /* diagnostics already printed */
- return 1;
- }
+ if (opt_index < 0)
+ return EXIT_FAILURE;
db_path = notmuch_config_get_database_path (config);
new_tags = notmuch_config_get_new_tags (config, &new_tags_length);
tag_ops = tag_op_list_create (config);
if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
- return 1;
+ return EXIT_FAILURE;
}
for (i = 0; i < new_tags_length; i++) {
+ const char *error_msg;
+
+ error_msg = illegal_tag (new_tags[i], FALSE);
+ if (error_msg) {
+ fprintf (stderr, "Error: tag '%s' in new.tags: %s\n",
+ new_tags[i], error_msg);
+ return EXIT_FAILURE;
+ }
+
if (tag_op_list_append (tag_ops, new_tags[i], FALSE))
- return 1;
+ return EXIT_FAILURE;
}
if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
&query_string, tag_ops))
- return 1;
+ return EXIT_FAILURE;
if (*query_string != '\0') {
fprintf (stderr, "Error: unexpected query string: %s\n", query_string);
- return 1;
+ return EXIT_FAILURE;
}
if (folder == NULL) {
maildir = db_path;
} else {
- if (! check_folder_name (folder)) {
- fprintf (stderr, "Error: bad folder name: %s\n", folder);
- return 1;
+ if (! is_valid_folder_name (folder)) {
+ fprintf (stderr, "Error: invalid folder name: '%s'\n", folder);
+ return EXIT_FAILURE;
}
maildir = talloc_asprintf (config, "%s/%s", db_path, folder);
if (! maildir) {
fprintf (stderr, "Out of memory\n");
- return 1;
+ return EXIT_FAILURE;
}
if (create_folder && ! maildir_create_folder (config, maildir)) {
fprintf (stderr, "Error: creating maildir %s: %s\n",
maildir, strerror (errno));
- return 1;
+ return EXIT_FAILURE;
}
}
if (notmuch_database_open (notmuch_config_get_database_path (config),
NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
- return 1;
+ return EXIT_FAILURE;
+
+ /* Write the message to the Maildir new directory. */
+ if (! write_message (config, STDIN_FILENO, maildir, &newpath)) {
+ notmuch_database_destroy (notmuch);
+ return EXIT_FAILURE;
+ }
- ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops,
- synchronize_flags);
+ /* Add the message to the index.
+ * Even if adding the message to the notmuch database fails,
+ * the message is on disk and we consider the delivery completed. */
+ add_file_to_database (notmuch, newpath, tag_ops,
+ synchronize_flags);
notmuch_database_destroy (notmuch);
-
- return (ret) ? 0 : 1;
+ return EXIT_SUCCESS;
}