add free_field as standard for struct field
[mmh] / uip / send.c
index ed6b08d..df81340 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>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <locale.h>
 
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
 #include <time.h>
 
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
 int debugsw = 0;  /* global */
 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 */
@@ -44,7 +49,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 *);
@@ -99,19 +103,19 @@ main(int argc, char **argv)
                        switch (smatch(++cp, switches)) {
                        case AMBIGSW:
                                ambigsw(cp, switches);
-                               done(1);
+                               exit(EX_USAGE);
                        case UNKWNSW:
-                               adios(NULL, "-%s unknown\n", cp);
+                               adios(EX_USAGE, NULL, "-%s unknown\n", cp);
 
                        case HELPSW:
                                snprintf(buf, sizeof(buf),
                                                "%s [file] [switches]",
                                                invo_name);
                                print_help(buf, switches, 1);
-                               done(1);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
                        case VERSIONSW:
                                print_version(invo_name);
-                               done(1);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
 
                        case DEBUGSW:
                                debugsw++;
@@ -137,20 +141,20 @@ main(int argc, char **argv)
        if (nmsgs) {
                maildir = toabsdir(draftfolder);
                if (chdir(maildir) == NOTOK) {
-                       adios(maildir, "unable to change directory to");
+                       adios(EX_OSERR, maildir, "unable to change directory to");
                }
                if (!(mp = folder_read(draftfolder))) {
-                       adios(NULL, "unable to read draft folder %s",
+                       adios(EX_IOERR, NULL, "unable to read draft folder %s",
                                        draftfolder);
                }
                if (mp->nummsg == 0) {
-                       adios(NULL, "no messages in draft folder %s",
+                       adios(EX_DATAERR, 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);
+                               exit(EX_USAGE);
                        }
                }
                seq_setprev(mp);
@@ -175,7 +179,7 @@ main(int argc, char **argv)
 
        for (n = 0; n < nfiles; n++) {
                if (stat(files[n], &st) == NOTOK) {
-                       adios(files[n], "unable to stat draft file");
+                       adios(EX_IOERR, files[n], "unable to stat draft file");
                }
        }
 
@@ -189,12 +193,12 @@ main(int argc, char **argv)
        if ((cp = getenv("mhdist")) && *cp && (distsw = atoi(cp)) && altmsg) {
                vec[vecp++] = "-dist";
                if ((in = open(altmsg, O_RDONLY)) == NOTOK) {
-                       adios(altmsg, "unable to open for reading");
+                       adios(EX_IOERR, altmsg, "unable to open for reading");
                }
                fstat(in, &st2);
                distfile = getcpy(m_mktemp2(NULL, invo_name, NULL, NULL));
                if ((out = creat(distfile, (int)st2.st_mode & 0777))==NOTOK) {
-                       adios(distfile, "unable to open for writing");
+                       adios(EX_IOERR, distfile, "unable to open for writing");
                }
                cpydata(in, out, altmsg, distfile);
                close(in);
@@ -217,7 +221,7 @@ main(int argc, char **argv)
        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:
@@ -226,8 +230,7 @@ main(int argc, char **argv)
        }
 
        context_save();
-       done(status);
-       return 1;
+       return status;
 }
 
 
@@ -288,31 +291,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 */
-                       /* 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");
-                       }
-                       dup2(dupfd, 0);
-                       close(dupfd);
+       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);
        }
@@ -326,18 +320,31 @@ sendsbr(char **vec, int vecp, char *drft, struct stat *st)
 }
 
 static int
+contains_non_ascii(char *str)
+{
+       unsigned char *cp;
+
+       for (cp = str; *cp; cp++) {
+               if (*cp > 127) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int
 attach(char *draft_file_name)
 {
        char buf[MAXPATHLEN + 6];
        int c;
        int has_attachment;
-       int has_body;
-       int non_ascii; /* msg body contains non-ASCII chars */
+       int has_body = 0;
+       int non_ascii = 0; /* msg body or hdr contains non-ASCII chars */
        int length;  /* length of attachment header field name */
        char *p;
 
        if (!(draft_file = fopen(draft_file_name, "r"))) {
-               adios(NULL, "can't open draft file `%s'.", draft_file_name);
+               adios(EX_IOERR, NULL, "can't open draft file `%s'.", draft_file_name);
        }
 
        /* We'll grow the buffer as needed. */
@@ -353,6 +360,9 @@ attach(char *draft_file_name)
                                field[length] == ':') {
                        has_attachment = 1;
                }
+               if (contains_non_ascii(field)) {
+                       non_ascii = 1;
+               }
        }
 
        /*
@@ -361,16 +371,14 @@ attach(char *draft_file_name)
        ** Check if body contains at least one non-blank (= not empty)
        ** and if it contains any non-ASCII chars (= need MIME).
        */
