Merge branch 'master' of ssh://marmaro.de:443/var/git/mmh
[mmh] / uip / send.c
index bf37600..234dfb2 100644 (file)
 #include <errno.h>
 #include <signal.h>
 #include <h/signals.h>
-#include <setjmp.h>
 #include <h/mime.h>
 #include <h/tws.h>
 #include <h/utils.h>
+#include <sysexits.h>
+#include <sys/wait.h>
 
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #include <time.h>
 
 int debugsw = 0;  /* global */
-char *altmsg   = NULL;
+char *altmsg = NULL;
 char *annotext = NULL;
 char *distfile = NULL;
 
-static jmp_buf env;
-
 /* name of temp file for body content */
 static char body_file_name[MAXPATHLEN + 1];
 /* name of mhbuild composition temporary file */
@@ -42,7 +41,6 @@ static FILE *composition_file;  /* composition file pointer */
 ** static prototypes
 */
 static int sendsbr(char **, int, char *, struct stat *);
-static void armed_done(int) NORETURN;
 static void anno(struct stat *);
 static int sendaux(char **, int, char *, struct stat *);
 static int attach(char *);
@@ -50,6 +48,7 @@ static int signandenc(char *);
 static void clean_up_temporary_files(void);
 static int get_line(void);
 static void make_mime_composition_file_entry(char *);
