-
-/*
- * mhoutsbr.c -- routines to output MIME messages
+/* mhoutsbr.c -- routines to output MIME messages
* -- given a Content structure
*
* This code is Copyright (c) 2002, by the authors of nmh. See the
#include <h/mh.h>
#include <fcntl.h>
-#include <h/signals.h>
+#include <h/utils.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/mhparse.h>
+#include "mhoutsbr.h"
+#include "sbr/base64.h"
-extern int ebcdicsw;
-
-static char ebcdicsafe[0x100] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/*
- * prototypes
- */
-int output_message (CT, char *);
-int output_message_fp (CT, FILE *, char *);
-
/*
* static prototypes
*/
return OK;
}
-int
-output_message (CT ct, char *file)
-{
- FILE *fp;
- int status;
-
- if ((fp = fopen (file, "w")) == NULL) {
- advise (file, "unable to open for writing");
- return NOTOK;
- }
- status = output_message_fp(ct, fp, file);
- fclose(fp);
- return status;
-}
-
/*
* Output a Content structure to a file.
{
int result = 0;
CI ci = &ct->c_ctinfo;
+ char *boundary = "", *cp;
+
+ if ((cp = get_param(ci->ci_first_pm, "boundary", '-', 0)))
+ boundary = cp;
/*
* Output all header fields for this content
* "message/external", then we are done with the
* headers (since it has no body).
*/
- if (ct->c_ctexbody)
+ if (ct->c_ctexbody) {
+ if (*boundary != '\0')
+ free(boundary);
return OK;
+ }
/*
* Now output the content bodies.
putc ('\n', out);
m = (struct multipart *) ct->c_ctparams;
+
+ if (m->mp_content_before) {
+ fputs(m->mp_content_before, out);
+ }
+
for (part = m->mp_parts; part; part = part->mp_next) {
CT p = part->mp_part;
- fprintf (out, "\n--%s\n", ci->ci_values[0]);
- if (output_content (p, out) == NOTOK)
- return NOTOK;
+ fprintf (out, "\n--%s\n", boundary);
+ if (output_content (p, out) == NOTOK) {
+ if (*boundary != '\0')
+ free(boundary);
+ return NOTOK;
+ }
}
- fprintf (out, "\n--%s--\n", ci->ci_values[0]);
+ fprintf (out, "\n--%s--\n", boundary);
+
+ if (m->mp_content_after) {
+ fputs(m->mp_content_after, out);
+ }
}
break;
default:
switch (ct->c_encoding) {
case CE_7BIT:
- putc ('\n', out);
+ /* Special case: if this is a non-MIME message with no
+ body, don't emit the newline that would appear between
+ the headers and body. In that case, the call to
+ write8Bit() shouldn't be needed, but is harmless. */
+ if (ct->c_ctinfo.ci_first_pm != NULL || ct->c_begin == 0 ||
+ ct->c_begin != ct->c_end) {
+ putc ('\n', out);
+ }
result = write8Bit (ct, out);
break;
break;
case CE_BINARY:
- advise (NULL, "can't handle binary transfer encoding in content");
- result = NOTOK;
+ if (ct->c_type == CT_TEXT) {
+ /* So that mhfixmsg can decode to binary text. */
+ putc ('\n', out);
+ result = write8Bit (ct, out);
+ } else {
+ inform("can't handle binary transfer encoding in content");
+ result = NOTOK;
+ }
break;
default:
- advise (NULL, "unknown transfer encoding in content");
+ inform("unknown transfer encoding in content");
result = NOTOK;
break;
}
break;
}
+ if (*boundary != '\0')
+ free(boundary);
+
return result;
}
static int
writeExternalBody (CT ct, FILE *out)
{
- char **ap, **ep, *cp;
+ char *cp, *dp;
struct exbody *e = (struct exbody *) ct->c_ctparams;
putc ('\n', out);
switch (*++cp) {
case 'I':
if (ct2->c_id) {
- char *dp = trimcpy (ct2->c_id);
+ dp = trimcpy (ct2->c_id);
fputs (dp, out);
free (dp);
continue;
case 'N':
- for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
- if (!mh_strcasecmp (*ap, "name")) {
- fprintf (out, "%s", *ep);
- break;
- }
+ dp = get_param(ci2->ci_first_pm, "name", '_', 0);
+ if (dp) {
+ fputs (dp, out);
+ free (dp);
+ }
continue;
case 'T':
fprintf (out, "%s/%s", ci2->ci_type, ci2->ci_subtype);
- for (ap = ci2->ci_attrs, ep = ci2->ci_values; *ap; ap++, ep++)
- fprintf (out, "; %s=\"%s\"", *ap, *ep);
+ dp = output_params(strlen(ci2->ci_type) +
+ strlen(ci2->ci_subtype) + 1,
+ ci2->ci_first_pm, NULL, 0);
+ if (dp) {
+ fputs (dp, out);
+ free (dp);
+ }
continue;
case 'n':
write8Bit (CT ct, FILE *out)
{
int fd;
+ size_t inbytes;
char c, *file, buffer[BUFSIZ];
- CE ce = ct->c_cefile;
+ CE ce = &ct->c_cefile;
file = NULL;
if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
return NOTOK;
c = '\n';
- while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
- c = buffer[strlen (buffer) - 1];
- fputs (buffer, out);
+ while ((inbytes = fread (buffer, 1, sizeof buffer, ce->ce_fp)) > 0) {
+ c = buffer[inbytes - 1];
+ if (fwrite (buffer, 1, inbytes, out) < inbytes) {
+ advise ("write8Bit", "fwrite");
+ }
}
if (c != '\n')
putc ('\n', out);
{
int fd;
char *cp, *file;
- char c, buffer[BUFSIZ];
- CE ce = ct->c_cefile;
+ char c = '\0';
+ CE ce = &ct->c_cefile;
+ int n = 0;
+ char *bufp = NULL;
+ size_t buflen;
+ ssize_t gotlen;
file = NULL;
if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
return NOTOK;
- while (fgets (buffer, sizeof(buffer) - 1, ce->ce_fp)) {
- int n;
+ while ((gotlen = getline(&bufp, &buflen, ce->ce_fp)) != -1) {
- cp = buffer + strlen (buffer) - 1;
+ cp = bufp + gotlen - 1;
if ((c = *cp) == '\n')
- *cp = '\0';
-
- if (strncmp (cp = buffer, "From ", sizeof("From ") - 1) == 0) {
- fprintf (out, "=%02X", *cp++ & 0xff);
- n = 3;
- } else {
- n = 0;
+ gotlen--;
+
+ /*
+ * if the line starts with "From ", encode the 'F' so it
+ * doesn't falsely match an mbox delimiter.
+ */
+ cp = bufp;
+ if (gotlen >= 5 && has_prefix(cp, "From ")) {
+ fprintf (out, "=%02X", 'F');
+ cp++;
+ n += 3;
}
- for (; *cp; cp++) {
+
+ for (; cp < bufp + gotlen; cp++) {
if (n > CPERLIN - 3) {
fputs ("=\n", out);
n = 0;
break;
default:
- if (*cp < '!' || *cp > '~'
- || (ebcdicsw && !ebcdicsafe[*cp & 0xff]))
+ if (*cp < '!' || *cp > '~')
goto three_print;
putc (*cp, out);
n++;
}
if (c == '\n') {
- if (cp > buffer && (*--cp == ' ' || *cp == '\t'))
+ if (cp > bufp && (*--cp == ' ' || *cp == '\t'))
fputs ("=\n", out);
putc ('\n', out);
- } else {
- fputs ("=\n", out);
+ n = 0;
}
}
+ if (c != '\n')
+ putc ('\n', out);
+
(*ct->c_ceclosefnx) (ct);
+ free (bufp);
return OK;
}
{
int fd, result;
char *file;
- CE ce = ct->c_cefile;
+ CE ce = &ct->c_cefile;
file = NULL;
if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
return NOTOK;
- result = writeBase64aux (ce->ce_fp, out);
+ result = writeBase64aux (ce->ce_fp, out,
+ ct->c_type == CT_TEXT && ct->c_ctparams
+ ? ((struct text *) ct->c_ctparams)->lf_line_endings == 0
+ : 0);
(*ct->c_ceclosefnx) (ct);
return result;
}