X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=contrib%2Fnotmuch-deliver%2Fsrc%2Fmain.c;h=032b9d6297daa14f850b4cccfb83013e53716070;hb=5973881b771b4da489a365572152c44e21c329eb;hp=49919ff10591631f4a06f7c808fe5f2fe035d0da;hpb=649db5eab6e67c753301633a9261a08be83d0f3b;p=notmuch diff --git a/contrib/notmuch-deliver/src/main.c b/contrib/notmuch-deliver/src/main.c index 49919ff1..032b9d62 100644 --- a/contrib/notmuch-deliver/src/main.c +++ b/contrib/notmuch-deliver/src/main.c @@ -1,22 +1,23 @@ -/* vim: set cino= fo=croql sw=8 ts=8 sts=0 noet cin fdm=syntax : */ - -/* - * Copyright (c) 2010 Ali Polatel +/* notmuch-deliver - If you make the user a promise... make sure you deliver it! + * + * Copyright © 2010 Ali Polatel * Based in part upon deliverquota of maildrop which is: * Copyright 1998 - 2009 Double Precision, Inc. * - * This file is part of the notmuch-deliver. notmuch-deliver is free software; - * you can redistribute it and/or modify it under the terms of the GNU General - * Public License version 2, as published by the Free Software Foundation. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * notmuch-deliver is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA + * Author: Ali Polatel */ #ifdef HAVE_CONFIG_H @@ -26,7 +27,12 @@ #include #include #include +#ifdef HAVE_UNISTD_H #include +#endif +#ifdef HAVE_SPLICE +#include +#endif #ifdef HAVE_SYSEXITS_H #include @@ -136,32 +142,60 @@ load_keyfile(const gchar *path, gchar **db_path, gchar ***tags) return TRUE; } +#ifdef HAVE_SPLICE static int -save_maildir(int fdin, const char *dir, int auto_create, char **path) +save_splice(int fdin, int fdout) { - int fd, ret, written; - char buf[4096], *p; - struct maildir_tmpcreate_info info; + int ret, written, pfd[2]; - maildir_tmpcreate_init(&info); - info.openmode = 0666; - info.maildir = dir; - info.doordie = 1; + if (pipe(pfd) < 0) { + g_critical("Failed to create pipe: %s", g_strerror(errno)); + return EX_IOERR; + } - while ((fd = maildir_tmpcreate_fd(&info)) < 0) - { - if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0) - { - auto_create = 0; - continue; + for (;;) { + ret = splice(fdin, NULL, pfd[1], NULL, 4096, 0); + if (!ret) + break; + if (ret < 0) { + g_critical("Splicing data from standard input failed: %s", + g_strerror(errno)); + close(pfd[0]); + close(pfd[1]); + return EX_IOERR; } - g_critical("Failed to create temporary file `%s': %s", - info.tmpname, g_strerror(errno)); - return EX_TEMPFAIL; + do { + written = splice(pfd[0], NULL, fdout, NULL, ret, 0); + if (!written) { + g_critical("Splicing data to temporary file failed: internal error"); + close(pfd[0]); + close(pfd[1]); + return EX_IOERR; + } + if (written < 0) { + g_critical("Splicing data to temporary file failed: %s", + g_strerror(errno)); + close(pfd[0]); + close(pfd[1]); + return EX_IOERR; + } + ret -= written; + } while (ret); } - g_debug("Reading from standard input and writing to `%s'", info.tmpname); + close(pfd[0]); + close(pfd[1]); + return 0; +} +#endif /* HAVE_SPLICE */ + +static int +save_readwrite(int fdin, int fdout) +{ + int ret, written; + char buf[4096], *p; + for (;;) { ret = read(fdin, buf, 4096); if (!ret) @@ -169,27 +203,66 @@ save_maildir(int fdin, const char *dir, int auto_create, char **path) if (ret < 0) { if (errno == EINTR) continue; - g_critical("Reading from standard input failed: %s", g_strerror(errno)); - goto fail; + g_critical("Reading from standard input failed: %s", + g_strerror(errno)); + return EX_IOERR; } p = buf; do { - written = write(fd, p, ret); + written = write(fdout, p, ret); if (!written) - goto fail; + return EX_IOERR; if (written < 0) { if (errno == EINTR) continue; - g_critical("Writing to temporary file `%s' failed: %s", - info.tmpname, g_strerror(errno)); - goto fail; + g_critical("Writing to temporary file failed: %s", + g_strerror(errno)); + return EX_IOERR; } p += written; ret -= written; } while (ret); } - close(fd); + return 0; +} + +static int +save_maildir(int fdin, const char *dir, int auto_create, char **path) +{ + int fdout, ret; + struct maildir_tmpcreate_info info; + + maildir_tmpcreate_init(&info); + info.openmode = 0666; + info.maildir = dir; + info.doordie = 1; + + while ((fdout = maildir_tmpcreate_fd(&info)) < 0) + { + if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0) + { + auto_create = 0; + continue; + } + + g_critical("Failed to create temporary file `%s': %s", + info.tmpname, g_strerror(errno)); + return EX_TEMPFAIL; + } + + g_debug("Reading from standard input and writing to `%s'", info.tmpname); +#ifdef HAVE_SPLICE + ret = g_getenv("NOTMUCH_DELIVER_NO_SPLICE") + ? save_readwrite(fdin, fdout) + : save_splice(fdin, fdout); +#else + ret = save_readwrite(fdin, fdout); +#endif /* HAVE_SPLICE */ + if (ret) + goto fail; + + close(fdout); g_debug("Moving `%s' to `%s'", info.tmpname, info.newname); if (maildir_movetmpnew(info.tmpname, info.newname)) { g_critical("Moving `%s' to `%s' failed: %s", @@ -286,6 +359,7 @@ main(int argc, char **argv) GOptionContext *ctx; GError *error = NULL; notmuch_database_t *db; + notmuch_status_t status; ctx = g_option_context_new("[FOLDER]"); g_option_context_add_main_entries(ctx, options, PACKAGE); @@ -295,6 +369,9 @@ main(int argc, char **argv) " "PACKAGE" uses notmuch's configuration file to determine database path and\n" " initial tags to add to new messages. You may set NOTMUCH_CONFIG environment\n" " variable to specify an alternative configuration file.\n" + "\nEnvironment:\n" + " NOTMUCH_CONFIG: Path to notmuch configuration file\n" + " NOTMUCH_DELIVER_NO_SPLICE: Don't use splice() even if it's available\n" "\nExit codes:\n" " 0 => Successful run\n" " 64 => Usage error\n" @@ -339,6 +416,11 @@ main(int argc, char **argv) } g_free(conf_path); + if ((argc - 1) > 1) { + g_critical("Won't deliver to %d folders", argc - 1); + return EX_USAGE; + } + if (argc > 1) { folder = g_strdup_printf("%s%s", opt_folder ? "." : "", argv[1]); maildir = g_build_filename(db_path, folder, NULL); @@ -348,7 +430,14 @@ main(int argc, char **argv) maildir = g_strdup(db_path); g_debug("Opening notmuch database `%s'", db_path); - db = notmuch_database_open(db_path, NOTMUCH_DATABASE_MODE_READ_WRITE); + status = notmuch_database_open(db_path, NOTMUCH_DATABASE_MODE_READ_WRITE, + &db); + if (status) { + g_critical("Failed to open database `%s': %s", + db_path, notmuch_status_to_string(status)); + g_free(maildir); + return EX_SOFTWARE; + } g_free(db_path); if (db == NULL) return EX_SOFTWARE; @@ -374,7 +463,7 @@ main(int argc, char **argv) g_strfreev(opt_rtags); g_free(mail); - notmuch_database_close(db); + notmuch_database_destroy(db); return 0; }