Use execprog() instead of system() ... partly transition
[mmh] / uip / send.c
index c454f76..3ca6772 100644 (file)
@@ -15,6 +15,8 @@
 #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>
@@ -22,6 +24,7 @@
 #include <time.h>
 
 int debugsw = 0;  /* global */
+int verbosesw = 0;
 char *altmsg   = NULL;
 char *annotext = NULL;
 char *distfile = NULL;
@@ -46,23 +49,23 @@ static void armed_done(int) NORETURN;
 static void anno(struct stat *);
 static int sendaux(char **, int, char *, struct stat *);
 static int attach(char *);
+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[] = {
-#define ALIASW  0
-       { "alias aliasfile", 0 },
-#define DEBUGSW  1
+#define DEBUGSW  0
        { "debug", -5 },
-#define VERBSW  2
+#define VERBSW  1
        { "verbose", 0 },
-#define NVERBSW  3
+#define NVERBSW  2
        { "noverbose", 2 },
-#define VERSIONSW  4
+#define VERSIONSW  3
        { "Version", 0 },
-#define HELPSW  5
+#define HELPSW  4
        { "help", 0 },
        { NULL, 0 }
 };
@@ -71,12 +74,12 @@ 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;
        char *cp, *maildir = NULL;
-       char buf[BUFSIZ], **ap, **argp, **arguments;
+       char buf[BUFSIZ], **argp, **arguments;
        char *msgs[MAXARGS], *vec[MAXARGS];
        char *files[MAXARGS];
        struct msgs *mp;
@@ -92,9 +95,6 @@ main(int argc, char **argv)
        arguments = getarguments(invo_name, argc, argv, 1);
        argp = arguments;
 
-       vec[vecp++] = "-library";
-       vec[vecp++] = getcpy(toabsdir("+"));
-
        while ((cp = *argp++)) {
                if (*cp == '-') {
                        switch (smatch(++cp, switches)) {
@@ -118,71 +118,57 @@ main(int argc, char **argv)
                                debugsw++;
                                /* fall */
                        case VERBSW:
+                               verbosesw += 2;
                        case NVERBSW:
+                               verbosesw--;
                                vec[vecp++] = --cp;
                                continue;
-
-                       case ALIASW:
-                               vec[vecp++] = --cp;
-                               if (!(cp = *argp++) || *cp == '-') {
-                                       adios(NULL, "missing argument to %s",
-                                                       argp[-2]);
-                               }
-                               vec[vecp++] = cp;
-                               continue;
-
                        }
                } else {
                        if (*cp == '/') {
                                files[nfiles++] = cp;
                        } else {
-                               msgs[msgp++] = cp;
+                               msgs[nmsgs++] = cp;
                        }
                }
        }
 
-       /* check for "Aliasfile:" profile entry */
-       if ((cp = context_find("Aliasfile"))) {
-               char *dp = NULL;
-
-               for (ap=brkstring(dp=getcpy(cp), " ", "\n"); ap && *ap; ap++) {
-                       vec[vecp++] = "-alias";
-                       vec[vecp++] = getcpy(etcpath(*ap));
-               }
-       }
-
-       if (!msgp && !nfiles) {
-               msgs[msgp++] = seq_cur;
+       if (!nmsgs && !nfiles) {
+               msgs[nmsgs++] = seq_cur;
        }
-       maildir = toabsdir(draftfolder);
 
-       if (chdir(maildir) == NOTOK) {
-               adios(maildir, "unable to change directory to");
-       }
-
-       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])) {
+                               done(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) {
@@ -190,9 +176,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");
                }
        }
 
@@ -231,8 +217,8 @@ 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);
                case NOTOK:
@@ -257,7 +243,6 @@ sendsbr(char **vec, int vecp, char *drft, struct stat *st)
        int status;
        char buffer[BUFSIZ];
        char *original_draft;
