#include <h/mh.h>
#include <fcntl.h>
-#include <h/signals.h>
-#include <h/md5.h>
-#include <errno.h>
-#include <setjmp.h>
#include <signal.h>
-#include <h/mts.h>
+#include <errno.h>
#include <h/tws.h>
#include <h/mime.h>
#include <h/mhparse.h>
#include <h/utils.h>
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sysexits.h>
extern int debugsw;
extern pid_t xpid; /* mhshowsbr.c */
-/* cache policies */
-extern int rcachesw; /* mhcachesbr.c */
-extern int wcachesw; /* mhcachesbr.c */
-
-int checksw = 0; /* check Content-MD5 field */
-
/*
** Directory to place temp files. This must
** be set before these routines are called.
};
-/* 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);
static int InitQuoted(CT);
static int openQuoted(CT, char **);
static int Init7Bit(CT);
-static int openExternal(CT, CT, CE, char **, int *);
-static int InitFile(CT);
-static int openFile(CT, char **);
-static int InitFTP(CT);
-static int openFTP(CT, char **);
-static int InitMail(CT);
-static int openMail(CT, char **);
-static int readDigest(CT, char *);
struct str2init str2cts[] = {
{ "application", CT_APPLICATION, InitApplication },
{ NULL, CE_UNKNOWN, NULL },
};
-/*
-** NOTE WELL: si_key MUST NOT have value of NOTOK
-**
-** si_key is 1 if access method is anonymous.
-*/
-struct str2init str2methods[] = {
- { "afs", 1, InitFile },
- { "anon-ftp", 1, InitFTP },
- { "ftp", 0, InitFTP },
- { "local-file", 0, InitFile },
- { "mail-server", 0, InitMail },
- { NULL, 0, NULL }
-};
-
int
pidcheck(int status)
fflush(stdout);
fflush(stderr);
- done(1);
+ exit(EX_SOFTWARE);
return 1;
}
advise("mhparse", "unable to create temporary file");
return NULL;
}
- file = getcpy(tfile);
+ file = mh_xstrdup(tfile);
chmod(file, 0600);
while (fgets(buffer, sizeof(buffer), stdin))
static CT
get_content(FILE *in, char *file, int toplevel)
{
- int compnum, state;
- char buf[BUFSIZ], name[NAMESZ];
- char *np, *vp;
+ enum state state;
+ struct field f = {{0}};
+ int compnum;
CT ct;
HF hp;
/* allocate the content structure */
- if (!(ct = (CT) calloc(1, sizeof(*ct))))
- adios(NULL, "out of memory");
+ ct = mh_xcalloc(1, sizeof(*ct));
ct->c_fp = in;
- ct->c_file = getcpy(file);
+ ct->c_file = mh_xstrdup(file);
ct->c_begin = ftell(ct->c_fp) + 1;
/*
** 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)) {
- case FLD:
- case FLDPLUS:
- case FLDEOF:
+ for (compnum = 1, state = FLD2;;) {
+ switch (state = m_getfld2(state, &f, in)) {
+ case LENERR2:
+ state = FLD2;
+ /* FALL */
+ case FLD2:
compnum++;
- /* get copies of the buffers */
- np = getcpy(name);
- vp = getcpy(buf);
+ /* add the header data to the list */
+ add_header(ct, mh_xstrdup(f.name), mh_xstrdup(f.value));
- /* if necessary, get rest of field */
- while (state == FLDPLUS) {
- state = m_getfld(state, name, buf,
- sizeof(buf), 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... */
+ ct->c_begin = ftell(in) + 1;
+ continue;
- case BODY:
- case BODYEOF:
- ct->c_begin = ftell(in) - strlen(buf);
+ case BODY2:
+ ct->c_begin = ftell(in) - strlen(f.value);
break;
- case FILEEOF:
+ case FILEEOF2:
ct->c_begin = ftell(in);
break;
- case LENERR:
- case FMTERR:
- adios(NULL, "message format error in component #%d",
- compnum);
+ case FMTERR2:
+ advise(NULL, "message format error in component #%d", compnum);
+ state = FLD2;
+ continue;
+
+ case IOERR2:
+ adios(EX_IOERR, "m_getfld2", "io error");
default:
- adios(NULL, "getfld() returned %d", state);
+ adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
}
-
- /* break out of the loop */
break;
}
advise(NULL, "message %s has multiple %s: fields", ct->c_file, VRSN_FIELD);
goto next_header;
}
- ct->c_vrsn = getcpy(hp->value);
+ ct->c_vrsn = mh_xstrdup(hp->value);
/* Now, cleanup this field */
cp = ct->c_vrsn;
}
/* get copy of this field */
- ct->c_celine = cp = getcpy(hp->value);
+ ct->c_celine = cp = mh_xstrdup(hp->value);
while (isspace(*cp))
cp++;
if (s2i->si_init && (*s2i->si_init) (ct) == NOTOK)
goto out;
- } else if (!mh_strcasecmp(hp->name, MD5_FIELD)) {
- /* Get Content-MD5 field */
- unsigned char *cp, *dp;
- char *ep;
-
- if (!checksw)
- goto next_header;
-
- if (ct->c_digested) {
- advise(NULL, "message %s has multiple %s: fields", ct->c_file, MD5_FIELD);
- goto next_header;
- }
-
- ep = cp = getcpy(hp->value);
-
- while (isspace(*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))
- break;
- *++dp = '\0';
- if (debugsw)
- fprintf(stderr, "%s: %s\n", MD5_FIELD, cp);
-
- if (*cp == '(' && get_comment(ct, &cp, 0) == NOTOK) {
- free(ep);
- goto out;
- }
-
- for (dp = cp; *dp && !isspace(*dp); dp++)
- continue;
- *dp = '\0';
-
- readDigest(ct, cp);
- free(ep);
- ct->c_digested++;
-
} else if (!mh_strcasecmp(hp->name, ID_FIELD)) {
/* Get Content-ID field */
ct->c_id = add(hp->value, ct->c_id);
HF hp;
/* allocate header field structure */
- hp = mh_xmalloc(sizeof(*hp));
+ hp = mh_xcalloc(1, sizeof(*hp));
/* link data into header structure */
hp->name = name;
** Insert at first semicolon, if any.
** If none, append to end.
*/
- prefix = getcpy(buf);
+ prefix = mh_xstrdup(buf);
if ((cp = strchr(prefix, ';'))) {
suffix = concat(cp, NULL);
*cp = '\0';
newbuf = concat(prefix, insertion, suffix,
"\n", NULL);
- free(suffix);
+ mh_free0(&suffix);
} else {
/* Append to end. */
newbuf = concat(buf, insertion, "\n", NULL);
}
- free(prefix);
- free(insertion);
- free(buf);
+ mh_free0(&prefix);
+ mh_free0(&insertion);
+ mh_free0(&buf);
}
- free(name_plus_equal);
+ mh_free0(&name_plus_equal);
}
return newbuf;
char *name_suffix_equals = strstr(value, name_suffix_plus_quote);
char *cp;
- free(name_suffix_plus_quote);
+ mh_free0(&name_suffix_plus_quote);
if (name_suffix_equals) {
char *name_suffix_begin;
for (; *cp != '"'; ++cp)
;
- extracted_name_value = mh_xmalloc(cp - name_suffix_begin + 1);
+ extracted_name_value = mh_xcalloc(cp - name_suffix_begin + 1, sizeof(char));
memcpy(extracted_name_value, name_suffix_begin,
cp - name_suffix_begin);
extracted_name_value[cp - name_suffix_begin] = '\0';
i = strlen(invo_name) + 2;
/* store copy of Content-Type line */
- cp = ct->c_ctline = getcpy(cp);
+ cp = ct->c_ctline = mh_xstrdup(cp);
while (isspace(*cp)) /* trim leading spaces */
cp++;
for (dp = cp; istoken(*dp); dp++)
continue;
c = *dp, *dp = '\0';
- ci->ci_type = getcpy(cp); /* store content type */
+ ci->ci_type = mh_xstrdup(cp); /* store content type */
*dp = c, cp = dp;
if (!*ci->ci_type) {
if (*cp != '/') {
if (!magic)
- ci->ci_subtype = getcpy("");
+ ci->ci_subtype = mh_xstrdup("");
goto magic_skip;
}
for (dp = cp; istoken(*dp); dp++)
continue;
c = *dp, *dp = '\0';
- ci->ci_subtype = getcpy(cp); /* store the content subtype */
+ ci->ci_subtype = mh_xstrdup(cp); /* store the content subtype */
*dp = c, cp = dp;
if (!*ci->ci_subtype) {
return NOTOK;
}
- vp = (*ap = getcpy(cp)) + (up - cp);
+ vp = (*ap = mh_xstrdup(cp)) + (up - cp);
*vp = '\0';
for (dp++; isspace(*dp);)
dp++;
}
if (!*vp) {
advise(NULL, "invalid parameter in message %s's %s: field\n%*.*s(parameter %s)", ct->c_file, TYPE_FIELD, i, i, "", *ap);
- return NOTOK;
+ *ci->ci_values[ap - ci->ci_attrs] = '\0';
+ *ci->ci_attrs[ap - ci->ci_attrs] = '\0';
+ continue;
}
ap++;
*/
if (magic && *cp == '<') {
if (ct->c_id) {
- free(ct->c_id);
- ct->c_id = NULL;
+ mh_free0(&(ct->c_id));
}
if (!(dp = strchr(ct->c_id = ++cp, '>'))) {
advise(NULL, "invalid ID in message %s", ct->c_file);
*/
if (*cp) {
if (magic) {
- ci->ci_magic = getcpy(cp);
+ ci->ci_magic = mh_xstrdup(cp);
/*
** If there is a Content-Disposition header and
if (istype) {
if ((dp = ci->ci_comment)) {
ci->ci_comment = concat(dp, " ", buffer, NULL);
- free(dp);
+ mh_free0(&dp);
} else {
- ci->ci_comment = getcpy(buffer);
+ ci->ci_comment = mh_xstrdup(buffer);
}
}
static int
InitText(CT ct)
{
- char buffer[BUFSIZ];
- char *chset = NULL;
- char **ap, **ep, *cp;
+ char **ap, **ep;
struct k2v *kv;
struct text *t;
CI ci = &ct->c_ctinfo;
ct->c_subtype = kv->kv_value;
/* allocate text character set structure */
- if ((t = (struct text *) calloc(1, sizeof(*t))) == NULL)
- adios(NULL, "out of memory");
+ t = mh_xcalloc(1, sizeof(*t));
ct->c_ctparams = (void *) t;
/* scan for charset parameter */
/* check if content specified a character set */
if (*ap) {
+ /* store its name */
+ ct->c_charset = mh_xstrdup(norm_charmap(*ep));
/* 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 = CHARSET_UNSPECIFIED;
}
- /*
- ** If we can not handle character set natively,
- ** then check profile for string to modify the
- ** terminal or display method.
- **
- ** termproc is for mhshow, though mhlist -debug prints it, too.
- */
- if (chset != NULL && !check_charset(chset, strlen(chset))) {
- snprintf(buffer, sizeof(buffer), "%s-charset-%s",
- invo_name, chset);
- if ((cp = context_find(buffer)))
- ct->c_termproc = getcpy(cp);
- }
-
return OK;
}
if (ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT
&& ct->c_encoding != CE_BINARY) {
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);
- return NOTOK;
+ ct->c_encoding = CE_7BIT;
}
/* match subtype */
}
/* allocate primary structure for multipart info */
- if ((m = (struct multipart *) calloc(1, sizeof(*m))) == NULL)
- adios(NULL, "out of memory");
+ m = mh_xcalloc(1, sizeof(*m));
ct->c_ctparams = (void *) m;
/* check if boundary parameter contains only whitespace characters */
if (strcmp(buffer + 2, m->mp_start)!=0)
continue;
next_part:
- if ((part = (struct part *) calloc(1, sizeof(*part)))
- == NULL)
- adios(NULL, "out of memory");
+ part = mh_xcalloc(1, sizeof(*part));
*next = part;
next = &part->mp_next;
continue;
*next = NULL;
free_content(p);
- free((char *) part);
+ mh_free0(&part);
}
}
p = part->mp_part;
sprintf(pp, "%d", partnum);
- p->c_partno = getcpy(partnam);
+ p->c_partno = mh_xstrdup(partnam);
/* initialize the content of the subparts */
if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) {
i++;
/* allocate array of pointers to the parts */
- if (!(base = (struct part **) calloc((size_t) (i + 1), sizeof(*base))))
- adios(NULL, "out of memory");
+ base = mh_xcalloc(i + 1, sizeof(*base));
bmp = base;
/* point at all the parts */
*next = NULL;
/* free array of pointers */
- free((char *) base);
+ mh_free0(&base);
}
char **ap, **ep;
struct partial *p;
- if ((p = (struct partial *) calloc(1, sizeof(*p))) == NULL)
- adios(NULL, "out of memory");
+ p = mh_xcalloc(1, sizeof(*p));
ct->c_ctparams = (void *) p;
/*
*/
for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
if (!mh_strcasecmp(*ap, "id")) {
- p->pm_partid = getcpy(*ep);
+ p->pm_partid = mh_xstrdup(*ep);
continue;
}
if (!mh_strcasecmp(*ap, "number")) {
case MESSAGE_EXTERNAL:
{
- int exresult;
- struct exbody *e;
CT p;
FILE *fp;
- if ((e = (struct exbody *) calloc(1, sizeof(*e))) == NULL)
- adios(NULL, "out of memory");
- ct->c_ctparams = (void *) e;
-
if (!ct->c_fp && (ct->c_fp = fopen(ct->c_file, "r")) == NULL) {
advise(ct->c_file, "unable to open for reading");
return NOTOK;
return NOTOK;
}
- e->eb_parent = ct;
- e->eb_content = p;
- p->c_ctexbody = e;
- if ((exresult = params_external(ct, 0)) != NOTOK &&
- p->c_ceopenfnx == openMail) {
- int cc, size;
- char *bp;
-
- if ((size = ct->c_end - p->c_begin) <= 0) {
- if (!e->eb_subject)
- content_error(NULL, ct, "empty body for access-type=mail-server");
- goto no_body;
- }
-
- e->eb_body = bp = mh_xmalloc((unsigned) size);
- fseek(p->c_fp, p->c_begin, SEEK_SET);
- while (size > 0)
- switch (cc = fread(bp, sizeof(*bp), size, p->c_fp)) {
- case NOTOK:
- adios("failed", "fread");
- case OK:
- adios(NULL, "unexpected EOF from fread");
- default:
- bp += cc, size -= cc;
- break;
- }
- *bp = 0;
- }
-no_body:
p->c_fp = NULL;
p->c_end = p->c_begin;
fclose(ct->c_fp);
ct->c_fp = NULL;
- if (exresult == NOTOK)
- return NOTOK;
- if (e->eb_flags == NOTOK)
- return OK;
-
switch (p->c_type) {
case CT_MULTIPART:
break;
case CT_MESSAGE:
if (p->c_subtype != MESSAGE_RFC822)
break;
- /* else fall... */
+ /* else fall... */
default:
- e->eb_partno = ct->c_partno;
if (p->c_ctinitfnx)
(*p->c_ctinitfnx) (p);
break;
}
-int
-params_external(CT ct, int composing)
-{
- char **ap, **ep;
- struct exbody *e = (struct exbody *) ct->c_ctparams;
- CI ci = &ct->c_ctinfo;
-
- for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
- if (!mh_strcasecmp(*ap, "access-type")) {
- struct str2init *s2i;
- CT p = e->eb_content;
-
- for (s2i = str2methods; s2i->si_key; s2i++)
- if (!mh_strcasecmp(*ep, s2i->si_key))
- break;
- if (!s2i->si_key) {
- e->eb_access = *ep;
- e->eb_flags = NOTOK;
- p->c_encoding = CE_EXTERNAL;
- continue;
- }
- e->eb_access = s2i->si_key;
- e->eb_flags = s2i->si_val;
- p->c_encoding = CE_EXTERNAL;
-
- /* Call the Init function for this external type */
- if ((*s2i->si_init)(p) == NOTOK)
- return NOTOK;
- continue;
- }
- if (!mh_strcasecmp(*ap, "name")) {
- e->eb_name = *ep;
- continue;
- }
- if (!mh_strcasecmp(*ap, "permission")) {
- e->eb_permission = *ep;
- continue;
- }
- if (!mh_strcasecmp(*ap, "site")) {
- e->eb_site = *ep;
- continue;
- }
- if (!mh_strcasecmp(*ap, "directory")) {
- e->eb_dir = *ep;
- continue;
- }
- if (!mh_strcasecmp(*ap, "mode")) {
- e->eb_mode = *ep;
- continue;
- }
- if (!mh_strcasecmp(*ap, "size")) {
- sscanf(*ep, "%lu", &e->eb_size);
- continue;
- }
- if (!mh_strcasecmp(*ap, "server")) {
- e->eb_server = *ep;
- continue;
- }
- if (!mh_strcasecmp(*ap, "subject")) {
- e->eb_subject = *ep;
- continue;
- }
- if (composing && !mh_strcasecmp(*ap, "body")) {
- e->eb_body = getcpy(*ep);
- continue;
- }
- }
-
- if (!e->eb_access) {
- advise(NULL, "invalid parameters for \"%s/%s\" type in message %s's %s field", ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD);
- return NOTOK;
- }
-
- return OK;
-}
-
-
/*
** APPLICATION
*/
{
CE ce;
- if ((ce = (CE) calloc(1, sizeof(*ce))) == NULL)
- adios(NULL, "out of memory");
+ ce = mh_xcalloc(1, sizeof(*ce));
ct->c_cefile = ce;
ct->c_ceopenfnx = openfnx;
static int
openBase64(CT ct, char **file)
{
- int bitno, cc, digested;
- int fd, len, skip;
+ int bitno, cc;
+ int fd, len, skip, own_ct_fp = 0;
unsigned long bits;
unsigned char value, *b, *b1, *b2, *b3;
unsigned char *cp, *ep;
/* sbeck -- handle suffixes */
CI ci;
CE ce;
- MD5_CTX mdContext;
b = (unsigned char *) &bits;
b1 = &b[endian > 0 ? 1 : 2];
}
if (*file == NULL) {
- ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL));
+ ce->ce_file = mh_xstrdup(m_mktemp(tmp, NULL, NULL));
ce->ce_unlink = 1;
} else {
- ce->ce_file = getcpy(*file);
+ ce->ce_file = mh_xstrdup(*file);
ce->ce_unlink = 0;
}
cp = context_find(buffer);
if (cp == NULL || *cp == '\0') {
snprintf(buffer, sizeof(buffer), "%s-suffix-%s", invo_name,
- ci->ci_type);
+ ci->ci_type);
cp = context_find(buffer);
}
if (cp != NULL && *cp != '\0') {
** Temporary file already exists, so we rename to
** version with extension.
*/
- char *file_org = strdup(ce->ce_file);
+ char *file_org = mh_xstrdup(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 ",
+ adios(EX_IOERR, ce->ce_file, "unable to rename %s to ",
file_org);
}
- free(file_org);
+ mh_free0(&file_org);
} else {
ce->ce_file = add(cp, ce->ce_file);
}
if ((len = ct->c_end - ct->c_begin) < 0)
- adios(NULL, "internal error(1)");
+ adios(EX_SOFTWARE, 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))
- MD5Init(&mdContext);
-
bitno = 18;
bits = 0L;
skip = 0;
test_end:
if ((bitno -= 6) < 0) {
putc((char) *b1, ce->ce_fp);
- if (digested)
- MD5Update(&mdContext, b1, 1);
if (skip < 2) {
putc((char) *b2, ce->ce_fp);
- if (digested)
- MD5Update(&mdContext, b2, 1);
if (skip < 1) {
putc((char) *b3, ce->ce_fp);
- if (digested)
- MD5Update(&mdContext, b3, 1);
}
}
goto clean_up;
}
- if (digested) {
- unsigned char digest[16];
-
- MD5Final(digest, &mdContext);
- if (memcmp((char *) digest, (char *) ct->c_digest,
- sizeof(digest) / sizeof(digest[0])))
- content_error(NULL, ct, "content integrity suspect (digest mismatch) -- continuing");
- else if (debugsw)
- fprintf(stderr, "content integrity confirmed\n");
- }
-
fseek(ce->ce_fp, 0L, 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;
}
static int
openQuoted(CT ct, char **file)
{
- int cc, digested, len, quoted;
+ int cc, len, quoted, own_ct_fp = 0;
unsigned char *cp, *ep;
char buffer[BUFSIZ];
- unsigned char mask;
+ unsigned char mask = 0;
CE ce;
/* sbeck -- handle suffixes */
CI ci;
- MD5_CTX mdContext;
ce = ct->c_cefile;
if (ce->ce_fp) {
}
if (*file == NULL) {
- ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL));
+ ce->ce_file = mh_xstrdup(m_mktemp(tmp, NULL, NULL));
ce->ce_unlink = 1;
} else {
- ce->ce_file = getcpy(*file);
+ ce->ce_file = mh_xstrdup(*file);
ce->ce_unlink = 0;
}
}
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);
+ /*
+ ** Temporary file already exists, so we rename to
+ ** version with extension.
+ */
+ char *file_org = mh_xstrdup(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 ",
+ adios(EX_IOERR, ce->ce_file, "unable to rename %s to ",
file_org);
}
- free(file_org);
+ mh_free0(&file_org);
} else {
ce->ce_file = add(cp, ce->ce_file);
return NOTOK;
}
- 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 ((len = ct->c_end - ct->c_begin) < 0)
- adios(NULL, "internal error(2)");
+ adios(EX_SOFTWARE, 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))
- MD5Init(&mdContext);
-
quoted = 0;
-#ifdef lint
- mask = 0;
-#endif
fseek(ct->c_fp, ct->c_begin, SEEK_SET);
while (len > 0) {
mask <<= 4;
mask |= hex2nib[*cp & 0x7f];
putc(mask, ce->ce_fp);
- if (digested)
- MD5Update(&mdContext, &mask, 1);
if (ferror(ce->ce_fp)) {
content_error(ce->ce_file, ct, "error writing to");
goto clean_up;
/* Just show the raw byte. */
putc(*cp, ce->ce_fp);
- if (digested) {
- if (*cp == '\n') {
- MD5Update(&mdContext, (unsigned char *) "\r\n",2);
- } else {
- MD5Update(&mdContext, (unsigned char *) cp, 1);
- }
- }
if (ferror(ce->ce_fp)) {
content_error(ce->ce_file, ct,
"error writing to");
goto clean_up;
}
- if (digested) {
- unsigned char digest[16];
-
- MD5Final(digest, &mdContext);
- if (memcmp((char *) digest, (char *) ct->c_digest,
- sizeof(digest) / sizeof(digest[0])))
- content_error(NULL, ct, "content integrity suspect (digest mismatch) -- continuing");
- else if (debugsw)
- fprintf(stderr, "content integrity confirmed\n");
- }
-
fseek(ce->ce_fp, 0L, 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;
}
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 = getcpy(m_mktemp(tmp, NULL, NULL));
+ ce->ce_file = mh_xstrdup(m_mktemp(tmp, NULL, NULL));
ce->ce_unlink = 1;
} else {
- ce->ce_file = getcpy(*file);
+ ce->ce_file = mh_xstrdup(*file);
ce->ce_unlink = 0;
}
cp = context_find(buffer);
if (cp == NULL || *cp == '\0') {
snprintf(buffer, sizeof(buffer), "%s-suffix-%s", invo_name,
- ci->ci_type);
+ ci->ci_type);
cp = context_find(buffer);
}
if (cp != NULL && *cp != '\0') {
** Temporary file already exists, so we rename to
** version with extension.
*/
- char *file_org = strdup(ce->ce_file);
+ char *file_org = mh_xstrdup(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 ",
+ adios(EX_IOERR, ce->ce_file, "unable to rename %s to ",
file_org);
}
- free(file_org);
+ mh_free0(&file_org);
} else {
ce->ce_file = add(cp, ce->ce_file);
}
if ((len = ct->c_end - ct->c_begin) < 0)
- adios(NULL, "internal error(3)");
+ adios(EX_SOFTWARE, 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);
- return NOTOK;
-}
-
-
-/*
-** External
-*/
-
-static int
-openExternal(CT ct, CT cb, CE ce, char **file, int *fd)
-{
- char cachefile[BUFSIZ];
-
- if (ce->ce_fp) {
- fseek(ce->ce_fp, 0L, SEEK_SET);
- goto ready_already;
- }
-
- if (ce->ce_file) {
- if ((ce->ce_fp = fopen(ce->ce_file, "r")) == NULL) {
- content_error(ce->ce_file, ct,
- "unable to fopen for reading");
- return NOTOK;
- }
- goto ready_already;
- }
-
- if (find_cache(ct, rcachesw, (int *) 0, cb->c_id,
- cachefile, sizeof(cachefile)) != NOTOK) {
- if ((ce->ce_fp = fopen(cachefile, "r"))) {
- ce->ce_file = getcpy(cachefile);
- ce->ce_unlink = 0;
- goto ready_already;
- } else {
- admonish(cachefile, "unable to fopen for reading");
- }
- }
-
- return OK;
-
-ready_already:
- *file = ce->ce_file;
- *fd = fileno(ce->ce_fp);
- return DONE;
-}
-
-/*
-** File
-*/
-
-static int
-InitFile(CT ct)
-{
- return init_encoding(ct, openFile);
-}
-
-
-static int
-openFile(CT ct, char **file)
-{
- int fd, cachetype;
- char cachefile[BUFSIZ];
- struct exbody *e = ct->c_ctexbody;
- CE ce = ct->c_cefile;
-
- switch (openExternal(e->eb_parent, e->eb_content, ce, file, &fd)) {
- case NOTOK:
- return NOTOK;
- case OK:
- break;
- case DONE:
- return fd;
- }
-
- if (!e->eb_name) {
- content_error(NULL, ct, "missing name parameter");
- return NOTOK;
- }
-
- ce->ce_file = getcpy(e->eb_name);
- ce->ce_unlink = 0;
-
- if ((ce->ce_fp = fopen(ce->ce_file, "r")) == NULL) {
- content_error(ce->ce_file, ct, "unable to fopen for reading");
- return NOTOK;
- }
-
- if ((!e->eb_permission ||
- mh_strcasecmp(e->eb_permission, "read-write")) &&
- find_cache(NULL, wcachesw, &cachetype,
- e->eb_content->c_id, cachefile, sizeof(cachefile))
- != NOTOK) {
- int mask;
- FILE *fp;
-
- mask = umask(cachetype ? ~m_gmprot() : 0222);
- if ((fp = fopen(cachefile, "w"))) {
- int cc;
- char buffer[BUFSIZ];
- FILE *gp = ce->ce_fp;
-
- fseek(gp, 0L, SEEK_SET);
-
- while ((cc = fread(buffer, sizeof(*buffer),
- sizeof(buffer), gp)) > 0)
- fwrite(buffer, sizeof(*buffer), cc, fp);
- fflush(fp);
-
- if (ferror(gp)) {
- admonish(ce->ce_file, "error reading");
- unlink(cachefile);
- } else if (ferror(fp)) {
- admonish(cachefile, "error writing");
- unlink(cachefile);
- }
- fclose(fp);
- }
- umask(mask);
- }
-
- fseek(ce->ce_fp, 0L, SEEK_SET);
- *file = ce->ce_file;
- return fileno(ce->ce_fp);
-}
-
-/*
-** FTP
-*/
-
-static int
-InitFTP(CT ct)
-{
- return init_encoding(ct, openFTP);
-}
-
-
-static int
-openFTP(CT ct, char **file)
-{
- int cachetype, caching, fd;
- int len, buflen;
- char *bp, *ftp, *user, *pass;
- char buffer[BUFSIZ], cachefile[BUFSIZ];
- struct exbody *e;
- CE ce;
- static char *username = NULL;
- static char *password = NULL;
-
- e = ct->c_ctexbody;
- ce = ct->c_cefile;
-
- 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:
- return NOTOK;
- case OK:
- break;
- case DONE:
- return fd;
- }
-
- if (!e->eb_name || !e->eb_site) {
- content_error(NULL, ct, "missing %s parameter",
- e->eb_name ? "site": "name");
- return NOTOK;
- }
-
- if (xpid) {
- if (xpid < 0)
- xpid = -xpid;
- pidcheck(pidwait(xpid, NOTOK));
- xpid = 0;
- }
-
- /* Get the buffer ready to go */
- bp = buffer;
- buflen = sizeof(buffer);
-
- /*
- ** Construct the query message for user
- */
- snprintf(bp, buflen, "Retrieve %s", e->eb_name);
- len = strlen(bp);
- bp += len;
- buflen -= len;
-
- if (e->eb_partno) {
- snprintf(bp, buflen, " (content %s)", e->eb_partno);
- len = strlen(bp);
- bp += len;
- buflen -= len;
- }
-
- snprintf(bp, buflen, "\n using %sFTP from site %s",
- e->eb_flags ? "anonymous " : "", e->eb_site);
- len = strlen(bp);
- bp += len;
- buflen -= len;
-
- if (e->eb_size > 0) {
- snprintf(bp, buflen, " (%lu octets)", e->eb_size);
- len = strlen(bp);
- bp += len;
- buflen -= len;
- }
- snprintf(bp, buflen, "? ");
-
- /*
- ** Now, check the answer
- */
- if (!getanswer(buffer))
- return NOTOK;
-
- if (e->eb_flags) {
- user = "anonymous";
- snprintf(buffer, sizeof(buffer), "%s@%s", getusername(),
- LocalName());
- pass = buffer;
- } else {
- ruserpass(e->eb_site, &username, &password);
- user = username;
- pass = password;
- }
-
- ce->ce_unlink = (*file == NULL);
- caching = 0;
- cachefile[0] = '\0';
- if ((!e->eb_permission ||
- mh_strcasecmp(e->eb_permission, "read-write")) &&
- find_cache(NULL, wcachesw, &cachetype,
- e->eb_content->c_id, cachefile, sizeof(cachefile))
- != NOTOK) {
- if (*file == NULL) {
- ce->ce_unlink = 0;
- caching = 1;
- }
- }
-
- if (*file)
- ce->ce_file = getcpy(*file);
- else if (caching)
- ce->ce_file = getcpy(cachefile);
- else
- ce->ce_file = getcpy(m_mktemp(tmp, 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];
-
- vecp = 0;
- vec[vecp++] = mhbasename(ftp);
- vec[vecp++] = e->eb_site;
- vec[vecp++] = user;
- vec[vecp++] = pass;
- vec[vecp++] = e->eb_dir;
- vec[vecp++] = e->eb_name;
- vec[vecp++] = ce->ce_file,
- vec[vecp++] = e->eb_mode &&
- !mh_strcasecmp(e->eb_mode, "ascii") ?
- "ascii" : "binary";
- vec[vecp] = NULL;
-
- fflush(stdout);
-
- for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
- sleep(5);
- switch (child_id) {
- case NOTOK:
- adios("fork", "unable to");
- /* NOTREACHED */
-
- case OK:
- close(fileno(ce->ce_fp));
- execvp(ftp, vec);
- fprintf(stderr, "unable to exec ");
- perror(ftp);
- _exit(-1);
- /* NOTREACHED */
-
- 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)
- chmod(cachefile, cachetype ? m_gmprot() : 0444);
- else {
- int mask;
- FILE *fp;
-
- mask = umask(cachetype ? ~m_gmprot() : 0222);
- if ((fp = fopen(cachefile, "w"))) {
- int cc;
- FILE *gp = ce->ce_fp;
-
- fseek(gp, 0L, SEEK_SET);
-
- while ((cc= fread(buffer, sizeof(*buffer),
- sizeof(buffer), gp)) > 0)
- fwrite(buffer, sizeof(*buffer), cc, fp);
- fflush(fp);
-
- if (ferror(gp)) {
- admonish(ce->ce_file, "error reading");
- unlink(cachefile);
- } else if (ferror(fp)) {
- admonish(cachefile, "error writing");
- unlink(cachefile);
- }
- fclose(fp);
- }
- umask(mask);
- }
- }
-
- fseek(ce->ce_fp, 0L, SEEK_SET);
- *file = ce->ce_file;
- return fileno(ce->ce_fp);
-}
-
-
-/*
-** Mail
-*/
-
-static int
-InitMail(CT ct)
-{
- return init_encoding(ct, openMail);
-}
-
-
-static int
-openMail(CT ct, char **file)
-{
- int child_id, fd, i, vecp;
- int len, buflen;
- char *bp, buffer[BUFSIZ], *vec[7];
- struct exbody *e = ct->c_ctexbody;
- CE ce = ct->c_cefile;
-
- switch (openExternal(e->eb_parent, e->eb_content, ce, file, &fd)) {
- case NOTOK:
- return NOTOK;
- case OK:
- break;
- case DONE:
- return fd;
- }
-
- if (!e->eb_server) {
- content_error(NULL, ct, "missing server parameter");
- return NOTOK;
- }
-
- if (xpid) {
- if (xpid < 0)
- xpid = -xpid;
- pidcheck(pidwait(xpid, NOTOK));
- xpid = 0;
- }
-
- /* Get buffer ready to go */
- bp = buffer;
- buflen = sizeof(buffer);
-
- /* Now, construct query message */
- snprintf(bp, buflen, "Retrieve content");
- len = strlen(bp);
- bp += len;
- buflen -= len;
-
- if (e->eb_partno) {
- snprintf(bp, buflen, " %s", e->eb_partno);
- len = strlen(bp);
- bp += len;
- buflen -= len;
- }
-
- snprintf(bp, buflen, " by asking %s\n\n%s\n? ", e->eb_server,
- e->eb_subject ? e->eb_subject : e->eb_body);
-
- /* Now, check answer */
- if (!getanswer(buffer))
- return NOTOK;
-
- vecp = 0;
- vec[vecp++] = mhbasename(mailproc);
- vec[vecp++] = e->eb_server;
- vec[vecp++] = "-subject";
- vec[vecp++] = e->eb_subject ? e->eb_subject : "mail-server request";
- vec[vecp++] = "-body";
- vec[vecp++] = e->eb_body;
- vec[vecp] = NULL;
-
- for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
- sleep(5);
- switch (child_id) {
- case NOTOK:
- advise("fork", "unable to");
- return NOTOK;
-
- case OK:
- execvp(mailproc, vec);
- fprintf(stderr, "unable to exec ");
- perror(mailproc);
- _exit(-1);
- /* NOTREACHED */
-
- default:
- if (pidXwait(child_id, NULL) == OK)
- advise(NULL, "request sent");
- break;
- }
-
- if (*file == NULL) {
- ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL));
- ce->ce_unlink = 1;
- } else {
- ce->ce_file = getcpy(*file);
- ce->ce_unlink = 0;
- }
-
- if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) {
- content_error(ce->ce_file, ct,
- "unable to fopen for reading/writing");
- return NOTOK;
- }
-
- /*
- ** showproc is for mhshow and mhstore, though mhlist -debug
- ** prints it, too.
- */
- if (ct->c_showproc)
- free(ct->c_showproc);
- ct->c_showproc = getcpy("true");
-
- fseek(ce->ce_fp, 0L, SEEK_SET);
- *file = ce->ce_file;
- return fileno(ce->ce_fp);
-}
-
-
-static int
-readDigest(CT ct, char *cp)
-{
- int bitno, skip;
- unsigned long 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;
-
- for (ep = (dp = ct->c_digest)
- + sizeof(ct->c_digest) / sizeof(ct->c_digest[0]); *cp; cp++)
- switch (*cp) {
- default:
- if (skip || (*cp & 0x80) ||
- (value = b642nib[*cp & 0x7f])
- > 0x3f) {
- if (debugsw)
- fprintf(stderr, "invalid BASE64 encoding\n");
- return NOTOK;
- }
-
- bits |= value << bitno;
-test_end:
- if ((bitno -= 6) < 0) {
- if (dp + (3 - skip) > ep)
- goto invalid_digest;
- *dp++ = *b1;
- if (skip < 2) {
- *dp++ = *b2;
- if (skip < 1)
- *dp++ = *b3;
- }
- bitno = 18;
- bits = 0L;
- skip = 0;
- }
- break;
-
- case '=':
- if (++skip > 3)
- goto self_delimiting;
- goto test_end;
- }
- if (bitno != 18) {
- if (debugsw)
- fprintf(stderr, "premature ending (bitno %d)\n",
- bitno);
-
- return NOTOK;
- }
-self_delimiting:
- if (dp != ep) {
-invalid_digest:
- if (debugsw) {
- while (*cp)
- cp++;
- fprintf(stderr, "invalid MD5 digest (got %d octets)\n",
- (int)(cp - bp));
- }
-
- return NOTOK;
- }
-
- if (debugsw) {
- fprintf(stderr, "MD5 digest=");
- for (dp = ct->c_digest; dp < ep; dp++)
- fprintf(stderr, "%02x", *dp & 0xff);
- fprintf(stderr, "\n");
+ if (own_ct_fp) {
+ fclose(ct->c_fp);
+ ct->c_fp = NULL;
}
-
- return OK;
+ return NOTOK;
}