+static char* strexit(int status);
 
 
 static struct swit switches[] = {
@@ -70,7 +69,7 @@ static struct swit switches[] = {
 int
 main(int argc, char **argv)
 {
-       int msgp = 0, nfiles = 0, distsw = 0, vecp = 1;
+       int nmsgs = 0, nfiles = 0, distsw = 0, vecp = 1;
        int msgnum, status;
        int in, out;
        int n;
@@ -96,7 +95,7 @@ main(int argc, char **argv)
                        switch (smatch(++cp, switches)) {
                        case AMBIGSW:
                                ambigsw(cp, switches);
-                               done(1);
+                               exit(1);
                        case UNKWNSW:
                                adios(NULL, "-%s unknown\n", cp);
 
@@ -105,10 +104,10 @@ main(int argc, char **argv)
                                                "%s [file] [switches]",
                                                invo_name);
                                print_help(buf, switches, 1);
-                               done(1);
+                               exit(0);
                        case VERSIONSW:
                                print_version(invo_name);
-                               done(1);
+                               exit(0);
 
                        case DEBUGSW:
                                debugsw++;
@@ -122,43 +121,47 @@ main(int argc, char **argv)
                        if (*cp == '/') {
                                files[nfiles++] = cp;
                        } else {
-                               msgs[msgp++] = cp;
+                               msgs[nmsgs++] = cp;
                        }
                }
        }
 
-       if (!msgp && !nfiles) {
-               msgs[msgp++] = seq_cur;
-       }
-       maildir = toabsdir(draftfolder);
-
-       if (chdir(maildir) == NOTOK) {
-               adios(maildir, "unable to change directory to");
+       if (!nmsgs && !nfiles) {
+               msgs[nmsgs++] = seq_cur;
        }
 
-       if (!(mp = folder_read(draftfolder))) {
-               adios(NULL, "unable to read draft folder %s", draftfolder);
-       }
-       if (mp->nummsg == 0) {
-               adios(NULL, "no messages in draft folder %s", draftfolder);
-       }
-       /* parse all the message ranges/sequences and set SELECTED */
-       for (msgnum = 0; msgnum < msgp; msgnum++) {
-               if (!m_convert(mp, msgs[msgnum])) {
-                       done(1);
+       if (nmsgs) {
+               maildir = toabsdir(draftfolder);
+               if (chdir(maildir) == NOTOK) {
+                       adios(maildir, "unable to change directory to");
                }
-       }
-       seq_setprev(mp);
+               if (!(mp = folder_read(draftfolder))) {
+                       adios(NULL, "unable to read draft folder %s",
+                                       draftfolder);
+               }
+               if (mp->nummsg == 0) {
+                       adios(NULL, "no messages in draft folder %s",
+                                       draftfolder);
+               }
+               /* parse all the msgranges/sequences and set SELECTED */
+               for (msgnum = 0; msgnum < nmsgs; msgnum++) {
+                       if (!m_convert(mp, msgs[msgnum])) {
+                               exit(1);
+                       }
+               }
+               seq_setprev(mp);
 
-       for (msgp = 0, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
-               if (is_selected(mp, msgnum)) {
-                       files[nfiles++] = getcpy(m_name(msgnum));
-                       unset_exists(mp, msgnum);
+               for (nmsgs = 0, msgnum = mp->lowsel;
+                               msgnum <= mp->hghsel; msgnum++) {
+                       if (is_selected(mp, msgnum)) {
+                               files[nfiles++] = getcpy(m_name(msgnum));
+                               unset_exists(mp, msgnum);
+                       }
                }
-       }
 
-       mp->msgflags |= SEQMOD;
-       seq_save(mp);
+               mp->msgflags |= SEQMOD;
+               seq_save(mp);
+       }
 
        if (!(cp = getenv("SIGNATURE")) || !*cp) {
                if ((cp = context_find("signature")) && *cp) {
@@ -166,9 +169,9 @@ main(int argc, char **argv)
                }
        }
 
-       for (msgnum = 0; msgnum < nfiles; msgnum++) {
-               if (stat(files[msgnum], &st) == NOTOK) {
-                       adios(files[msgnum], "unable to stat draft file");
+       for (n = 0; n < nfiles; n++) {
+               if (stat(files[n], &st) == NOTOK) {
+                       adios(files[n], "unable to stat draft file");
                }
        }
 
@@ -207,10 +210,10 @@ main(int argc, char **argv)
                close(n);
        }
 
-       for (msgnum = 0; msgnum < nfiles; msgnum++) {
-               switch (sendsbr(vec, vecp, files[msgnum], &st)) {
+       for (n = 0; n < nfiles; n++) {
+               switch (sendsbr(vec, vecp, files[n], &st)) {
                case DONE:
-                       done(++status);
+                       exit(++status);
                case NOTOK:
                        status++;  /* fall */
                case OK:
@@ -219,8 +222,7 @@ main(int argc, char **argv)
        }
 
        context_save();
-       done(status);
-       return 1;
+       return status;
 }
 
 
@@ -230,8 +232,7 @@ main(int argc, char **argv)
 static int
 sendsbr(char **vec, int vecp, char *drft, struct stat *st)
 {
-       int status;
-       char buffer[BUFSIZ];
+       int status, dupfd;
        char *original_draft;
 
        /*
@@ -282,27 +283,22 @@ sendsbr(char **vec, int vecp, char *drft, struct stat *st)
                break;
        }
 
-       done=armed_done;
-       switch (setjmp(env)) {
-       case OK:
-               status = sendaux(vec, vecp, drft, st) ? NOTOK : OK;
-               if (status == OK) {
-                       /* move original draft to +trash folder */
-                       snprintf(buffer, sizeof buffer,
-                                       "</dev/null refile -file %s +trash",
-                                       original_draft);
-                       if (system(buffer) != 0) {
-                               advise(NULL, "unable to trash the draft");
-                       }
+       if ((status = sendaux(vec, vecp, drft, st)) == OK) {
+               /* move original draft to +trash folder */
+               /* temporary close stdin, for refile not to ask */
+               dupfd = dup(0);
+               close(0);
+               if (execprogl("refile", "refile", "-file",
+                               original_draft, "+trash",
+                               (char *)NULL) != 0) {
+                       advise(NULL, "unable to trash the draft");
                }
-               break;
-
-       default:
+               dup2(dupfd, 0);
+               close(dupfd);
+       } else {
                status = DONE;
-               break;
        }
 
-       done=exit;
        if (distfile) {
                unlink(distfile);
        }
@@ -438,8 +434,8 @@ attach(char *draft_file_name)
        fclose(composition_file);
 
        /* We're ready to roll! */
-       sprintf(buf, "mhbuild %s", composition_file_name);
-       if (system(buf) != 0) {
+       if (execprogl("mhbuild", "mhbuild", composition_file_name,
+                       (char *)NULL) != 0) {
                /* some problem */
                clean_up_temporary_files();
                return (NOTOK);
@@ -459,6 +455,7 @@ signandenc(char *draft_file_name)
        char buf[BUFSIZ];
        int dosign = 0;
        int doenc = 0;
+       int ret;
 
        if (!(draft_file = fopen(draft_file_name, "r"))) {
                adios(NULL, "can't open draft file `%s'.", draft_file_name);
@@ -485,9 +482,14 @@ signandenc(char *draft_file_name)
        strcpy(composition_file_name, draft_file_name);
 
        /* We're ready to roll! */
-       sprintf(buf, "mhsign -m%s '%s'", doenc ? " -e" : "",
-                       draft_file_name);
-       if (system(buf) != 0) {
+       if (doenc) {
+               ret = execprogl("mhsign", "mhsign", "-m", "-e",
+                               draft_file_name, (char *)NULL);
+       } else {
+               ret = execprogl("mhsign", "mhsign", "-m",
+                               draft_file_name, (char *)NULL);
+       }
+       if (ret != 0) {
                /* some problem */
                return (NOTOK);
        }
@@ -612,15 +614,15 @@ sendaux(char **vec, int vecp, char *drft, struct stat *st)
 
        vec[vecp++] = drft;
        if (distfile && distout(drft, distfile, backup) == NOTOK) {
-               done(1);
+               return DONE;
        }
        vec[vecp] = NULL;
 
        switch (child_id = fork()) {
        case -1:
                /* oops -- fork error */
-               adios("fork", "unable to");
-               break;  /* NOT REACHED */
+               advise("fork", "unable to");
+               return DONE;
 
        case 0:
                /* child process -- send it */
@@ -632,13 +634,14 @@ sendaux(char **vec, int vecp, char *drft, struct stat *st)
 
        default:
                /* parent process -- wait for it */
-               if ((status = pidwait(child_id, NOTOK)) == OK) {
+               status = pidwait(child_id, NOTOK);
+               if (WIFEXITED(status) && WEXITSTATUS(status) == EX_OK) {
                        if (annotext) {
                                anno(st);
                        }
                } else {
                        /* spost failed */
-                       advise(NULL, "message not delivered to anyone");
+                       advise(NULL, "%s", strexit(status));
                        if (distfile) {
                                unlink(drft);
                                if (rename(backup, drft) == NOTOK) {
@@ -647,10 +650,10 @@ sendaux(char **vec, int vecp, char *drft, struct stat *st)
                                }
                        }
                }
-               break;
        }
 
-       return status;
+
+       return status ? NOTOK : status;
 }
 
 
@@ -660,6 +663,9 @@ anno(struct stat *st)
        struct stat st2;
        char *msgs, *folder;
        char buf[BUFSIZ];
+       char *vec[MAXARGS];
+       int vecp = 0;
+       char *cp, *dp;
 
        if (altmsg && (stat(altmsg, &st2) == NOTOK ||
                        st->st_mtime != st2.st_mtime ||
@@ -687,18 +693,45 @@ anno(struct stat *st)
                advise(NULL, "annotate as `%s': %s %s", annotext,
                                folder, msgs);
        }
-       snprintf(buf, sizeof buf, "anno -comp '%s' '+%s' %s",
-                       annotext, folder, msgs);
-       if (system(buf) != 0) {
+       vec[vecp++] = "anno";
+       vec[vecp++] = "-comp";
+       vec[vecp++] = annotext;
+       snprintf(buf, sizeof buf, "+%s", folder);
+       vec[vecp++] = buf;
+
+       while (isspace(*msgs)) {
+               msgs++;
+       }
+       for (cp=dp=msgs; *cp; cp++) {
+               if (isspace(*cp)) {
+                       while (isspace(*cp)) {
+                               *cp++ = '\0';
+                       }
+                       vec[vecp++] = dp;
+                       dp = cp;
+               }
+       }
+       vec[vecp++] = dp;
+       vec[vecp] = NULL;
+       if (execprog(*vec, vec) != 0) {
                advise(NULL, "unable to annotate");
        }
 }
 
 
-static void
-armed_done(int status)
+char*
+strexit(int status)
 {
-       longjmp(env, status ? status : NOTOK);
-
-       exit(status);
+       if (WIFSIGNALED(status)) {
+               return "spost or sendmail killed by signal";
+       }
+       if (!WIFEXITED(status)) {
+               return "message not delivered to anyone";
+       }
+       switch (WEXITSTATUS(status)) {
+       case EX_TEMPFAIL:
+               return "Temporary error, maybe the MTA has queued the message";
+       default:
+               return "message not delivered to anyone";
+       }
 }