-       has_body = 0;
-       non_ascii = 0;
        while (get_line() != EOF) {
-               for (p = field; *p != '\0'; p++) {
-                       if (*p != ' ' && *p != '\t') {
+               if (contains_non_ascii(field)) {
+                       non_ascii = 1;
+               }
+               for (p = field; *p; p++) {
+                       if (isgraph(*p)) {
                                has_body = 1;
                        }
-                       if (*p > 127 || *p < 0) {
-                               non_ascii = 1;
-                       }
                }
                if (has_body && non_ascii) {
                        break;  /* that's been already enough information */
@@ -401,7 +409,7 @@ attach(char *draft_file_name)
 
        if ((has_body && !body_file) || !composition_file) {
                clean_up_temporary_files();
-               adios(NULL, "unable to open all of the temporary files.");
+               adios(EX_IOERR, NULL, "unable to open all of the temporary files.");
        }
 
        /* Copy non-attachment header fields to the temp composition file. */
@@ -472,7 +480,7 @@ signandenc(char *draft_file_name)
        int ret;
 
        if (!(draft_file = fopen(draft_file_name, "r"))) {
-               adios(NULL, "can't open draft file `%s'.", draft_file_name);
+               adios(EX_IOERR, NULL, "can't open draft file `%s'.", draft_file_name);
        }
 
        /* We'll grow the buffer as needed. */
@@ -575,7 +583,7 @@ make_mime_composition_file_entry(char *file_name)
 
        if (!(fp = popen(cmdbuf, "r"))) {
                clean_up_temporary_files();
-               adios(NULL, "unable to determine content type with `%s'",
+               adios(EX_IOERR, NULL, "unable to determine content type with `%s'",
                                cmdbuf);
        }
        if (fgets(content_type, sizeof content_type, fp) &&
@@ -591,14 +599,14 @@ make_mime_composition_file_entry(char *file_name)
        /* TODO: don't use access(2) because it checks for ruid, not euid */
        if (access(file_name, R_OK) != 0) {
                clean_up_temporary_files();
-               adios(NULL, "unable to access file `%s'", file_name);
+               adios(EX_IOERR, NULL, "unable to access file `%s'", file_name);
        }
 
        /* 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);
+                               adios(EX_SOFTWARE, 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;
@@ -628,22 +636,22 @@ 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 */
                execvp(*vec, vec);
                fprintf(stderr, "unable to exec ");
                perror(*vec);
-               _exit(-1);
+               _exit(EX_OSERR);
                break;  /* NOT REACHED */
 
        default:
@@ -667,7 +675,7 @@ sendaux(char **vec, int vecp, char *drft, struct stat *st)
        }
 
 
-       return status;
+       return status ? NOTOK : status;
 }
 
 
@@ -749,12 +757,3 @@ strexit(int status)
                return "message not delivered to anyone";
        }
 }
-
-
-static void
-armed_done(int status)
-{
-       longjmp(env, status ? status : NOTOK);
-
-       exit(status);
-}