Replaced mkinstalldirs with `mkdir -p'.
[mmh] / uip / mhbuild.c
index dc0059c..63d7be2 100644 (file)
@@ -1,9 +1,10 @@
-
 /*
- * mhbuild.c -- expand/translate MIME composition files
- *
- * $Id$
- */
+** mhbuild.c -- expand/translate MIME composition files
+**
+** This code is Copyright (c) 2002, by the authors of nmh.  See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+*/
 
 #include <h/mh.h>
 #include <fcntl.h>
 #include <h/md5.h>
 #include <errno.h>
 #include <signal.h>
-#include <zotnet/mts/mts.h>
-#include <zotnet/tws/tws.h>
+#include <h/tws.h>
 #include <h/mime.h>
 #include <h/mhparse.h>
 #include <h/mhcachesbr.h>
+#include <h/utils.h>
 
 #ifdef HAVE_SYS_WAIT_H
 # include <sys/wait.h>
 #endif
 
 static struct swit switches[] = {
-#define        CHECKSW                 0
-    { "check", 0 },
-#define        NCHECKSW                1
-    { "nocheck", 0 },
-#define        EBCDICSW                2
-    { "ebcdicsafe", 0 },
-#define        NEBCDICSW               3
-    { "noebcdicsafe", 0 },
-#define        HEADSW                  4
-    { "headers", 0 },
-#define        NHEADSW                 5
-    { "noheaders", 0 },
-#define        LISTSW                  6
-    { "list", 0 },
-#define        NLISTSW                 7
-    { "nolist", 0 },
-#define        SIZESW                  8
-    { "realsize", 0 },
-#define        NSIZESW                 9
-    { "norealsize", 0 },
-#define        RFC934SW               10
-    { "rfc934mode", 0 },
-#define        NRFC934SW              11
-    { "norfc934mode", 0 },
-#define        VERBSW                 12
-    { "verbose", 0 },
-#define        NVERBSW                13
-    { "noverbose", 0 },
-#define        RCACHESW               14
-    { "rcache policy", 0 },
-#define        WCACHESW               15
-    { "wcache policy", 0 },
-#define VERSIONSW              16
-    { "version", 0 },
-#define        HELPSW                 17
-    { "help", 4 },
-#define        DEBUGSW                18
-    { "debug", -5 },
-    { NULL, 0 }
+#define CHECKSW  0
+       { "check", 0 },
+#define NCHECKSW  1
+       { "nocheck", 0 },
+#define EBCDICSW  2
+       { "ebcdicsafe", 0 },
+#define NEBCDICSW  3
+       { "noebcdicsafe", 0 },
+#define HEADSW  4
+       { "headers", 0 },
+#define NHEADSW  5
+       { "noheaders", 0 },
+#define LISTSW  6
+       { "list", 0 },
+#define NLISTSW  7
+       { "nolist", 0 },
+#define SIZESW  8
+       { "realsize", 0 },
+#define NSIZESW  9
+       { "norealsize", 0 },
+#define RFC934SW  10
+       { "rfc934mode", 0 },
+#define NRFC934SW  11
+       { "norfc934mode", 0 },
+#define VERBSW  12
+       { "verbose", 0 },
+#define NVERBSW  13
+       { "noverbose", 0 },
+#define RCACHESW  14
+       { "rcache policy", 0 },
+#define WCACHESW  15
+       { "wcache policy", 0 },
+#define CONTENTIDSW  16
+       { "contentid", 0 },
+#define NCONTENTIDSW  17
+       { "nocontentid", 0 },
+#define VERSIONSW  18
+       { "version", 0 },
+#define HELPSW  19
+       { "help", 0 },
+#define DEBUGSW  20
+       { "debug", -5 },
+       { NULL, 0 }
 };
 
 
-extern int errno;
-
 /* mhbuildsbr.c */
-extern int checksw;
-extern char *tmp;      /* directory to place temp files */
+extern char *tmp;  /* directory to place temp files */
 
 /* mhcachesbr.c */
 extern int rcachesw;
@@ -82,303 +84,318 @@ int verbosw = 0;
 int ebcdicsw = 0;
 int listsw   = 0;
 int rfc934sw = 0;
+int contentidsw = 1;
 
 /*
- * Temporary files
- */
+** Temporary files
+*/
 static char infile[BUFSIZ];
 static int unlink_infile  = 0;
 
 static char outfile[BUFSIZ];
 static int unlink_outfile = 0;
 
+static void unlink_done(int) NORETURN;
 
 /* mhbuildsbr.c */
-CT build_mime (char *);
-int output_message (CT, char *);
+CT build_mime(char *);
+int output_message(CT, char *);
+int output_message_fp(CT, FILE *, char*);
 
 /* mhlistsbr.c */
-int list_all_messages (CT *, int, int, int, int);
+int list_all_messages(CT *, int, int, int, int);
 
 /* mhmisc.c */
-void set_endian (void);
+void set_endian(void);
 
 /* mhfree.c */
-void free_content (CT);
+void free_content(CT);
 
 
 int
-main (int argc, char **argv)
+main(int argc, char **argv)
 {
-    int sizesw = 1, headsw = 1;
-    int *icachesw;
-    char *cp, buf[BUFSIZ];
-    char buffer[BUFSIZ], *compfile = NULL;
-    char **argp, **arguments;
-    CT ct, cts[2];
-    FILE *fp;
+       int sizesw = 1, headsw = 1;
+       int *icachesw;
+       char *cp, buf[BUFSIZ];
+       char buffer[BUFSIZ], *compfile = NULL;
+       char **argp, **arguments;
+       CT ct, cts[2];
+       FILE *fp = NULL;
+       FILE *fp_out = NULL;
+
+       done = unlink_done;
 
 #ifdef LOCALE
-    setlocale(LC_ALL, "");
+       setlocale(LC_ALL, "");
 #endif
-    invo_name = r1bindex (argv[0], '/');
-
-    /* read user profile/context */
-    context_read();
-
-    arguments = getarguments (invo_name, argc, argv, 1);
-    argp = arguments;
-
-    while ((cp = *argp++)) {
-       if (cp[0] == '-' && cp[1] == '\0') {
-           if (compfile)
-               adios (NULL, "cannot specify both standard input and a file");
-           else
-               compfile = cp;
-           listsw = 0;         /* turn off -list if using standard in/out */
-           verbosw = 0;        /* turn off -verbose listings */
-           break;
+       invo_name = mhbasename(argv[0]);
+
+       /* read user profile/context */
+       context_read();
+
+       arguments = getarguments(invo_name, argc, argv, 1);
+       argp = arguments;
+
+       while ((cp = *argp++)) {
+               if (cp[0] == '-' && cp[1] == '\0') {
+                       if (compfile)
+                               adios(NULL, "cannot specify both standard input and a file");
+                       else
+                               compfile = cp;
+                       listsw = 0;  /* turn off -list if using std in/out */
+                       verbosw = 0;  /* turn off -verbose listings */
+                       break;
+               }
+               if (*cp == '-') {
+                       switch (smatch(++cp, switches)) {
+                       case AMBIGSW:
+                               ambigsw(cp, switches);
+                               done(1);
+                       case UNKWNSW:
+                               adios(NULL, "-%s unknown", cp);
+
+                       case HELPSW:
+                               snprintf(buf, sizeof(buf), "%s [switches] file", invo_name);
+                               print_help(buf, switches, 1);
+                               done(1);
+                       case VERSIONSW:
+                               print_version(invo_name);
+                               done(1);
+
+                       case RCACHESW:
+                               icachesw = &rcachesw;
+                               goto do_cache;
+                       case WCACHESW:
+                               icachesw = &wcachesw;
+                       do_cache: ;
+                               if (!(cp = *argp++) || *cp == '-')
+                                       adios(NULL, "missing argument to %s",
+                                                       argp[-2]);
+                               switch (*icachesw = smatch(cp, caches)) {
+                               case AMBIGSW:
+                                       ambigsw(cp, caches);
+                                       done(1);
+                               case UNKWNSW:
+                                       adios(NULL, "%s unknown", cp);
+                               default:
+                                       break;
+                               }
+                               continue;
+
+                       case CHECKSW:
+                               checksw++;
+                               continue;
+                       case NCHECKSW:
+                               checksw = 0;
+                               continue;
+
+                       case EBCDICSW:
+                               ebcdicsw++;
+                               continue;
+                       case NEBCDICSW:
+                               ebcdicsw = 0;
+                               continue;
+
+                       case HEADSW:
+                               headsw++;
+                               continue;
+                       case NHEADSW:
+                               headsw = 0;
+                               continue;
+
+                       case LISTSW:
+                               listsw++;
+                               continue;
+                       case NLISTSW:
+                               listsw = 0;
+                               continue;
+
+                       case RFC934SW:
+                               rfc934sw++;
+                               continue;
+                       case NRFC934SW:
+                               rfc934sw = 0;
+                               continue;
+
+                       case SIZESW:
+                               sizesw++;
+                               continue;
+                       case NSIZESW:
+                               sizesw = 0;
+                               continue;
+
+                       case CONTENTIDSW:
+                               contentidsw = 1;
+                               continue;
+                       case NCONTENTIDSW:
+                               contentidsw = 0;
+                               continue;
+
+                       case VERBSW:
+                               verbosw++;
+                               continue;
+                       case NVERBSW:
+                               verbosw = 0;
+                               continue;
+                       case DEBUGSW:
+                               debugsw = 1;
+                               continue;
+                       }
+               }
+               if (compfile)
+                       adios(NULL, "only one composition file allowed");
+               else
+                       compfile = cp;
        }
-       if (*cp == '-') {
-           switch (smatch (++cp, switches)) {
-           case AMBIGSW: 
-               ambigsw (cp, switches);
-               done (1);
-           case UNKWNSW: 
-               adios (NULL, "-%s unknown", cp);
-
-           case HELPSW: 
-               snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
-               print_help (buf, switches, 1);
-               done (1);
-           case VERSIONSW:
-               print_version(invo_name);
-               done (1);
-
-           case RCACHESW:
-               icachesw = &rcachesw;
-               goto do_cache;
-           case WCACHESW:
-               icachesw = &wcachesw;
-           do_cache: ;
-               if (!(cp = *argp++) || *cp == '-')
-                   adios (NULL, "missing argument to %s", argp[-2]);
-               switch (*icachesw = smatch (cp, caches)) {
-               case AMBIGSW:
-                   ambigsw (cp, caches);
-                   done (1);
-               case UNKWNSW:
-                   adios (NULL, "%s unknown", cp);
-               default:
-                   break;
+
+       set_endian();
+
+       if ((cp = getenv("MM_NOASK")) && strcmp(cp, "1")==0)
+               listsw  = 0;
+
+       /*
+       ** Check if we've specified an additional profile
+       */
+       if ((cp = getenv("MHBUILD"))) {
+               if ((fp = fopen(cp, "r"))) {
+                       readconfig((struct node **) 0, fp, cp, 0);
+                       fclose(fp);
+               } else {
+                       admonish("", "unable to read $MHBUILD profile (%s)",
+                                       cp);
                }
-               continue;
-
-           case CHECKSW:
-               checksw++;
-               continue;
-           case NCHECKSW:
-               checksw = 0;
-               continue;
-
-           case EBCDICSW:
-               ebcdicsw++;
-               continue;
-           case NEBCDICSW:
-               ebcdicsw = 0;
-               continue;
-
-           case HEADSW:
-               headsw++;
-               continue;
-           case NHEADSW:
-               headsw = 0;
-               continue;
-
-           case LISTSW:
-               listsw++;
-               continue;
-           case NLISTSW:
-               listsw = 0;
-               continue;
-
-           case RFC934SW:
-               rfc934sw++;
-               continue;
-           case NRFC934SW:
-               rfc934sw = 0;
-               continue;
-
-           case SIZESW:
-               sizesw++;
-               continue;
-           case NSIZESW:
-               sizesw = 0;
-               continue;
-
-           case VERBSW: 
-               verbosw++;
-               continue;
-           case NVERBSW: 
-               verbosw = 0;
-               continue;
-           case DEBUGSW:
-               debugsw = 1;
-               continue;
-           }
        }
-       if (compfile)
-           adios (NULL, "only one composition file allowed");
+
+       /*
+       ** Read the standard profile setup
+       */
+       if ((fp = fopen(cp = etcpath("mhn.defaults"), "r"))) {
+               readconfig((struct node **) 0, fp, cp, 0);
+               fclose(fp);
+       }
+
+       /* Check for public cache location */
+       if ((cache_public = context_find(nmhcache)) && *cache_public != '/')
+               cache_public = NULL;
+
+       /* Check for private cache location */
+       if (!(cache_private = context_find(nmhprivcache)))
+               cache_private = ".cache";
+       cache_private = getcpy(toabsdir(cache_private));
+
+       /*
+       ** Check for storage directory.  If defined, we
+       ** will store temporary files there.  Else we
+       ** store them in standard nmh directory.
+       */
+       if ((cp = context_find(nmhstorage)) && *cp)
+               tmp = concat(cp, "/", invo_name, NULL);
        else
-           compfile = cp;
-    }
-
-    set_endian ();
-
-    if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1"))
-       listsw  = 0;
-
-    /*
-     * Check if we've specified an additional profile
-     */
-    if ((cp = getenv ("MHBUILD"))) {
-       if ((fp = fopen (cp, "r"))) {
-           readconfig ((struct node **) 0, fp, cp, 0);
-           fclose (fp);
-       } else {
-           admonish ("", "unable to read $MHBUILD profile (%s)", cp);
+               tmp = getcpy(toabsdir(invo_name));
+
+       /* Check if we have a file to process */
+       if (!compfile)
+               adios(NULL, "need to specify a %s composition file",
+                               invo_name);
+
+       /*
+       ** Process the composition file from standard input.
+       */
+       if (compfile[0] == '-' && compfile[1] == '\0') {
+               /* copy standard input to temporary file */
+               strncpy(infile, m_mktemp(invo_name, NULL, &fp),
+                               sizeof(infile));
+               while (fgets(buffer, BUFSIZ, stdin))
+                       fputs(buffer, fp);
+               fclose(fp);
+               unlink_infile = 1;
+
+               /* build the content structures for MIME message */
+               ct = build_mime(infile);
+               cts[0] = ct;
+               cts[1] = NULL;
+
+               /* output MIME message to this temporary file */
+               strncpy(outfile, m_mktemp(invo_name, NULL, &fp_out),
+                               sizeof(outfile));
+               unlink_outfile = 1;
+
+               /* output the message */
+               output_message_fp(ct, fp_out, outfile);
+               fclose(fp_out);
+
+               /* output the temp file to standard output */
+               if ((fp = fopen(outfile, "r")) == NULL)
+                       adios(outfile, "unable to open");
+               while (fgets(buffer, BUFSIZ, fp))
+                       fputs(buffer, stdout);
+               fclose(fp);
+
+               unlink(infile);
+               unlink_infile = 0;
+
+               unlink(outfile);
+               unlink_outfile = 0;
+
+               free_content(ct);
+               done(0);
        }
-    }
-
-    /*
-     * Read the standard profile setup
-     */
-    if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) {
-       readconfig ((struct node **) 0, fp, cp, 0);
-       fclose (fp);
-    }
-
-    /* Check for public cache location */
-    if ((cache_public = context_find (nmhcache)) && *cache_public != '/')
-       cache_public = NULL;
-
-    /* Check for private cache location */
-    if (!(cache_private = context_find (nmhprivcache)))
-       cache_private = ".cache";
-    cache_private = getcpy (m_maildir (cache_private));
-
-    /*
-     * Check for storage directory.  If defined, we
-     * will store temporary files there.  Else we
-     * store them in standard nmh directory.
-     */
-    if ((cp = context_find (nmhstorage)) && *cp)
-       tmp = concat (cp, "/", invo_name, NULL);
-    else
-       tmp = add (m_maildir (invo_name), NULL);
-
-    if (!context_find ("path"))
-       free (path ("./", TFOLDER));
-
-    /* Check if we have a file to process */
-    if (!compfile)
-       adios (NULL, "need to specify a %s composition file", invo_name);
-
-    /*
-     * Process the composition file from standard input.
-     */
-    if (compfile[0] == '-' && compfile[1] == '\0') {
-
-       /* copy standard input to temporary file */
-       strncpy (infile, m_scratch ("", invo_name), sizeof(infile));
-       if ((fp = fopen (infile, "w")) == NULL)
-           adios (infile, "unable to open");
-       while (fgets (buffer, BUFSIZ, stdin))
-           fputs (buffer, fp);
-       fclose (fp);
-       unlink_infile = 1;
+
+       /*
+       ** Process the composition file from a file.
+       */
 
        /* build the content structures for MIME message */
-       ct = build_mime (infile);
+       ct = build_mime(compfile);
        cts[0] = ct;
        cts[1] = NULL;
 
        /* output MIME message to this temporary file */
-       strncpy (outfile, m_scratch ("", invo_name), sizeof(outfile));
+       strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out),
+                       sizeof(outfile));
        unlink_outfile = 1;
 
        /* output the message */
-       output_message (ct, outfile);
-
-       /* output the temp file to standard output */
-       if ((fp = fopen (outfile, "r")) == NULL)
-           adios (outfile, "unable to open");
-       while (fgets (buffer, BUFSIZ, fp))
-           fputs (buffer, stdout);
-       fclose (fp);
-
-       unlink (infile);
-       unlink_infile = 0;
+       output_message_fp(ct, fp_out, outfile);
+       fclose(fp_out);
+
+       /*
+       ** List the message info
+       */
+       if (listsw)
+               list_all_messages(cts, headsw, sizesw, verbosw, debugsw);
+
+       /* Rename composition draft */
+       snprintf(buffer, sizeof(buffer), "%s.orig", m_backup(compfile));
+       if (rename(compfile, buffer) == NOTOK) {
+               adios(compfile, "unable to rename comp draft %s to", buffer);
+       }
 
-       unlink (outfile);
+       /* Rename output file to take its place */
+       if (rename(outfile, compfile) == NOTOK) {
+               advise(outfile, "unable to rename output %s to", compfile);
+               rename(buffer, compfile);
+               done(1);
+       }
        unlink_outfile = 0;
 
-       free_content (ct);
-       done (0);
-    }
-
-    /*
-     * Process the composition file from a file.
-     */
-
-    /* build the content structures for MIME message */
-    ct = build_mime (compfile);
-    cts[0] = ct;
-    cts[1] = NULL;
-
-    /* output MIME message to this temporary file */
-    strncpy (outfile, m_scratch (compfile, invo_name), sizeof(outfile));
-    unlink_outfile = 1;
-
-    /* output the message */
-    output_message (ct, outfile);
-
-    /*
-     * List the message info
-     */
-    if (listsw)
-       list_all_messages (cts, headsw, sizesw, verbosw, debugsw);
-
-    /* Rename composition draft */
-    snprintf (buffer, sizeof(buffer), "%s.orig", m_backup (compfile));
-    if (rename (compfile, buffer) == NOTOK)
-       adios (compfile, "unable to rename %s to", buffer);
-
-    /* Rename output file to take its place */
-    if (rename (outfile, compfile) == NOTOK) {
-       advise (outfile, "unable to rename %s to", compfile);
-       rename (buffer, compfile);
-       done (1);
-    }
-    unlink_outfile = 0;
-
-    free_content (ct);
-    return done (0);
+       free_content(ct);
+       done(0);
+       return 1;
 }
 
 
-int
-done (int status)
+static void
+unlink_done(int status)
 {
-    /*
-     * Check if we need to remove stray
-     * temporary files.
-     */
-    if (unlink_infile)
-       unlink (infile);
-    if (unlink_outfile)
-       unlink (outfile);
-
-    exit (status);
-    return 1;  /* dead code to satisfy the compiler */
+       /*
+       ** Check if we need to remove stray temporary files.
+       */
+       if (unlink_infile)
+               unlink(infile);
+       if (unlink_outfile)
+               unlink(outfile);
+
+       exit(status);
 }