-       char *p;  /* string pointer for building file name */
 
        /*
        ** Save the original name of the draft file.  The name of the
@@ -287,16 +272,37 @@ sendsbr(char **vec, int vecp, char *drft, struct stat *st)
                break;
        }
 
+       /*
+       ** Sign and encrypt the message as needed.
+       ** Use the mhbuild composition file for the draft if there was
+       ** a successful conversion because that now contains the MIME
+       ** message.  A nice side effect of this is that it leaves the
+       ** original draft file untouched so that it can be retrieved
+       ** and modified if desired.
+       */
+       switch (signandenc(drft)) {
+       case OK:
+               drft = composition_file_name;
+               break;
+
+       case NOTOK:
+               return (NOTOK);
+
+       case DONE:
+               break;
+       }
+
        done=armed_done;
        switch (setjmp(env)) {
        case OK:
                status = sendaux(vec, vecp, drft, st) ? NOTOK : OK;
-               /* rename the original draft */
                if (status == OK) {
-                       strncpy(buffer, m_backup(original_draft),
-                                       sizeof(buffer));
-                       if (rename(original_draft, buffer) == NOTOK) {
-                               advise(buffer, "unable to rename %s to", drft);
+                       /* 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");
                        }
                }
                break;
@@ -311,31 +317,9 @@ sendsbr(char **vec, int vecp, char *drft, struct stat *st)
                unlink(distfile);
        }
 
-       /*
-       ** Get rid of any temporary files that we created for attachments.
-       ** Also get rid of the renamed composition file that mhbuild
-       ** leaves as a turd.  It looks confusing, but we use the body
-       ** file name to help build the renamed composition file name.
-       */
+       /* Get rid of temporary files that we created for attachments. */
        if (drft == composition_file_name) {
                clean_up_temporary_files();
-
-               if (strlen(composition_file_name) >=
-                               sizeof (composition_file_name) - 6) {
-                       advise(NULL, "unable to remove original composition file.");
-               } else {
-                       if (!(p = strrchr(composition_file_name, '/'))) {
-                               p = composition_file_name;
-                       } else {
-                               p++;
-                       }
-                       strcpy(body_file_name, p);
-                       *p++ = ',';
-                       strcpy(p, body_file_name);
-                       strcat(p, ".orig");
-
-                       unlink(composition_file_name);
-               }
        }
 
        return status;
@@ -451,9 +435,7 @@ attach(char *draft_file_name)
        while (get_line() != EOF && *field && *field != '-') {
                if (strncasecmp(field, attach_hdr, length) == 0 &&
                                field[length] == ':') {
-                       for (p = field+length+1; *p==' ' || *p=='\t'; p++) {
-                               continue;
-                       }
+                       p = trim(field+length+1);
                        if (*p == '+') {
                                /* forwarded message */
                                fprintf(composition_file, "#forw [forwarded message(s)] %s\n", p);
@@ -466,12 +448,70 @@ 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);
        }
+       /* Remove the automatically created backup of mhbuild. */
+       snprintf(buf, sizeof buf, "%s.orig", composition_file_name);
+       if (unlink(buf) == -1) {
+               advise(NULL, "unable to remove original composition file.");
+       }
+
+       return (OK);
+}
+
+static int
+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);
+       }
+
+       /* We'll grow the buffer as needed. */
+       field = (char *)mh_xmalloc(field_size = 256);
+
+       /* Scan the draft file for an attachment header field name. */
+       while (get_line() != EOF && *field != '\0' && *field != '-') {
+               if (strncasecmp(field, sign_hdr, strlen(sign_hdr))==0 &&
+                               field[strlen(sign_hdr)] == ':') {
+                       dosign = 1;
+               }
+               if (strncasecmp(field, enc_hdr, strlen(enc_hdr))==0 &&
+                               field[strlen(enc_hdr)] == ':') {
+                       doenc = 1;
+               }
+       }
+       if (!dosign && !doenc) {
+               return DONE;
+       }
+
+       strcpy(composition_file_name, draft_file_name);
+
+       /* We're ready to roll! */
+       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);
+       }
+       /* Remove the automatically created backup of mhsign. */
+       snprintf(buf, sizeof buf, "%s.orig", draft_file_name);
+       if (unlink(buf) == -1) {
+               advise(NULL, "unable to remove original draft file.");
+       }
 
        return (OK);
 }
@@ -523,6 +563,7 @@ make_mime_composition_file_entry(char *file_name)
        char content_type[BUFSIZ];
        char cmdbuf[BUFSIZ];
        char *cmd = mimetypequeryproc;
+       int semicolon = 0;
 
        for (np = m_defs; np; np = np->n_next) {
                if (strcasecmp(np->n_name, mimetypequery)==0) {
@@ -553,11 +594,23 @@ make_mime_composition_file_entry(char *file_name)
                adios(NULL, "unable to access file `%s'", file_name);
        }
 
-       cp = (!(cp = strrchr(file_name, '/'))) ? file_name : cp + 1;
-       fprintf(composition_file, "#%s; name=\"%s\" <> [%s] {attachment}",
-                       content_type, cp, cp);
+       /* Check for broken file(1). See man page mh-profile(5). */
+       for (cp=content_type; *cp; cp++) {
+               if (isspace(*cp)) {
+                       if (!semicolon) {
+                               adios(NULL, "Sorry, your Mime-Type-Query command (%s) is broken.\n\tThe output misses a semicolon before the whitespace.\n\tOutput was: %s", cmd, content_type);
+                       }
+               } else if (*cp == ';') {
+                       semicolon = 1;
+               } else {
+                       semicolon = 0;
+               }
+       }
 
-       fprintf(composition_file, " %s\n", file_name);
+       cp = (!(cp = strrchr(file_name, '/'))) ? file_name : cp + 1;
+       fprintf(composition_file,
+                       "#%s; name=\"%s\" <> [%s] {attachment} %s\n",
+                       content_type, cp, cp, file_name);
 
        return;
 }
@@ -595,13 +648,17 @@ 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");
+               }
+               else {
+                       advise(NULL, "%s", strexit(status));
+                       if (verbosesw <= 0) {
+                               advise(NULL, "Try using -v to get better output");
+                       }
                        if (distfile) {
                                unlink(drft);
                                if (rename(backup, drft) == NOTOK) {
@@ -610,9 +667,9 @@ sendaux(char **vec, int vecp, char *drft, struct stat *st)
                                }
                        }
                }
-               break;
        }
 
+
        return status;
 }
 
@@ -658,6 +715,24 @@ anno(struct stat *st)
 }
 
 
+char*
+strexit(int status)
+{
+       if (WIFSIGNALED(status)) {
+               return "spost or sendmail killed by signal";
+       }
+       if (!WIFEXITED(status)) {
+               return "sendmail stopt for unknown reasen, message not deliverd to anyone";
+       }
+       switch (WEXITSTATUS(status)) {
+               case EX_TEMPFAIL:
+                       return "Temporary error, maby the MTA hase queued the Mail";
+               default:
+                       return "sendmail stopt for unknown reasen, message not deliverd to anyone";
+       }
+}
+
+
 static void
 armed_done(int status)
 {