X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/0bfb53a23531bea3aaeadcd1a6f6c372eef96612..ec173fd2c:/uip/mhbuild.c?ds=sidebyside diff --git a/uip/mhbuild.c b/uip/mhbuild.c index 893ef8d6..1ef84211 100644 --- a/uip/mhbuild.c +++ b/uip/mhbuild.c @@ -1,26 +1,38 @@ - -/* - * mhbuild.c -- expand/translate MIME composition files +/* 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 +#include "h/mh.h" +#include "sbr/getarguments.h" +#include "sbr/smatch.h" +#include "sbr/m_backup.h" +#include "sbr/context_find.h" +#include "sbr/readconfig.h" +#include "sbr/ambigsw.h" +#include "sbr/path.h" +#include "sbr/print_version.h" +#include "sbr/print_help.h" +#include "sbr/error.h" #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "h/md5.h" +#include "h/mts.h" +#include "h/tws.h" +#include "h/mime.h" +#include "h/mhparse.h" +#include "h/mhcachesbr.h" +#include "h/done.h" +#include "h/utils.h" +#include "sbr/m_maildir.h" +#include "sbr/m_mktemp.h" +#include "mhfree.h" +#include "mhoutsbr.h" #define MHBUILD_SWITCHES \ + X("auto", 0, AUTOSW) \ + X("noauto", 0, NAUTOSW) \ X("check", 0, CHECKSW) \ X("nocheck", 0, NCHECKSW) \ X("directives", 0, DIRECTIVES) \ @@ -35,13 +47,19 @@ X("norfc934mode", 0, NRFC934SW) \ X("verbose", 0, VERBSW) \ X("noverbose", 0, NVERBSW) \ + X("disposition", 0, DISPOSW) \ + X("nodisposition", 0, NDISPOSW) \ X("rcache policy", 0, RCACHESW) \ X("wcache policy", 0, WCACHESW) \ X("contentid", 0, CONTENTIDSW) \ X("nocontentid", 0, NCONTENTIDSW) \ + X("headerencoding encoding-algorithm", 0, HEADERENCSW) \ + X("autoheaderencoding", 0, AUTOHEADERENCSW) \ + X("maxunencoded", 0, MAXUNENCSW) \ X("version", 0, VERSIONSW) \ X("help", 0, HELPSW) \ X("debug", -5, DEBUGSW) \ + X("dist", 0, DISTSW) \ #define X(sw, minchars, id) id, DEFINE_SWITCH_ENUM(MHBUILD); @@ -51,50 +69,44 @@ DEFINE_SWITCH_ENUM(MHBUILD); DEFINE_SWITCH_ARRAY(MHBUILD, switches); #undef X +/* utf-8 is for Email Address Internationalization, using SMTPUTF8. */ +#define MIMEENCODING_SWITCHES \ + X("base64", 0, BASE64SW) \ + X("quoted-printable", 0, QUOTEDPRINTSW) \ + X("utf-8", 0, UTF8SW) \ -/* mhbuildsbr.c */ -extern char *tmp; /* directory to place temp files */ +#define X(sw, minchars, id) id, +DEFINE_SWITCH_ENUM(MIMEENCODING); +#undef X -/* mhcachesbr.c */ -extern int rcachesw; -extern int wcachesw; -extern char *cache_public; -extern char *cache_private; +#define X(sw, minchars, id) { sw, minchars, id }, +DEFINE_SWITCH_ARRAY(MIMEENCODING, encodingswitches); +#undef X int debugsw = 0; -int verbosw = 0; -int listsw = 0; -int rfc934sw = 0; -int contentidsw = 1; +bool listsw; +bool rfc934sw; +bool contentidsw = true; /* * 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); -int output_message (CT, char *); -int output_message_fp (CT, FILE *, char*); - -/* mhlistsbr.c */ -int list_all_messages (CT *, int, int, int, int); - -/* mhfree.c */ -void free_content (CT); int main (int argc, char **argv) { - int sizesw = 1, headsw = 1, directives = 1; + bool sizesw = true; + bool headsw = true; + bool directives = true; + bool autobuild = false; + bool dist = false; + bool verbosw = false; + bool dispo = false; + size_t maxunencoded = MAXTEXTPERLN; int *icachesw; char *cp, buf[BUFSIZ]; char buffer[BUFSIZ], *compfile = NULL; @@ -102,16 +114,10 @@ main (int argc, char **argv) CT ct, cts[2]; FILE *fp = NULL; FILE *fp_out = NULL; + int header_encoding = CE_UNKNOWN; + size_t n; - done=unlink_done; - -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); + if (nmh_init(argv[0], true, false)) { return 1; } arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -119,11 +125,10 @@ main (int argc, char **argv) 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 */ + die("cannot specify both standard input and a file"); + compfile = cp; + listsw = false; /* turn off -list if using standard in/out */ + verbosw = false; /* turn off -verbose listings */ break; } if (*cp == '-') { @@ -132,7 +137,7 @@ main (int argc, char **argv) ambigsw (cp, switches); done (1); case UNKWNSW: - adios (NULL, "-%s unknown", cp); + die("-%s unknown", cp); case HELPSW: snprintf (buf, sizeof(buf), "%s [switches] file", invo_name); @@ -142,6 +147,20 @@ main (int argc, char **argv) print_version(invo_name); done (0); + case AUTOSW: + /* -auto implies -nodirectives */ + autobuild = true; + directives = false; + continue; + case NAUTOSW: + /* + * We're turning directives back on since this is likely here + * to override a profile entry + */ + autobuild = false; + directives = true; + continue; + case RCACHESW: icachesw = &rcachesw; goto do_cache; @@ -149,13 +168,13 @@ main (int argc, char **argv) icachesw = &wcachesw; do_cache: ; if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - switch (*icachesw = smatch (cp, caches)) { + die("missing argument to %s", argp[-2]); + switch (*icachesw = smatch (cp, cache_policy)) { case AMBIGSW: - ambigsw (cp, caches); + ambigsw (cp, cache_policy); done (1); case UNKWNSW: - adios (NULL, "%s unknown", cp); + die("%s unknown", cp); default: break; } @@ -169,62 +188,109 @@ main (int argc, char **argv) continue; case HEADSW: - headsw++; + headsw = true; continue; case NHEADSW: - headsw = 0; + headsw = false; continue; case DIRECTIVES: - directives = 1; + directives = true; continue; case NDIRECTIVES: - directives = 0; + directives = false; continue; case LISTSW: - listsw++; + listsw = true; continue; case NLISTSW: - listsw = 0; + listsw = false; continue; case RFC934SW: - rfc934sw++; + rfc934sw = true; continue; case NRFC934SW: - rfc934sw = 0; + rfc934sw = false; continue; case SIZESW: - sizesw++; + sizesw = true; continue; case NSIZESW: - sizesw = 0; + sizesw = false; continue; case CONTENTIDSW: - contentidsw = 1; + contentidsw = true; continue; case NCONTENTIDSW: - contentidsw = 0; + contentidsw = false; + continue; + + case HEADERENCSW: { + int encoding; + + if (!(cp = *argp++) || *cp == '-') + die("missing argument to %s", argp[-2]); + switch (encoding = smatch (cp, encodingswitches)) { + case AMBIGSW: + ambigsw (cp, encodingswitches); + done (1); + case UNKWNSW: + die("%s unknown encoding algorithm", cp); + case BASE64SW: + header_encoding = CE_BASE64; + break; + case QUOTEDPRINTSW: + header_encoding = CE_QUOTED; + break; + case UTF8SW: + header_encoding = CE_8BIT; + break; + default: + die("Internal error: algorithm %s", cp); + } + continue; + } + + case AUTOHEADERENCSW: + header_encoding = CE_UNKNOWN; + continue; + + case MAXUNENCSW: + if (!(cp = *argp++) || *cp == '-') + die("missing argument to %s", argp[-2]); + if ((maxunencoded = atoi(cp)) < 1) + die("Invalid argument for %s: %s", argp[-2], cp); + if (maxunencoded > 998) + die("limit of -maxunencoded is 998"); continue; case VERBSW: - verbosw++; + verbosw = true; continue; case NVERBSW: - verbosw = 0; + verbosw = false; + continue; + case DISPOSW: + dispo = true; + continue; + case NDISPOSW: + dispo = false; continue; case DEBUGSW: debugsw = 1; continue; + case DISTSW: + dist = true; + continue; } } if (compfile) - adios (NULL, "only one composition file allowed"); - else - compfile = cp; + die("only one composition file allowed"); + compfile = cp; } /* @@ -232,7 +298,7 @@ main (int argc, char **argv) */ if ((cp = getenv ("MHBUILD"))) { if ((fp = fopen (cp, "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); + readconfig(NULL, fp, cp, 0); fclose (fp); } else { admonish ("", "unable to read $MHBUILD profile (%s)", cp); @@ -243,7 +309,7 @@ main (int argc, char **argv) * Read the standard profile setup */ if ((fp = fopen (cp = etcpath ("mhn.defaults"), "r"))) { - readconfig ((struct node **) 0, fp, cp, 0); + readconfig(NULL, fp, cp, 0); fclose (fp); } @@ -254,63 +320,57 @@ main (int argc, char **argv) /* 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); + cache_private = mh_xstrdup(m_maildir(cache_private)); 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); + die("need to specify a %s composition file", invo_name); /* * Process the composition file from standard input. */ if (compfile[0] == '-' && compfile[1] == '\0') { + if ((cp = m_mktemp2(NULL, invo_name, NULL, &fp)) == NULL) { + die("unable to create temporary file in %s", + get_temp_dir()); + } + strncpy (infile, cp, sizeof(infile)); + /* copy standard input to temporary file */ - strncpy (infile, m_mktemp(invo_name, NULL, &fp), sizeof(infile)); - while (fgets (buffer, BUFSIZ, stdin)) - fputs (buffer, fp); + while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) { + if (fwrite(buffer, 1, n, fp) != n) { + die("error copying to temporary file"); + } + } fclose (fp); - unlink_infile = 1; /* build the content structures for MIME message */ - ct = build_mime (infile, directives); - 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); + ct = build_mime (infile, autobuild, dist, directives, header_encoding, + maxunencoded, verbosw); - unlink (infile); - unlink_infile = 0; + /* + * If ct == NULL, that means that -auto was set and a MIME version + * header was already seen. Just use the input file as the output + */ - unlink (outfile); - unlink_outfile = 0; + if (!ct) { + if (! (fp = fopen(infile, "r"))) { + die("Unable to open %s for reading", infile); + } + while ((n = fread(buffer, 1, sizeof(buffer), fp)) > 0) { + if (fwrite(buffer, 1, n, stdout) != n) { + die("error copying %s to stdout", infile); + } + } + } else { + /* output the message */ + output_message_fp (ct, stdout, NULL); + free_content (ct); + } - free_content (ct); done (0); } @@ -319,14 +379,25 @@ main (int argc, char **argv) */ /* build the content structures for MIME message */ - ct = build_mime (compfile, directives); + ct = build_mime (compfile, autobuild, dist, directives, header_encoding, + maxunencoded, verbosw); + + /* + * If ct == NULL, that means -auto was set and we found a MIME version + * header. Simply exit and do nothing. + */ + + if (! ct) + done(0); + cts[0] = ct; cts[1] = NULL; /* output MIME message to this temporary file */ - strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out), - sizeof(outfile)); - unlink_outfile = 1; + if ((cp = m_mktemp2(compfile, invo_name, NULL, &fp_out)) == NULL) { + die("unable to create temporary file"); + } + strncpy(outfile, cp, sizeof(outfile)); /* output the message */ output_message_fp (ct, fp_out, outfile); @@ -336,7 +407,7 @@ main (int argc, char **argv) * List the message info */ if (listsw) - list_all_messages (cts, headsw, sizesw, verbosw, debugsw); + list_all_messages (cts, headsw, sizesw, verbosw, debugsw, dispo); /* Rename composition draft */ snprintf (buffer, sizeof(buffer), "%s.orig", m_backup (compfile)); @@ -350,25 +421,12 @@ main (int argc, char **argv) rename (buffer, compfile); done (1); } - unlink_outfile = 0; + /* Remove from atexit(3) list of files to unlink. */ + if (!(m_unlink(outfile) == -1 && errno == ENOENT)) { + adios(outfile, "file exists after rename:"); + } free_content (ct); done (0); return 1; } - - -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); -}