/*
* mhparse.c -- routines to parse the contents of MIME messages
*
- * $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/signals.h>
#include <h/md5.h>
#include <errno.h>
-#include <setjmp.h>
#include <signal.h>
#include <h/mts.h>
#include <h/tws.h>
#include <h/mhparse.h>
#include <h/utils.h>
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
extern int debugsw;
-extern int endian; /* mhmisc.c */
-
extern pid_t xpid; /* mhshowsbr.c */
/* cache policies */
*/
char *tmp;
+/*
+ * Instruct parser not to detect invalid Content-Transfer-Encoding
+ * in a multipart.
+ */
+int skip_mp_cte_check;
+
/*
* Structures for TEXT messages
*/
{ NULL, TEXT_UNKNOWN } /* this one must be last! */
};
-struct k2v Charset[] = {
- { "us-ascii", CHARSET_USASCII },
- { "iso-8859-1", CHARSET_LATIN },
- { NULL, CHARSET_UNKNOWN } /* this one must be last! */
-};
+/* Charset[] removed -- yozo. Mon Oct 8 01:03:41 JST 2012 */
/*
* Structures for MULTIPART messages
};
-/* ftpsbr.c */
-int ftp_get (char *, char *, char *, char *, char *, char *, int, int);
-
/* mhcachesbr.c */
int find_cache (CT, int, int *, char *, char *, int);
/* mhmisc.c */
int part_ok (CT, int);
int type_ok (CT, int);
-int make_intermediates (char *);
void content_error (char *, CT, char *, ...);
/* mhfree.c */
-void free_content (CT);
void free_encoding (CT, int);
/*
* static prototypes
*/
static CT get_content (FILE *, char *, int);
-static int get_comment (CT, unsigned char **, int);
+static int get_comment (CT, char **, int);
static int InitGeneric (CT);
static int InitText (CT);
static int InitMail (CT);
static int openMail (CT, char **);
static int readDigest (CT, char *);
+static int get_leftover_mp_content (CT, int);
struct str2init str2cts[] = {
{ "application", CT_APPLICATION, InitApplication },
* Check if file is actually standard input
*/
if ((is_stdin = !(strcmp (file, "-")))) {
- file = add (m_tmpfil (invo_name), NULL);
- if ((fp = fopen (file, "w+")) == NULL) {
- advise (file, "unable to fopen for writing and reading");
- return NULL;
- }
+ char *tfile = m_mktemp2(NULL, invo_name, NULL, &fp);
+ if (tfile == NULL) {
+ advise("mhparse", "unable to create temporary file");
+ return NULL;
+ }
+ file = add (tfile, NULL);
chmod (file, 0600);
+
while (fgets (buffer, sizeof(buffer), stdin))
fputs (buffer, fp);
fflush (fp);
char *np, *vp;
CT ct;
HF hp;
+ m_getfld_state_t gstate = 0;
/* allocate the content structure */
if (!(ct = (CT) calloc (1, sizeof(*ct))))
* Parse the header fields for this
* content into a linked list.
*/
- for (compnum = 1, state = FLD;;) {
- switch (state = m_getfld (state, name, buf, sizeof(buf), in)) {
+ m_getfld_track_filepos (&gstate, in);
+ for (compnum = 1;;) {
+ int bufsz = sizeof buf;
+ switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) {
case FLD:
case FLDPLUS:
- case FLDEOF:
compnum++;
/* get copies of the buffers */
/* if necessary, get rest of field */
while (state == FLDPLUS) {
- state = m_getfld (state, name, buf, sizeof(buf), in);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, in);
vp = add (buf, vp); /* add to previous value */
}
/* Now add the header data to the list */
add_header (ct, np, vp);
- /* continue, if this isn't the last header field */
- if (state != FLDEOF) {
- ct->c_begin = ftell (in) + 1;
- continue;
- }
- /* else fall... */
+ /* continue, to see if this isn't the last header field */
+ ct->c_begin = ftell (in) + 1;
+ continue;
case BODY:
- case BODYEOF:
ct->c_begin = ftell (in) - strlen (buf);
break;
/* break out of the loop */
break;
}
+ m_getfld_state_destroy (&gstate);
/*
* Read the content headers. We will parse the
/* Get MIME-Version field */
if (!mh_strcasecmp (hp->name, VRSN_FIELD)) {
int ucmp;
- char c;
- unsigned char *cp, *dp;
+ char c, *cp, *dp;
if (ct->c_vrsn) {
advise (NULL, "message %s has multiple %s: fields",
/* Now, cleanup this field */
cp = ct->c_vrsn;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n'))
*dp++ = ' ';
for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
- if (!isspace (*dp))
+ if (!isspace ((unsigned char) *dp))
break;
*++dp = '\0';
if (debugsw)
}
else if (!mh_strcasecmp (hp->name, ENCODING_FIELD)) {
/* Get Content-Transfer-Encoding field */
- char c;
- unsigned char *cp, *dp;
+ char c, *cp, *dp;
struct str2init *s2i;
/*
/* get copy of this field */
ct->c_celine = cp = add (hp->value, NULL);
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
for (dp = cp; istoken (*dp); dp++)
continue;
}
else if (!mh_strcasecmp (hp->name, MD5_FIELD)) {
/* Get Content-MD5 field */
- unsigned char *cp, *dp;
- char *ep;
+ char *cp, *dp, *ep;
if (!checksw)
goto next_header;
ep = cp = add (hp->value, NULL); /* get a copy */
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n'))
*dp++ = ' ';
for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
- if (!isspace (*dp))
+ if (!isspace ((unsigned char) *dp))
break;
*++dp = '\0';
if (debugsw)
goto out;
}
- for (dp = cp; *dp && !isspace (*dp); dp++)
+ for (dp = cp; *dp && !isspace ((unsigned char) *dp); dp++)
continue;
*dp = '\0';
filename="foo". If it doesn't and value does, use value from
that. */
static char *
-incl_name_value (unsigned char *buf, char *name, char *value) {
+incl_name_value (char *buf, char *name, char *value) {
char *newbuf = buf;
/* Assume that name is non-null. */
if (! strstr (buf, name_plus_equal)) {
char *insertion;
- unsigned char *cp;
- char *prefix, *suffix;
+ char *cp, *prefix, *suffix;
/* Trim trailing space, esp. newline. */
for (cp = &buf[strlen (buf) - 1];
- cp >= buf && isspace (*cp);
+ cp >= buf && isspace ((unsigned char) *cp);
--cp) {
*cp = '\0';
}
* directives. Fills in the information of the CTinfo structure.
*/
int
-get_ctinfo (unsigned char *cp, CT ct, int magic)
+get_ctinfo (char *cp, CT ct, int magic)
{
int i;
- unsigned char *dp;
- char **ap, **ep;
+ char *dp, **ap, **ep;
char c;
CI ci;
/* store copy of Content-Type line */
cp = ct->c_ctline = add (cp, NULL);
- while (isspace (*cp)) /* trim leading spaces */
+ while (isspace ((unsigned char) *cp)) /* trim leading spaces */
cp++;
/* change newlines to spaces */
/* trim trailing spaces */
for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
- if (!isspace (*dp))
+ if (!isspace ((unsigned char) *dp))
break;
*++dp = '\0';
/* down case the content type string */
for (dp = ci->ci_type; *dp; dp++)
- if (isalpha(*dp) && isupper (*dp))
- *dp = tolower (*dp);
+ if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp))
+ *dp = tolower ((unsigned char) *dp);
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
}
cp++;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
/* down case the content subtype string */
for (dp = ci->ci_subtype; *dp; dp++)
- if (isalpha(*dp) && isupper (*dp))
- *dp = tolower (*dp);
+ if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp))
+ *dp = tolower ((unsigned char) *dp);
magic_skip:
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
*/
ep = (ap = ci->ci_attrs) + NPARMS;
while (*cp == ';') {
- char *vp;
- unsigned char *up;
+ char *vp, *up;
if (ap >= ep) {
advise (NULL,
}
cp++;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
}
/* down case the attribute name */
- for (dp = cp; istoken (*dp); dp++)
- if (isalpha(*dp) && isupper (*dp))
- *dp = tolower (*dp);
+ for (dp = cp; istoken ((unsigned char) *dp); dp++)
+ if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp))
+ *dp = tolower ((unsigned char) *dp);
- for (up = dp; isspace (*dp);)
+ for (up = dp; isspace ((unsigned char) *dp);)
dp++;
if (dp == cp || *dp != '=') {
advise (NULL,
vp = (*ap = add (cp, NULL)) + (up - cp);
*vp = '\0';
- for (dp++; isspace (*dp);)
+ for (dp++; isspace ((unsigned char) *dp);)
dp++;
/* now add the attribute value */
}
ap++;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
if (*cp == '(' && get_comment (ct, &cp, 1) == NOTOK)
*dp++ = c;
cp = dp;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
}
*dp++ = c;
cp = dp;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
}
*dp++ = c;
cp = dp;
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
}
static int
-get_comment (CT ct, unsigned char **ap, int istype)
+get_comment (CT ct, char **ap, int istype)
{
int i;
- char *bp;
- unsigned char *cp;
+ char *bp, *cp;
char c, buffer[BUFSIZ], *dp;
CI ci;
}
}
- while (isspace (*cp))
+ while (isspace ((unsigned char) *cp))
cp++;
*ap = cp;
static int
InitGeneric (CT ct)
{
+ NMH_UNUSED (ct);
+
return OK; /* not much to do here */
}
/* check if content specified a character set */
if (*ap) {
- /* match character set or set to CHARSET_UNKNOWN */
- for (kv = Charset; kv->kv_key; kv++) {
- if (!mh_strcasecmp (*ep, kv->kv_key)) {
- chset = *ep;
- break;
- }
- }
- t->tx_charset = kv->kv_value;
+ chset = *ep;
+ t->tx_charset = CHARSET_SPECIFIED;
} else {
t->tx_charset = CHARSET_UNSPECIFIED;
}
{
int inout;
long last, pos;
- unsigned char *cp, *dp;
- char **ap, **ep;
+ char *cp, *dp, **ap, **ep;
char *bp, buffer[BUFSIZ];
struct multipart *m;
struct k2v *kv;
* The encoding for multipart messages must be either
* 7bit, 8bit, or binary (per RFC2045).
*/
- if (ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT
- && ct->c_encoding != CE_BINARY) {
+ if (! skip_mp_cte_check && ct->c_encoding != CE_7BIT &&
+ ct->c_encoding != CE_8BIT && ct->c_encoding != CE_BINARY) {
+ /* Copy the Content-Transfer-Encoding header field body so we can
+ remove any trailing whitespace and leading blanks from it. */
+ char *cte = add (ct->c_celine ? ct->c_celine : "(null)", NULL);
+
+ bp = cte + strlen (cte) - 1;
+ while (bp >= cte && isspace ((unsigned char) *bp)) *bp-- = '\0';
+ for (bp = cte; *bp && isblank ((unsigned char) *bp); ++bp) continue;
+
admonish (NULL,
- "\"%s/%s\" type in message %s must be encoded in 7bit, 8bit, or binary",
- ci->ci_type, ci->ci_subtype, ct->c_file);
+ "\"%s/%s\" type in message %s must be encoded in\n"
+ "7bit, 8bit, or binary, per RFC 2045 (6.4). One workaround "
+ "is to\nmanually edit the file and change the \"%s\"\n"
+ "Content-Transfer-Encoding to one of those. For now",
+ ci->ci_type, ci->ci_subtype, ct->c_file, bp);
+ free (cte);
+
return NOTOK;
}
ct->c_ctparams = (void *) m;
/* check if boundary parameter contains only whitespace characters */
- for (cp = bp; isspace (*cp); cp++)
+ for (cp = bp; isspace ((unsigned char) *cp); cp++)
continue;
if (!*cp) {
advise (NULL, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field",
/* remove trailing whitespace from boundary parameter */
for (cp = bp, dp = cp + strlen (cp) - 1; dp > cp; dp--)
- if (!isspace (*dp))
+ if (!isspace ((unsigned char) *dp))
break;
*++dp = '\0';
}
}
+ get_leftover_mp_content (ct, 1);
+ get_leftover_mp_content (ct, 0);
+
fclose (ct->c_fp);
ct->c_fp = NULL;
return OK;
openBase64 (CT ct, char **file)
{
int bitno, cc, digested;
- int fd, len, skip;
- unsigned long bits;
- unsigned char value, *b, *b1, *b2, *b3;
- unsigned char *cp, *ep;
- char buffer[BUFSIZ];
+ int fd, len, skip, own_ct_fp = 0;
+ uint32_t bits;
+ unsigned char value, b;
+ char *cp, *ep, buffer[BUFSIZ];
/* sbeck -- handle suffixes */
CI ci;
CE ce;
MD5_CTX mdContext;
- b = (unsigned char *) &bits;
- b1 = &b[endian > 0 ? 1 : 2];
- b2 = &b[endian > 0 ? 2 : 1];
- b3 = &b[endian > 0 ? 3 : 0];
-
ce = ct->c_cefile;
if (ce->ce_fp) {
fseek (ce->ce_fp, 0L, SEEK_SET);
}
if (*file == NULL) {
- ce->ce_file = add (m_scratch ("", tmp), NULL);
+ ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL);
ce->ce_unlink = 1;
} else {
ce->ce_file = add (*file, NULL);
ci->ci_type);
cp = context_find (buffer);
}
- if (cp != NULL && *cp != '\0')
- ce->ce_file = add (cp, ce->ce_file);
+ if (cp != NULL && *cp != '\0') {
+ if (ce->ce_unlink) {
+ /* Temporary file already exists, so we rename to
+ version with extension. */
+ char *file_org = strdup(ce->ce_file);
+ ce->ce_file = add (cp, ce->ce_file);
+ if (rename(file_org, ce->ce_file)) {
+ adios (ce->ce_file, "unable to rename %s to ", file_org);
+ }
+ free(file_org);
+
+ } else {
+ ce->ce_file = add (cp, ce->ce_file);
+ }
+ }
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
if ((len = ct->c_end - ct->c_begin) < 0)
adios (NULL, "internal error(1)");
- if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
- content_error (ct->c_file, ct, "unable to open for reading");
- return NOTOK;
+ if (! ct->c_fp) {
+ if ((ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
+ content_error (ct->c_file, ct, "unable to open for reading");
+ return NOTOK;
+ }
+ own_ct_fp = 1;
}
if ((digested = ct->c_digested))
for (ep = (cp = buffer) + cc; cp < ep; cp++) {
switch (*cp) {
default:
- if (isspace (*cp))
+ if (isspace ((unsigned char) *cp))
break;
- if (skip || (*cp & 0x80)
- || (value = b642nib[*cp & 0x7f]) > 0x3f) {
+ if (skip || (((unsigned char) *cp) & 0x80)
+ || (value = b642nib[((unsigned char) *cp) & 0x7f]) > 0x3f) {
if (debugsw) {
fprintf (stderr, "*cp=0x%x pos=%ld skip=%d\n",
- *cp,
+ (unsigned char) *cp,
(long) (lseek (fd, (off_t) 0, SEEK_CUR) - (ep - cp)),
skip);
}
bits |= value << bitno;
test_end:
if ((bitno -= 6) < 0) {
- putc ((char) *b1, ce->ce_fp);
+ b = (bits >> 16) & 0xff;
+ putc ((char) b, ce->ce_fp);
if (digested)
- MD5Update (&mdContext, b1, 1);
+ MD5Update (&mdContext, &b, 1);
if (skip < 2) {
- putc ((char) *b2, ce->ce_fp);
+ b = (bits >> 8) & 0xff;
+ putc ((char) b, ce->ce_fp);
if (digested)
- MD5Update (&mdContext, b2, 1);
+ MD5Update (&mdContext, &b, 1);
if (skip < 1) {
- putc ((char) *b3, ce->ce_fp);
+ b = bits & 0xff;
+ putc ((char) b, ce->ce_fp);
if (digested)
- MD5Update (&mdContext, b3, 1);
+ MD5Update (&mdContext, &b, 1);
}
}
ready_to_go:
*file = ce->ce_file;
+ if (own_ct_fp) {
+ fclose (ct->c_fp);
+ ct->c_fp = NULL;
+ }
return fileno (ce->ce_fp);
clean_up:
+ if (own_ct_fp) {
+ fclose (ct->c_fp);
+ ct->c_fp = NULL;
+ }
free_encoding (ct, 0);
return NOTOK;
}
static int
openQuoted (CT ct, char **file)
{
- int cc, digested, len, quoted;
- unsigned char *cp, *ep;
+ int cc, digested, len, quoted, own_ct_fp = 0;
+ char *cp, *ep;
char buffer[BUFSIZ];
unsigned char mask;
CE ce;
}
if (*file == NULL) {
- ce->ce_file = add (m_scratch ("", tmp), NULL);
+ ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL);
ce->ce_unlink = 1;
} else {
ce->ce_file = add (*file, NULL);
ci->ci_type);
cp = context_find (buffer);
}
- if (cp != NULL && *cp != '\0')
- ce->ce_file = add (cp, ce->ce_file);
-
- if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
- return NOTOK;
+ if (cp != NULL && *cp != '\0') {
+ if (ce->ce_unlink) {
+ /* Temporary file already exists, so we rename to
+ version with extension. */
+ char *file_org = strdup(ce->ce_file);
+ ce->ce_file = add (cp, ce->ce_file);
+ if (rename(file_org, ce->ce_file)) {
+ adios (ce->ce_file, "unable to rename %s to ", file_org);
+ }
+ free(file_org);
+
+ } else {
+ ce->ce_file = add (cp, ce->ce_file);
+ }
}
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
if ((len = ct->c_end - ct->c_begin) < 0)
adios (NULL, "internal error(2)");
- if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
- content_error (ct->c_file, ct, "unable to open for reading");
- return NOTOK;
+ if (! ct->c_fp) {
+ if ((ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
+ content_error (ct->c_file, ct, "unable to open for reading");
+ return NOTOK;
+ }
+ own_ct_fp = 1;
}
if ((digested = ct->c_digested))
len -= cc;
for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--)
- if (!isspace (*ep))
+ if (!isspace ((unsigned char) *ep))
break;
*++ep = '\n', ep++;
/* in an escape sequence */
if (quoted == 1) {
/* at byte 1 of an escape sequence */
- mask = hex2nib[*cp & 0x7f];
+ mask = hex2nib[((unsigned char) *cp) & 0x7f];
/* next is byte 2 */
quoted = 2;
} else {
/* at byte 2 of an escape sequence */
mask <<= 4;
- mask |= hex2nib[*cp & 0x7f];
+ mask |= hex2nib[((unsigned char) *cp) & 0x7f];
putc (mask, ce->ce_fp);
if (digested)
MD5Update (&mdContext, &mask, 1);
if (cp + 1 >= ep || cp + 2 >= ep) {
/* We don't have 2 bytes left, so this is an invalid
* escape sequence; just show the raw bytes (below). */
- } else if (isxdigit (cp[1]) && isxdigit (cp[2])) {
+ } else if (isxdigit ((unsigned char) cp[1]) &&
+ isxdigit ((unsigned char) cp[2])) {
/* Next 2 bytes are hex digits, making this a valid escape
* sequence; let's decode it (above). */
quoted = 1;
ready_to_go:
*file = ce->ce_file;
+ if (own_ct_fp) {
+ fclose (ct->c_fp);
+ ct->c_fp = NULL;
+ }
return fileno (ce->ce_fp);
clean_up:
free_encoding (ct, 0);
+ if (own_ct_fp) {
+ fclose (ct->c_fp);
+ ct->c_fp = NULL;
+ }
return NOTOK;
}
int
open7Bit (CT ct, char **file)
{
- int cc, fd, len;
+ int cc, fd, len, own_ct_fp = 0;
char buffer[BUFSIZ];
/* sbeck -- handle suffixes */
char *cp;
}
if (*file == NULL) {
- ce->ce_file = add (m_scratch ("", tmp), NULL);
+ ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL);
ce->ce_unlink = 1;
} else {
ce->ce_file = add (*file, NULL);
ci->ci_type);
cp = context_find (buffer);
}
- if (cp != NULL && *cp != '\0')
- ce->ce_file = add (cp, ce->ce_file);
+ if (cp != NULL && *cp != '\0') {
+ if (ce->ce_unlink) {
+ /* Temporary file already exists, so we rename to
+ version with extension. */
+ char *file_org = strdup(ce->ce_file);
+ ce->ce_file = add (cp, ce->ce_file);
+ if (rename(file_org, ce->ce_file)) {
+ adios (ce->ce_file, "unable to rename %s to ", file_org);
+ }
+ free(file_org);
+
+ } else {
+ ce->ce_file = add (cp, ce->ce_file);
+ }
+ }
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
if ((len = ct->c_end - ct->c_begin) < 0)
adios (NULL, "internal error(3)");
- if (!ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
- content_error (ct->c_file, ct, "unable to open for reading");
- return NOTOK;
+ if (! ct->c_fp) {
+ if ((ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
+ content_error (ct->c_file, ct, "unable to open for reading");
+ return NOTOK;
+ }
+ own_ct_fp = 1;
}
lseek (fd = fileno (ct->c_fp), (off_t) ct->c_begin, SEEK_SET);
ready_to_go:
*file = ce->ce_file;
+ if (own_ct_fp) {
+ fclose (ct->c_fp);
+ ct->c_fp = NULL;
+ }
return fileno (ce->ce_fp);
clean_up:
free_encoding (ct, 0);
+ if (own_ct_fp) {
+ fclose (ct->c_fp);
+ ct->c_fp = NULL;
+ }
return NOTOK;
}
if ((ftp = context_find (nmhaccessftp)) && !*ftp)
ftp = NULL;
-#ifndef BUILTIN_FTP
if (!ftp)
return NOTOK;
-#endif
switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) {
case NOTOK:
if (e->eb_flags) {
user = "anonymous";
- snprintf (buffer, sizeof(buffer), "%s@%s", getusername (), LocalName ());
+ snprintf (buffer, sizeof(buffer), "%s@%s", getusername (),
+ LocalName (1));
pass = buffer;
} else {
ruserpass (e->eb_site, &username, &password);
else if (caching)
ce->ce_file = add (cachefile, NULL);
else
- ce->ce_file = add (m_scratch ("", tmp), NULL);
+ ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL);
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
return NOTOK;
}
-#ifdef BUILTIN_FTP
- if (ftp)
-#endif
{
int child_id, i, vecp;
char *vec[9];
fflush (stdout);
- for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
+ for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
sleep (5);
switch (child_id) {
case NOTOK:
default:
if (pidXwait (child_id, NULL)) {
-#ifdef BUILTIN_FTP
-losing_ftp:
-#endif
username = password = NULL;
ce->ce_unlink = 1;
return NOTOK;
break;
}
}
-#ifdef BUILTIN_FTP
- else
- if (ftp_get (e->eb_site, user, pass, e->eb_dir, e->eb_name,
- ce->ce_file,
- e->eb_mode && !mh_strcasecmp (e->eb_mode, "ascii"), 0)
- == NOTOK)
- goto losing_ftp;
-#endif
if (cachefile[0]) {
if (caching)
vec[vecp++] = e->eb_body;
vec[vecp] = NULL;
- for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
+ for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
sleep (5);
switch (child_id) {
case NOTOK:
}
if (*file == NULL) {
- ce->ce_file = add (m_scratch ("", tmp), NULL);
+ ce->ce_file = add (m_mktemp(tmp, NULL, NULL), NULL);
ce->ce_unlink = 1;
} else {
ce->ce_file = add (*file, NULL);
readDigest (CT ct, char *cp)
{
int bitno, skip;
- unsigned long bits;
+ uint32_t bits;
char *bp = cp;
unsigned char *dp, value, *ep;
- unsigned char *b, *b1, *b2, *b3;
- b = (unsigned char *) &bits,
- b1 = &b[endian > 0 ? 1 : 2],
- b2 = &b[endian > 0 ? 2 : 1],
- b3 = &b[endian > 0 ? 3 : 0];
bitno = 18;
bits = 0L;
skip = 0;
if ((bitno -= 6) < 0) {
if (dp + (3 - skip) > ep)
goto invalid_digest;
- *dp++ = *b1;
+ *dp++ = (bits >> 16) & 0xff;
if (skip < 2) {
- *dp++ = *b2;
+ *dp++ = (bits >> 8) & 0xff;
if (skip < 1)
- *dp++ = *b3;
+ *dp++ = bits & 0xff;
}
bitno = 18;
bits = 0L;
return OK;
}
+
+
+/* Multipart parts might have content before the first subpart and/or
+ after the last subpart that hasn't been stored anywhere else, so do
+ that. */
+int
+get_leftover_mp_content (CT ct, int before /* or after */) {
+ struct multipart *m = (struct multipart *) ct->c_ctparams;
+ char *boundary;
+ int found_boundary = 0;
+ char buffer[BUFSIZ];
+ int max = BUFSIZ;
+ int read = 0;
+ char *content = NULL;
+
+ if (! m) return NOTOK;
+
+ if (before) {
+ if (! m->mp_parts || ! m->mp_parts->mp_part) return NOTOK;
+
+ /* Isolate the beginning of this part to the beginning of the
+ first subpart and save any content between them. */
+ fseeko (ct->c_fp, ct->c_begin, SEEK_SET);
+ max = m->mp_parts->mp_part->c_begin - ct->c_begin;
+ boundary = concat ("--", m->mp_start, NULL);
+ } else {
+ struct part *last_subpart = NULL;
+ struct part *subpart;
+
+ /* Go to the last subpart to get its end position. */
+ for (subpart = m->mp_parts; subpart; subpart = subpart->mp_next) {
+ last_subpart = subpart;
+ }
+
+ if (last_subpart == NULL) return NOTOK;
+
+ /* Isolate the end of the last subpart to the end of this part
+ and save any content between them. */
+ fseeko (ct->c_fp, last_subpart->mp_part->c_end, SEEK_SET);
+ max = ct->c_end - last_subpart->mp_part->c_end;
+ boundary = concat ("--", m->mp_stop, NULL);
+ }
+
+ /* Back up by 1 to pick up the newline. */
+ while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) {
+ read += strlen (buffer);
+ /* Don't look beyond beginning of first subpart (before) or
+ next part (after). */
+ if (read > max) buffer[read-max] = '\0';
+
+ if (before) {
+ if (! strcmp (buffer, boundary)) {
+ found_boundary = 1;
+ }
+ } else {
+ if (! found_boundary && ! strcmp (buffer, boundary)) {
+ found_boundary = 1;
+ continue;
+ }
+ }
+
+ if ((before && ! found_boundary) || (! before && found_boundary)) {
+ if (content) {
+ char *old_content = content;
+ content = concat (content, buffer, NULL);
+ free (old_content);
+ } else {
+ content = before
+ ? concat ("\n", buffer, NULL)
+ : concat (buffer, NULL);
+ }
+ }
+
+ if (before) {
+ if (found_boundary || read > max) break;
+ } else {
+ if (read > max) break;
+ }
+ }
+
+ /* Skip the newline if that's all there is. */
+ if (content) {
+ char *cp;
+
+ /* Remove trailing newline, except at EOF. */
+ if ((before || ! feof (ct->c_fp)) &&
+ (cp = content + strlen (content)) > content &&
+ *--cp == '\n') {
+ *cp = '\0';
+ }
+
+ if (strlen (content) > 1) {
+ if (before) {
+ m->mp_content_before = content;
+ } else {
+ m->mp_content_after = content;
+ }
+ } else {
+ free (content);
+ }
+ }
+
+ free (boundary);
+
+ return OK;
+}