X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=uip%2Fmhbuild.c;h=c0320226daf06050cc6a303479e422f234c1a6e1;hp=cc319f5dcaa64c546df421d6eac21be3d2928d34;hb=HEAD;hpb=8d8f1c3abc586c005c904e52c4adbfe694d2201c diff --git a/uip/mhbuild.c b/uip/mhbuild.c index cc319f5..f9674a3 100644 --- a/uip/mhbuild.c +++ b/uip/mhbuild.c @@ -15,13 +15,16 @@ #include #include -#include #include -#include #include #include #include #include +#include +#include +#include +#include +#include #ifdef HAVE_SYS_TIME_H # include @@ -29,45 +32,26 @@ #include static struct swit switches[] = { -#define EBCDICSW 0 - { "ebcdicsafe", 0 }, -#define NEBCDICSW 1 - { "noebcdicsafe", 0 }, -#define HEADSW 2 - { "headers", 0 }, -#define NHEADSW 3 - { "noheaders", 0 }, -#define LISTSW 4 - { "list", 0 }, -#define NLISTSW 5 - { "nolist", 0 }, -#define RFC934SW 6 - { "rfc934mode", 0 }, -#define NRFC934SW 7 - { "norfc934mode", 0 }, -#define VERBSW 8 +#define VERBSW 0 { "verbose", 0 }, -#define NVERBSW 9 - { "noverbose", 0 }, -#define CONTENTIDSW 10 - { "contentid", 0 }, -#define NCONTENTIDSW 11 - { "nocontentid", 0 }, -#define VERSIONSW 12 - { "version", 0 }, -#define HELPSW 13 +#define NVERBSW 1 + { "noverbose", 2 }, +#define VERSIONSW 2 + { "Version", 0 }, +#define HELPSW 3 { "help", 0 }, -#define DEBUGSW 14 +#define DEBUGSW 4 { "debug", -5 }, { NULL, 0 } }; +char *version=VERSION; /* ** Directory to place tmp files. This must ** be set before these routines are called. */ -char *tmp; +extern char *tmp; pid_t xpid = 0; @@ -103,11 +87,6 @@ static CT build_mime(char *); int debugsw = 0; int verbosw = 0; -int ebcdicsw = 0; -int listsw = 0; -int rfc934sw = 0; -int contentidsw = 1; - /* ** Temporary files */ @@ -117,15 +96,12 @@ static int unlink_infile = 0; static char outfile[BUFSIZ]; static int unlink_outfile = 0; -static void unlink_done(int) NORETURN; +void unlink_done(); /* mhoutsbr.c */ int output_message(CT, char *); int output_message_fp(CT, FILE *, char*); -/* mhlistsbr.c */ -int list_all_messages(CT *, int, int, int); - /* mhmisc.c */ void set_endian(void); @@ -136,19 +112,18 @@ void free_content(CT); int main(int argc, char **argv) { - int headsw = 1; char *cp, buf[BUFSIZ]; char buffer[BUFSIZ], *compfile = NULL; char **argp, **arguments; - CT ct, cts[2]; + CT ct; FILE *fp = NULL; FILE *fp_out = NULL; - done = unlink_done; + if (atexit(unlink_done) != 0) { + adios(EX_OSERR, NULL, "atexit failed"); + } -#ifdef LOCALE setlocale(LC_ALL, ""); -#endif invo_name = mhbasename(argv[0]); /* read user profile/context */ @@ -160,10 +135,9 @@ 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"); + adios(EX_USAGE, NULL, "cannot specify both standard input and a file"); else compfile = cp; - listsw = 0; /* turn off -list if using std in/out */ verbosw = 0; /* turn off -verbose listings */ break; } @@ -171,52 +145,17 @@ main(int argc, char **argv) switch (smatch(++cp, switches)) { case AMBIGSW: ambigsw(cp, switches); - done(1); + exit(EX_USAGE); case UNKWNSW: - adios(NULL, "-%s unknown", cp); + adios(EX_USAGE, NULL, "-%s unknown", cp); case HELPSW: snprintf(buf, sizeof(buf), "%s [switches] file", invo_name); print_help(buf, switches, 1); - done(1); + exit(argc == 2 ? EX_OK : EX_USAGE); case VERSIONSW: print_version(invo_name); - done(1); - - case EBCDICSW: - ebcdicsw++; - continue; - case NEBCDICSW: - ebcdicsw = 0; - continue; - - case HEADSW: - headsw++; - continue; - case NHEADSW: - headsw = 0; - continue; - - case LISTSW: - listsw++; - continue; - case NLISTSW: - listsw = 0; - continue; - - case RFC934SW: - rfc934sw++; - continue; - case NRFC934SW: - rfc934sw = 0; - continue; - - case CONTENTIDSW: - contentidsw = 1; - continue; - case NCONTENTIDSW: - contentidsw = 0; - continue; + exit(argc == 2 ? EX_OK : EX_USAGE); case VERBSW: verbosw++; @@ -230,16 +169,13 @@ main(int argc, char **argv) } } if (compfile) - adios(NULL, "only one composition file allowed"); + adios(EX_USAGE, NULL, "only one composition file allowed"); else compfile = cp; } set_endian(); - if ((cp = getenv("MM_NOASK")) && strcmp(cp, "1")==0) - listsw = 0; - /* ** Check if we've specified an additional profile */ @@ -269,11 +205,11 @@ main(int argc, char **argv) if ((cp = context_find(nmhstorage)) && *cp) tmp = concat(cp, "/", invo_name, NULL); else - tmp = getcpy(toabsdir(invo_name)); + tmp = mh_xstrdup(toabsdir(invo_name)); /* Check if we have a file to process */ if (!compfile) - adios(NULL, "need to specify a %s composition file", + adios(EX_USAGE, NULL, "need to specify a %s composition file", invo_name); /* @@ -290,8 +226,6 @@ main(int argc, char **argv) /* 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_mktemp(invo_name, NULL, &fp_out), @@ -304,7 +238,7 @@ main(int argc, char **argv) /* output the temp file to standard output */ if ((fp = fopen(outfile, "r")) == NULL) - adios(outfile, "unable to open"); + adios(EX_IOERR, outfile, "unable to open"); while (fgets(buffer, BUFSIZ, fp)) fputs(buffer, stdout); fclose(fp); @@ -316,7 +250,7 @@ main(int argc, char **argv) unlink_outfile = 0; free_content(ct); - done(0); + exit(EX_OK); } /* @@ -325,8 +259,6 @@ main(int argc, char **argv) /* build the content structures for MIME message */ ct = build_mime(compfile); - cts[0] = ct; - cts[1] = NULL; /* output MIME message to this temporary file */ strncpy(outfile, m_mktemp2(compfile, invo_name, NULL, &fp_out), @@ -337,44 +269,37 @@ main(int argc, char **argv) output_message_fp(ct, fp_out, outfile); fclose(fp_out); - /* - ** List the message info - */ - if (listsw) - list_all_messages(cts, headsw, verbosw, debugsw); - /* Rename composition draft */ - snprintf(buffer, sizeof(buffer), "%s.orig", m_backup(compfile)); + snprintf(buffer, sizeof(buffer), "%s.orig", compfile); if (rename(compfile, buffer) == NOTOK) { - adios(compfile, "unable to rename comp draft %s to", buffer); + adios(EX_IOERR, buffer, "unable to rename draft %s to", compfile); } /* Rename output file to take its place */ if (rename(outfile, compfile) == NOTOK) { - advise(outfile, "unable to rename output %s to", compfile); + advise(compfile, "unable to rename output %s to", outfile); rename(buffer, compfile); - done(1); + exit(EX_IOERR); } unlink_outfile = 0; free_content(ct); - done(0); - return 1; + return 0; } -static void -unlink_done(int status) +void +unlink_done() { /* ** Check if we need to remove stray temporary files. */ - if (unlink_infile) + if (unlink_infile) { unlink(infile); - if (unlink_outfile) + } + if (unlink_outfile) { unlink(outfile); - - exit(status); + } } /* @@ -388,25 +313,28 @@ unlink_done(int status) static CT build_mime(char *infile) { - int compnum, state; - char buf[BUFSIZ], name[NAMESZ]; + enum state state; + struct field f = {{0}}; + int compnum; + char buf[BUFSIZ]; char *cp, *np, *vp; struct multipart *m; struct part **pp; CT ct; FILE *in; + HF hp; umask(~m_gmprot()); /* open the composition draft */ - if ((in = fopen(infile, "r")) == NULL) - adios(infile, "unable to open for reading"); + if ((in = fopen(infile, "r")) == NULL) { + adios(EX_IOERR, infile, "unable to open for reading"); + } /* ** Allocate space for primary (outside) content */ - if ((ct = (CT) calloc(1, sizeof(*ct))) == NULL) - adios(NULL, "out of memory"); + ct = mh_xcalloc(1, sizeof(*ct)); /* ** Allocate structure for handling decoded content @@ -420,93 +348,86 @@ build_mime(char *infile) ** draft into the linked list of header fields for ** the new MIME message. */ - 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; + case FLD2: compnum++; /* abort if draft has Mime-Version header field */ - if (!mh_strcasecmp(name, VRSN_FIELD)) - adios(NULL, "draft shouldn't contain %s: field", VRSN_FIELD); + if (!mh_strcasecmp(f.name, VRSN_FIELD)) { + adios(EX_CONFIG, NULL, "draft shouldn't contain %s: field", VRSN_FIELD); + } /* ** abort if draft has Content-Transfer-Encoding ** header field */ - if (!mh_strcasecmp(name, ENCODING_FIELD)) - adios(NULL, "draft shouldn't contain %s: field", ENCODING_FIELD); + if (!mh_strcasecmp(f.name, ENCODING_FIELD)) { + adios(EX_CONFIG, NULL, "draft shouldn't contain %s: field", ENCODING_FIELD); + } /* ignore any Content-Type fields in the header */ - if (!mh_strcasecmp(name, TYPE_FIELD)) { - while (state == FLDPLUS) - state = m_getfld(state, name, buf, - sizeof(buf), in); - goto finish_field; + if (!mh_strcasecmp(f.name, TYPE_FIELD)) { + continue; } - /* get copies of the buffers */ - np = getcpy(name); - vp = getcpy(buf); - - /* if necessary, get rest of field */ - while (state == FLDPLUS) { - state = m_getfld(state, name, buf, - sizeof(buf), in); - vp = add(buf, vp); /* add to prev value */ - } + /* add the header data to the list */ + add_header(ct, mh_xstrdup(f.name), mh_xstrdup(f.value)); - /* Now add the header data to the list */ - add_header(ct, np, vp); + continue; -finish_field: - /* if this wasn't the last hdr field, then continue */ - if (state != FLDEOF) - continue; - /* else fall... */ + case BODY2: + fseek(in, (long) (-strlen(f.value)), SEEK_CUR); + break; - case FILEEOF: - adios(NULL, "draft has empty body -- no directives!"); + case FILEEOF2: + adios(EX_CONFIG, NULL, "draft has empty body -- no directives!"); /* NOTREACHED */ - case BODY: - case BODYEOF: - fseek(in, (long) (-strlen(buf)), SEEK_CUR); - break; - - case LENERR: - case FMTERR: - adios(NULL, "message format error in component #%d", + case FMTERR2: + case IOERR2: + adios(EX_CONFIG, NULL, "message format error in component #%d", compnum); default: - adios(NULL, "getfld() returned %d", state); + adios(EX_SOFTWARE, NULL, "getfld() returned %d", state); } break; } /* + ** Iterate through the list of headers and call the function to + ** MIME-ify them if required. + */ + for (hp = ct->c_first_hf; hp != NULL; hp = hp->next) { + if (encode_rfc2047(hp->name, &hp->value, NULL)) { + adios(EX_DATAERR, NULL, "Unable to encode header \"%s\"", hp->name); + } + } + + /* ** Now add the MIME-Version header field ** to the list of header fields. */ - np = getcpy(VRSN_FIELD); + np = mh_xstrdup(VRSN_FIELD); vp = concat(" ", VRSN_VALUE, "\n", NULL); add_header(ct, np, vp); /* - ** We initally assume we will find multiple contents in the + ** We initially assume we will find multiple contents in the ** draft. So create a multipart/mixed content to hold everything. ** We can remove this later, if it is not needed. */ - if (get_ctinfo("multipart/mixed", ct, 0) == NOTOK) - done(1); + if (get_ctinfo("multipart/mixed", ct, 0) == NOTOK) { + exit(EX_DATAERR); + } ct->c_type = CT_MULTIPART; ct->c_subtype = MULTI_MIXED; - ct->c_file = getcpy(infile); + ct->c_file = mh_xstrdup(infile); - if ((m = (struct multipart *) calloc(1, sizeof(*m))) == NULL) - adios(NULL, "out of memory"); + m = (struct multipart *) mh_xcalloc(1, sizeof(*m)); ct->c_ctparams = (void *) m; pp = &m->mp_parts; @@ -525,8 +446,7 @@ finish_field: if (!p) continue; - if ((part = (struct part *) calloc(1, sizeof(*part))) == NULL) - adios(NULL, "out of memory"); + part = mh_xcalloc(1, sizeof(*part)); *pp = part; pp = &part->mp_next; part->mp_part = p; @@ -540,7 +460,7 @@ finish_field: /* check if any contents were found */ if (!m->mp_parts) - adios(NULL, "no content directives found"); + adios(EX_OSERR, NULL, "no content directives found"); /* ** If only one content was found, then remove and @@ -571,7 +491,7 @@ finish_field: compose_content(ct); if ((cp = strchr(prefix, 'a')) == NULL) - adios(NULL, "internal error(4)"); + adios(EX_SOFTWARE, NULL, "internal error(4)"); /* ** Scan the contents. Choose a transfer encoding, and @@ -583,7 +503,7 @@ finish_field: (*cp)++; } else { if (*++cp == 0) - adios(NULL, "giving up trying to find a unique delimiter string"); + adios(EX_SOFTWARE, NULL, "giving up trying to find a unique delimiter string"); else (*cp)++; } @@ -606,8 +526,7 @@ init_decoded_content(CT ct) { 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 = open7Bit; /* since unencoded */ @@ -656,7 +575,6 @@ user_content(FILE *in, char *file, char *buf, CT *ctp) char buffer[BUFSIZ]; struct multipart *m; struct part **pp; - struct stat st; struct str2init *s2i; CI ci; CT ct; @@ -668,8 +586,7 @@ user_content(FILE *in, char *file, char *buf, CT *ctp) } /* allocate basic Content structure */ - if ((ct = (CT) calloc(1, sizeof(*ct))) == NULL) - adios(NULL, "out of memory"); + ct = mh_xcalloc(1, sizeof(*ct)); *ctp = ct; /* allocate basic structure for handling decoded content */ @@ -697,10 +614,10 @@ user_content(FILE *in, char *file, char *buf, CT *ctp) cp = m_mktemp2(NULL, invo_name, NULL, &out); if (cp == NULL) - adios("mhbuild", "unable to create temporary file"); + adios(EX_CANTCREAT, "mhbuild", "unable to create temporary file"); /* use a temp file to collect the plain text lines */ - ce->ce_file = getcpy(cp); + ce->ce_file = mh_xstrdup(cp); ce->ce_unlink = 1; if (buf[0] == '#' && buf[1] == '<') { @@ -725,7 +642,7 @@ user_content(FILE *in, char *file, char *buf, CT *ctp) again_descr: ct->c_descr = add(buffer + i + 1, ct->c_descr); if (!fgetstr(buffer, sizeof(buffer) - 1, in)) - adios(NULL, "end-of-file after %s: field in plaintext", DESCR_FIELD); + adios(EX_DATAERR, NULL, "end-of-file after %s: field in plaintext", DESCR_FIELD); switch (buffer[0]) { case ' ': case '\t': @@ -733,7 +650,7 @@ again_descr: goto again_descr; case '#': - adios(NULL, "#-directive after %s: field in plaintext", DESCR_FIELD); + adios(EX_DATAERR, NULL, "#-directive after %s: field in plaintext", DESCR_FIELD); /* NOTREACHED */ default: @@ -748,7 +665,7 @@ again_descr: again_dispo: ct->c_dispo = add(buffer + i + 1, ct->c_dispo); if (!fgetstr(buffer, sizeof(buffer) - 1, in)) - adios(NULL, "end-of-file after %s: field in plaintext", DISPO_FIELD); + adios(EX_DATAERR, NULL, "end-of-file after %s: field in plaintext", DISPO_FIELD); switch (buffer[0]) { case ' ': case '\t': @@ -756,7 +673,7 @@ again_dispo: goto again_dispo; case '#': - adios(NULL, "#-directive after %s: field in plaintext", DISPO_FIELD); + adios(EX_DATAERR, NULL, "#-directive after %s: field in plaintext", DISPO_FIELD); /* NOTREACHED */ default: @@ -784,13 +701,11 @@ rock_and_roll: } } - if (listsw) - ct->c_end = ftell(out); fclose(out); /* parse content type */ if (get_ctinfo(content, ct, inlineD) == NOTOK) - done(1); + exit(EX_DATAERR); for (s2i = str2cts; s2i->si_key; s2i++) if (!mh_strcasecmp(ci->ci_type, s2i->si_key)) @@ -809,7 +724,7 @@ rock_and_roll: } /* else fall... */ case CT_MULTIPART: - adios(NULL, "it doesn't make sense to define an in-line %s content", + adios(EX_DATAERR, NULL, "it doesn't make sense to define an in-line %s content", ct->c_type == CT_MESSAGE ? "message" : "multipart"); /* NOTREACHED */ @@ -832,13 +747,13 @@ call_init: */ if (buf[1] == '@') { - adios(NULL, "The #@ directive i.e. message/external-body " + adios(EX_DATAERR, NULL, "The #@ directive i.e. message/external-body " "is not supported anymore."); } /* parse directive */ if (get_ctinfo(buf+1, ct, 1) == NOTOK) - done(1); + exit(EX_DATAERR); /* check directive against the list of MIME types */ for (s2i = str2cts; s2i->si_key; s2i++) @@ -853,22 +768,22 @@ call_init: */ if (s2i->si_key) { if (!ci->ci_subtype) - adios(NULL, "missing subtype in \"#%s\"", ci->ci_type); + adios(EX_DATAERR, NULL, "missing subtype in \"#%s\"", ci->ci_type); switch (ct->c_type = s2i->si_val) { case CT_MULTIPART: - adios(NULL, "use \"#begin ... #end\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); + adios(EX_DATAERR, NULL, "use \"#begin ... #end\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); /* NOTREACHED */ case CT_MESSAGE: if (!mh_strcasecmp(ci->ci_subtype, "partial") || !mh_strcasecmp(ci->ci_subtype, "external-body")) { - adios(NULL, "sorry, \"#%s/%s\" isn't supported", ci->ci_type, ci->ci_subtype); + adios(EX_DATAERR, NULL, "sorry, \"#%s/%s\" isn't supported", ci->ci_type, ci->ci_subtype); } use_forw: - adios(NULL, "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); - /* NOTREACHED */ + admonish(NULL, "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); + /* FALL */ default: if ((ct->c_ctinitfnx = s2i->si_init)) @@ -883,17 +798,15 @@ use_forw: for (cp = ci->ci_magic + 1; isspace(*cp); cp++) continue; if (!*cp) - adios(NULL, "empty pipe command for #%s directive", ci->ci_type); - cp = getcpy(cp); - free(ci->ci_magic); + adios(EX_DATAERR, NULL, "empty pipe command for #%s directive", ci->ci_type); + cp = mh_xstrdup(cp); + mh_free0(&(ci->ci_magic)); ci->ci_magic = cp; } else { /* record filename of decoded contents */ ce->ce_file = ci->ci_magic; if (access(ce->ce_file, R_OK) == NOTOK) - adios("reading", "unable to access %s for", ce->ce_file); - if (listsw && stat(ce->ce_file, &st) != NOTOK) - ct->c_end = (long) st.st_size; + adios(EX_IOERR, "reading", "unable to access %s for", ce->ce_file); ci->ci_magic = NULL; } return OK; @@ -911,10 +824,10 @@ use_forw: if ((cp = context_find(buffer)) == NULL || *cp == '\0') { content_error(NULL, ct, "don't know how to compose content"); - done(1); + exit(EX_CONFIG); } } - ci->ci_magic = getcpy(cp); + ci->ci_magic = mh_xstrdup(cp); return OK; } @@ -947,25 +860,25 @@ use_forw: cp = *ap; if (*cp == '+' || *cp == '@') { if (folder) - adios(NULL, "only one folder per #forw directive"); + adios(EX_USAGE, NULL, "only one folder per #forw directive"); else - folder = getcpy(expandfol(cp)); + folder = mh_xstrdup(expandfol(cp)); } } /* else, use the current folder */ if (!folder) - folder = getcpy(getcurfol()); + folder = mh_xstrdup(getcurfol()); if (!(mp = folder_read(folder))) - adios(NULL, "unable to read folder %s", folder); + adios(EX_IOERR, NULL, "unable to read folder %s", folder); for (ap = arguments; *ap; ap++) { cp = *ap; if (*cp != '+' && *cp != '@') if (!m_convert(mp, cp)) - done(1); + exit(EX_USAGE); } - free(folder); + mh_free0(&folder); free_ctinfo(ct); /* @@ -977,13 +890,11 @@ use_forw: if (mp->numsel > 1) { /* we are forwarding multiple messages */ if (get_ctinfo("multipart/digest", ct, 0) == NOTOK) - done(1); + exit(EX_DATAERR); ct->c_type = CT_MULTIPART; ct->c_subtype = MULTI_DIGEST; - 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; pp = &m->mp_parts; @@ -993,27 +904,21 @@ use_forw: CT p; CE pe; - if ((p = (CT) calloc(1, sizeof(*p))) - == NULL) - adios(NULL, "out of memory"); + p = mh_xcalloc(1, sizeof(*p)); init_decoded_content(p); pe = p->c_cefile; if (get_ctinfo("message/rfc822", p, 0) == NOTOK) - done(1); + exit(EX_DATAERR); p->c_type = CT_MESSAGE; p->c_subtype = MESSAGE_RFC822; snprintf(buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum); - pe->ce_file = getcpy(buffer); - if (listsw && stat(pe->ce_file, &st) - != NOTOK) - p->c_end = (long) st.st_size; + pe->ce_file = mh_xstrdup(buffer); - if ((part = (struct part *) calloc(1, sizeof(*part))) == NULL) - adios(NULL, "out of memory"); + part = mh_xcalloc(1, sizeof(*part)); *pp = part; pp = &part->mp_next; part->mp_part = p; @@ -1022,16 +927,14 @@ use_forw: } else { /* we are forwarding one message */ if (get_ctinfo("message/rfc822", ct, 0) == NOTOK) - done(1); + exit(EX_DATAERR); ct->c_type = CT_MESSAGE; ct->c_subtype = MESSAGE_RFC822; msgnum = mp->lowsel; snprintf(buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum); - ce->ce_file = getcpy(buffer); - if (listsw && stat(ce->ce_file, &st) != NOTOK) - ct->c_end = (long) st.st_size; + ce->ce_file = mh_xstrdup(buffer); } folder_free(mp); /* free folder/message structure */ @@ -1070,12 +973,11 @@ use_forw: free_ctinfo(ct); snprintf(buffer, sizeof(buffer), "multipart/%s", cp); if (get_ctinfo(buffer, ct, 0) == NOTOK) - done(1); + exit(EX_DATAERR); ct->c_type = CT_MULTIPART; ct->c_subtype = vrsn; - 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; pp = &m->mp_parts; @@ -1085,15 +987,13 @@ use_forw: if (user_content(in, file, buffer, &p) == DONE) { if (!m->mp_parts) - adios(NULL, "empty \"#begin ... #end\" sequence"); + adios(EX_DATAERR, NULL, "empty \"#begin ... #end\" sequence"); return OK; } if (!p) continue; - if ((part = (struct part *) - calloc(1, sizeof(*part))) == NULL) - adios(NULL, "out of memory"); + part = mh_xcalloc(1, sizeof(*part)); *pp = part; pp = &part->mp_next; part->mp_part = p; @@ -1105,7 +1005,7 @@ use_forw: /* ** Unknown directive */ - adios(NULL, "unknown directive \"#%s\"", ci->ci_type); + adios(EX_DATAERR, NULL, "unknown directive \"#%s\"", ci->ci_type); return NOTOK; /* NOT REACHED */ } @@ -1123,49 +1023,13 @@ set_id(CT ct, int top) snprintf(msgid, sizeof(msgid), "<%d.%ld.%%d@%s>\n", (int) getpid(), (long) clock, LocalName()); partno = 0; - msgfmt = getcpy(msgid); + msgfmt = mh_xstrdup(msgid); } snprintf(msgid, sizeof(msgid), msgfmt, top ? 0 : ++partno); - ct->c_id = getcpy(msgid); + ct->c_id = mh_xstrdup(msgid); } -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 -}; - - /* ** Fill out, or expand the various contents in the composition ** draft. Read-in any necessary files. Parse and execute any @@ -1200,45 +1064,10 @@ compose_content(CT ct) CT p = part->mp_part; sprintf(pp, "%d", partnum); - p->c_partno = getcpy(partnam); + p->c_partno = mh_xstrdup(partnam); if (compose_content(p) == NOTOK) return NOTOK; } - - /* - ** If the -rfc934mode switch is given, then check all - ** the subparts of a multipart/digest. If they are all - ** message/rfc822, then mark this content and all - ** subparts with the rfc934 compatibility mode flag. - */ - if (rfc934sw && ct->c_subtype == MULTI_DIGEST) { - int is934 = 1; - - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; - - if (p->c_subtype != MESSAGE_RFC822) { - is934 = 0; - break; - } - } - ct->c_rfc934 = is934; - for (part = m->mp_parts; part; part = part->mp_next) { - CT p = part->mp_part; - - if ((p->c_rfc934 = is934)) - p->c_end++; - } - } - - if (listsw) { - ct->c_end = (partnum = strlen(prefix) + 2) + 2; - if (ct->c_rfc934) - ct->c_end += 1; - - for (part = m->mp_parts; part; part = part->mp_next) - ct->c_end += part->mp_part->c_end + partnum; - } } break; @@ -1260,13 +1089,13 @@ compose_content(CT ct) char *tfile = NULL; if (!(cp = ci->ci_magic)) - adios(NULL, "internal error(5)"); + adios(EX_SOFTWARE, NULL, "internal error(5)"); tfile = m_mktemp2(NULL, invo_name, NULL, NULL); if (tfile == NULL) { - adios("mhbuild", "unable to create temporary file"); + adios(EX_CANTCREAT, "mhbuild", "unable to create temporary file"); } - ce->ce_file = getcpy(tfile); + ce->ce_file = mh_xstrdup(tfile); ce->ce_unlink = 1; xstdout = 0; @@ -1352,11 +1181,11 @@ raw: vec[3] = NULL; if ((out = fopen(ce->ce_file, "w")) == NULL) - adios(ce->ce_file, "unable to open for writing"); + adios(EX_IOERR, ce->ce_file, "unable to open for writing"); switch (child_id = fork()) { case NOTOK: - adios("fork", "unable to fork"); + adios(EX_OSERR, "fork", "unable to fork"); /* NOTREACHED */ case OK: @@ -1366,24 +1195,16 @@ raw: execvp("/bin/sh", vec); fprintf(stderr, "unable to exec "); perror("/bin/sh"); - _exit(-1); + _exit(EX_OSERR); /* NOTREACHED */ default: fclose(out); if (pidXwait(child_id, NULL)) - done(1); + exit(EX_SOFTWARE); break; } } - - /* Check size of file */ - if (listsw && ct->c_end == 0L) { - struct stat st; - - if (stat(ce->ce_file, &st) != NOTOK) - ct->c_end = (long) st.st_size; - } break; } @@ -1408,11 +1229,10 @@ static int scan_content(CT ct) { int len; - int check8bit = 0, contains8bit = 0; /* check if contains 8bit data */ - int checklinelen = 0, linelen = 0; /* check for long lines */ - int checkboundary = 0, boundaryclash = 0; /* check if clashes with multipart boundary */ - int checklinespace = 0, linespace = 0; /* check if any line ends with space */ - int checkebcdic = 0, ebcdicunsafe = 0; /* check if contains ebcdic unsafe characters */ + int check8bit = 0, contains8bit = 0; + int checklinelen = 0, linelen = 0; + int checkboundary = 0, boundaryclash = 0; + int checklinespace = 0, linespace = 0; /* trailing whitespace */ unsigned char *cp = NULL, buffer[BUFSIZ]; struct text *t = NULL; FILE *in = NULL; @@ -1458,42 +1278,22 @@ scan_content(CT ct) case CT_TEXT: check8bit = 1; checkboundary = 1; - if (ct->c_subtype == TEXT_PLAIN) { - checkebcdic = 0; - checklinelen = 0; - checklinespace = 0; - } else { - checkebcdic = ebcdicsw; - checklinelen = 1; - checklinespace = 1; - } - break; - - case CT_APPLICATION: - check8bit = 1; - checkebcdic = ebcdicsw; checklinelen = 1; checklinespace = 1; - checkboundary = 1; break; case CT_MESSAGE: check8bit = 0; - checkebcdic = 0; checklinelen = 0; checklinespace = 0; checkboundary = 1; break; + case CT_APPLICATION: case CT_AUDIO: case CT_IMAGE: case CT_VIDEO: - /* - ** Don't check anything for these types, - ** since we are forcing use of base64. - */ check8bit = 0; - checkebcdic = 0; checklinelen = 0; checklinespace = 0; checkboundary = 0; @@ -1505,13 +1305,10 @@ scan_content(CT ct) */ if (check8bit || checklinelen || checklinespace || checkboundary) { if ((in = fopen(ce->ce_file, "r")) == NULL) - adios(ce->ce_file, "unable to open for reading"); + adios(EX_IOERR, ce->ce_file, "unable to open for reading"); len = strlen(prefix); while (fgets(buffer, sizeof(buffer) - 1, in)) { - /* - ** Check for 8bit data. - */ if (check8bit) { for (cp = buffer; *cp; cp++) { if (!isascii(*cp)) { @@ -1519,30 +1316,14 @@ scan_content(CT ct) /* no need to keep checking */ check8bit = 0; } - /* - ** Check if character is ebcdic-safe. - ** We only check this if also checking - ** for 8bit data. - */ - if (checkebcdic && !ebcdicsafe[*cp & 0xff]) { - ebcdicunsafe = 1; - /* no need to keep checking */ - checkebcdic = 0; - } } } - /* - ** Check line length. - */ if (checklinelen && (strlen(buffer) > CPERLIN + 1)) { linelen = 1; checklinelen = 0; /* no need to keep checking */ } - /* - ** Check if line ends with a space. - */ if (checklinespace && (cp = buffer + strlen(buffer) - 2) > buffer && isspace(*cp)) { @@ -1596,7 +1377,7 @@ scan_content(CT ct) NULL); } else { t->tx_charset = CHARSET_USASCII; - *ap = getcpy("charset=us-ascii"); + *ap = mh_xstrdup("charset=us-ascii"); } cp = strchr(*ap++, '='); @@ -1605,30 +1386,25 @@ scan_content(CT ct) *ep = cp; } - if (contains8bit || ebcdicunsafe || linelen || linespace) + if (contains8bit || linelen || linespace) ct->c_encoding = CE_QUOTED; else ct->c_encoding = CE_7BIT; break; - case CT_APPLICATION: - /* For application type, use base64, except when postscript */ - if (contains8bit || ebcdicunsafe || linelen || linespace) - ct->c_encoding = (ct->c_subtype == - APPLICATION_POSTSCRIPT) ? - CE_QUOTED : CE_BASE64; - else - ct->c_encoding = CE_7BIT; - break; - case CT_MESSAGE: ct->c_encoding = CE_7BIT; break; + case CT_APPLICATION: case CT_AUDIO: case CT_IMAGE: case CT_VIDEO: - /* For audio, image, and video contents, just use base64 */ + /* + ** Forcing use of base64, because these types likely + ** contain binary data and NUL bytes. Don't care about + ** files that would be clean. + */ ct->c_encoding = CE_BASE64; break; } @@ -1663,26 +1439,16 @@ build_headers(CT ct) ep = ci->ci_values; snprintf(buffer, sizeof(buffer), "boundary=%s%d", prefix, level++); - cp = strchr(*ap++ = getcpy(buffer), '='); + cp = strchr(*ap++ = mh_xstrdup(buffer), '='); *ap = NULL; *cp++ = '\0'; *ep = cp; } /* - ** Skip the output of Content-Type, parameters, content - ** description and disposition, and Content-ID if the - ** content is of type "message" and the rfc934 compatibility - ** flag is set (which means we are inside multipart/digest - ** and the switch -rfc934mode was given). - */ - if (ct->c_type == CT_MESSAGE && ct->c_rfc934) - goto skip_headers; - - /* ** output the content type and subtype */ - np = getcpy(TYPE_FIELD); + np = mh_xstrdup(TYPE_FIELD); vp = concat(" ", ci->ci_type, "/", ci->ci_subtype, NULL); /* keep track of length of line */ @@ -1729,10 +1495,10 @@ build_headers(CT ct) add_header(ct, np, vp); /* - ** output the Content-ID, unless disabled by -nocontentid + ** output the Content-ID */ - if (contentidsw && ct->c_id) { - np = getcpy(ID_FIELD); + if (ct->c_id) { + np = mh_xstrdup(ID_FIELD); vp = concat(" ", ct->c_id, NULL); add_header(ct, np, vp); } @@ -1741,8 +1507,11 @@ build_headers(CT ct) ** output the Content-Description */ if (ct->c_descr) { - np = getcpy(DESCR_FIELD); + np = mh_xstrdup(DESCR_FIELD); vp = concat(" ", ct->c_descr, NULL); + if (encode_rfc2047(DESCR_FIELD, &vp, NULL)) { + adios(EX_DATAERR, NULL, "Unable to encode %s header", DESCR_FIELD); + } add_header(ct, np, vp); } @@ -1750,12 +1519,11 @@ build_headers(CT ct) ** output the Content-Disposition */ if (ct->c_dispo) { - np = getcpy(DISPO_FIELD); + np = mh_xstrdup(DISPO_FIELD); vp = concat(" ", ct->c_dispo, NULL); add_header(ct, np, vp); } -skip_headers: /* ** output the Content-Transfer-Encoding */ @@ -1766,42 +1534,42 @@ skip_headers: case CE_8BIT: if (ct->c_type == CT_MESSAGE) - adios(NULL, "internal error, invalid encoding"); + adios(EX_DATAERR, NULL, "internal error, invalid encoding"); - np = getcpy(ENCODING_FIELD); + np = mh_xstrdup(ENCODING_FIELD); vp = concat(" ", "8bit", "\n", NULL); add_header(ct, np, vp); break; case CE_QUOTED: if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) - adios(NULL, "internal error, invalid encoding"); + adios(EX_DATAERR, NULL, "internal error, invalid encoding"); - np = getcpy(ENCODING_FIELD); + np = mh_xstrdup(ENCODING_FIELD); vp = concat(" ", "quoted-printable", "\n", NULL); add_header(ct, np, vp); break; case CE_BASE64: if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) - adios(NULL, "internal error, invalid encoding"); + adios(EX_DATAERR, NULL, "internal error, invalid encoding"); - np = getcpy(ENCODING_FIELD); + np = mh_xstrdup(ENCODING_FIELD); vp = concat(" ", "base64", "\n", NULL); add_header(ct, np, vp); break; case CE_BINARY: if (ct->c_type == CT_MESSAGE) - adios(NULL, "internal error, invalid encoding"); + adios(EX_DATAERR, NULL, "internal error, invalid encoding"); - np = getcpy(ENCODING_FIELD); + np = mh_xstrdup(ENCODING_FIELD); vp = concat(" ", "binary", "\n", NULL); add_header(ct, np, vp); break; default: - adios(NULL, "unknown transfer encoding in content"); + adios(EX_DATAERR, NULL, "unknown transfer encoding in content"); break; }