/*
* mhbuild.c -- expand/translate MIME composition files
*
- * $Id$
- *
* 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/signals.h>
#include <h/md5.h>
-#include <errno.h>
-#include <signal.h>
#include <h/mts.h>
#include <h/tws.h>
#include <h/mime.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 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 }
-};
-
-
-/* mhbuildsbr.c */
-extern char *tmp; /* directory to place temp files */
+#define MHBUILD_SWITCHES \
+ X("auto", 0, AUTOSW) \
+ X("noauto", 0, NAUTOSW) \
+ X("check", 0, CHECKSW) \
+ X("nocheck", 0, NCHECKSW) \
+ X("directives", 0, DIRECTIVES) \
+ X("nodirectives", 0, NDIRECTIVES) \
+ X("headers", 0, HEADSW) \
+ X("noheaders", 0, NHEADSW) \
+ X("list", 0, LISTSW) \
+ X("nolist", 0, NLISTSW) \
+ X("realsize", 0, SIZESW) \
+ X("norealsize", 0, NSIZESW) \
+ X("rfc934mode", 0, RFC934SW) \
+ 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);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+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) \
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(MIMEENCODING);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(MIMEENCODING, encodingswitches);
+#undef X
/* mhcachesbr.c */
extern int rcachesw;
extern char *cache_private;
int debugsw = 0;
-int verbosw = 0;
-int ebcdicsw = 0;
int listsw = 0;
int rfc934sw = 0;
int contentidsw = 1;
static void unlink_done (int) NORETURN;
/* mhbuildsbr.c */
-CT build_mime (char *);
int output_message (CT, char *);
-
-/* mhlistsbr.c */
-int list_all_messages (CT *, int, int, int, int);
-
-/* mhmisc.c */
-void set_endian (void);
-
-/* mhfree.c */
-void free_content (CT);
+int output_message_fp (CT, FILE *, char*);
int
main (int argc, char **argv)
{
- int sizesw = 1, headsw = 1;
+ int sizesw = 1, headsw = 1, directives = 1, autobuild = 0, dist = 0;
+ int verbosw = 0, dispo = 0;
+ size_t maxunencoded = MAXTEXTPERLN;
int *icachesw;
char *cp, buf[BUFSIZ];
char buffer[BUFSIZ], *compfile = NULL;
char **argp, **arguments;
CT ct, cts[2];
- FILE *fp;
-
- done=unlink_done;
+ FILE *fp = NULL;
+ FILE *fp_out = NULL;
+ int header_encoding = CE_UNKNOWN;
+ size_t n;
-#ifdef LOCALE
- setlocale(LC_ALL, "");
-#endif
- invo_name = r1bindex (argv[0], '/');
+ if (nmh_init(argv[0], 2)) { return 1; }
- /* read user profile/context */
- context_read();
+ done=unlink_done;
arguments = getarguments (invo_name, argc, argv, 1);
argp = arguments;
case HELPSW:
snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
print_help (buf, switches, 1);
- done (1);
+ done (0);
case VERSIONSW:
print_version(invo_name);
- done (1);
+ done (0);
+
+ case AUTOSW:
+ /* -auto implies -nodirectives */
+ autobuild = 1;
+ directives = 0;
+ continue;
+ case NAUTOSW:
+ /*
+ * We're turning directives back on since this is likely here
+ * to override a profile entry
+ */
+ autobuild = 0;
+ directives = 1;
+ continue;
case RCACHESW:
icachesw = &rcachesw;
checksw = 0;
continue;
- case EBCDICSW:
- ebcdicsw++;
- continue;
- case NEBCDICSW:
- ebcdicsw = 0;
- continue;
-
case HEADSW:
headsw++;
continue;
headsw = 0;
continue;
+ case DIRECTIVES:
+ directives = 1;
+ continue;
+ case NDIRECTIVES:
+ directives = 0;
+ continue;
+
case LISTSW:
listsw++;
continue;
contentidsw = 0;
continue;
+ case HEADERENCSW: {
+ int encoding;
+
+ if (!(cp = *argp++) || *cp == '-')
+ adios (NULL, "missing argument to %s", argp[-2]);
+ switch (encoding = smatch (cp, encodingswitches)) {
+ case AMBIGSW:
+ ambigsw (cp, encodingswitches);
+ done (1);
+ case UNKWNSW:
+ adios (NULL, "%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:
+ adios (NULL, "Internal error: algorithm %s", cp);
+ }
+ continue;
+ }
+
+ case AUTOHEADERENCSW:
+ header_encoding = CE_UNKNOWN;
+ continue;
+
+ case MAXUNENCSW:
+ if (!(cp = *argp++) || *cp == '-')
+ adios (NULL, "missing argument to %s", argp[-2]);
+ if ((maxunencoded = atoi(cp)) < 1)
+ adios (NULL, "Invalid argument for %s: %s", argp[-2], cp);
+ if (maxunencoded > 998)
+ adios (NULL, "limit of -maxunencoded is 998");
+ continue;
+
case VERBSW:
verbosw++;
continue;
case NVERBSW:
verbosw = 0;
continue;
+ case DISPOSW:
+ dispo = 1;
+ continue;
+ case NDISPOSW:
+ dispo = 0;
+ continue;
case DEBUGSW:
debugsw = 1;
continue;
+ case DISTSW:
+ dist = 1;
+ continue;
}
}
if (compfile)
compfile = cp;
}
- set_endian ();
-
- if ((cp = getenv ("MM_NOASK")) && !strcmp (cp, "1"))
- listsw = 0;
-
/*
* Check if we've specified an additional profile
*/
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));
* Process the composition file from standard input.
*/
if (compfile[0] == '-' && compfile[1] == '\0') {
+ if ((cp = m_mktemp2(NULL, invo_name, NULL, &fp)) == NULL) {
+ adios(NULL, "unable to create temporary file in %s",
+ get_temp_dir());
+ }
+
+ /* save a copy of the name for later removal */
+ strncpy (infile, cp, sizeof(infile));
+ unlink_infile = 1;
/* 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);
+ while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
+ if (fwrite(buffer, 1, n, fp) != n) {
+ adios (NULL, "error copying to temporary file");
+ }
+ }
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_scratch ("", invo_name), 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);
+ 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"))) {
+ adios(NULL, "Unable to open %s for reading", infile);
+ }
+ while ((n = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
+ if (fwrite(buffer, 1, n, stdout) != n) {
+ adios(NULL, "error copying %s to stdout", infile);
+ }
+ }
+ } else {
+ /* output the message */
+ output_message_fp (ct, stdout, NULL);
+ free_content (ct);
+ }
- free_content (ct);
done (0);
}
*/
/* build the content structures for MIME message */
- ct = build_mime (compfile);
+ 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_scratch (compfile, invo_name), sizeof(outfile));
+ if ((cp = m_mktemp2(compfile, invo_name, NULL, &fp_out)) == NULL) {
+ adios(NULL, "unable to create temporary file in %s", get_temp_dir());
+ }
+ strncpy(outfile, cp, sizeof(outfile));
unlink_outfile = 1;
/* output the message */
- output_message (ct, outfile);
+ output_message_fp (ct, fp_out, outfile);
+ fclose(fp_out);
/*
* 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));
- if (rename (compfile, buffer) == NOTOK)
- adios (compfile, "unable to rename %s to", buffer);
+ if (rename (compfile, buffer) == NOTOK) {
+ adios (compfile, "unable to rename comp draft %s to", buffer);
+ }
/* Rename output file to take its place */
if (rename (outfile, compfile) == NOTOK) {
- advise (outfile, "unable to rename %s to", compfile);
+ advise (outfile, "unable to rename output %s to", compfile);
rename (buffer, compfile);
done (1);
}
* temporary files.
*/
if (unlink_infile)
- unlink (infile);
+ (void) m_unlink (infile);
if (unlink_outfile)
- unlink (outfile);
+ (void) m_unlink (outfile);
exit (status);
}