X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=contrib%2Fnotmuch-deliver%2Fsrc%2Fmain.c;h=6f32f73d68b97decbe382b3dc84cffc3e99f259d;hb=be2263e93035e778968e92d1b4db0166686be71b;hp=1fece76fe49c64d26decb228be5ec362368e7e9c;hpb=af863f8c7f1f1571df4f1172ec4e963fa654945e;p=notmuch diff --git a/contrib/notmuch-deliver/src/main.c b/contrib/notmuch-deliver/src/main.c index 1fece76f..6f32f73d 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", @@ -261,6 +334,7 @@ save_database(notmuch_database_t *db, const char *path, char **default_tags) case NOTMUCH_STATUS_SUCCESS: break; case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: + g_debug("Message is a duplicate, not adding tags"); return 0; default: g_warning("Failed to add `%s' to notmuch database: %s", @@ -292,8 +366,11 @@ main(int argc, char **argv) g_option_context_set_description(ctx, "\nConfiguration:\n" " "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" + " 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" @@ -303,7 +380,7 @@ main(int argc, char **argv) " (failed to read from standard input)\n" " (failed to write to temporary file)\n" " 76 => Failed to open/create maildir\n" - " 78 => Configuration error (wrt .notmuch-config\n"); + " 78 => Configuration error (wrt .notmuch-config)\n"); g_log_set_default_handler(log_handler, NULL); @@ -338,6 +415,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); @@ -364,6 +446,7 @@ main(int argc, char **argv) g_free(maildir); if ((ret = save_database(db, mail, conf_tags)) != 0 && opt_fatal) { + g_warning("Unlinking `%s'", mail); unlink(mail); return ret; }