MH_TEST_DIR="@abs_builddir@/test/testdir" \
nmhlibexecdir="$(nmhlibexecdir)" bindir="$(bindir)" \
mandir="$(mandir)" nmhetcdir="$(nmhetcdir)" \
+ nmhetcdirinst="@nmhetcdirinst@$(nmhetcdir)" \
supported_locks="$(supported_locks)" \
default_locking="${default_locking}" \
MULTIBYTE_ENABLED=$(MULTIBYTE_ENABLED) \
check_SCRIPTS = test/common.sh
check_PROGRAMS = test/getfullname test/getcanon test/fakepop test/fakesmtp \
test/getcwidth
-DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1
+
+## The location of installed nmhetcdir is, for all purposes except
+## distcheck, $nmhetcdir. For distcheck, prepend $MH_INST_DIR (from
+## test/common.sh.in), which is based on $MH_TEST_DIR (from
+## $TESTS_ENVIRONMENT).
+DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1 \
+ NMHETCDIRINST='$${abs_builddir}/test/testdir/inst'
##
## Stuff that should be cleaned via "make clean"
config/sbr_libmh_a-config.$(OBJEXT) sbr/sbr_libmh_a-mts.$(OBJEXT): Makefile
-sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETCDIR='"$(nmhetcdir)"' \
+sbr_libmh_a_CPPFLAGS = -I./sbr -DNMHETCDIR='"@nmhetcdirinst@$(nmhetcdir)"' \
-DMAILSPOOL='"$(mailspool)"' \
-DSENDMAILPATH='"$(sendmailpath)"' -DNMHBINDIR='"$(bindir)"' \
-DNMHLIBEXECDIR='"$(nmhlibexecdir)"'
'; sed "s/\( \)int i;/\1yy_size_t i;/" $@ >$@.tmp && mv -f $@.tmp $@'])
AC_SUBST([LFLAGS])])
+dnl ------------------
+dnl FOR INTERNAL USE by the NMH test suite
+dnl ------------------
+AC_ARG_VAR([NMHETCDIRINST], [for internal use by nmh test suite])
+AS_IF([test -n "$NMHETCDIRINST"], [nmhetcdirinst=$NMHETCDIRINST]
+ AC_SUBST([nmhetcdirinst]))
+
dnl ----------------
dnl CHECK STRUCTURES
dnl ----------------
- When building from source, configure will derive ${prefix} from an existing
nmh installation if it finds one in your $PATH.
- Added getmymbox and getmyaddr mh-format(5) function escapes.
-- The -changecur and -nochangecur switches have been added to mhfixmsg(1).
+- New -changecur, -nochangecur, and -fixtype switches have been added
+ to mhfixmsg(1).
- mhfixmsg now removes an extraneous trailing semicolon from header
parameter lists.
- Added -convertargs switch to repl(1), to pass arguments to programs
void free_content (CT);
char *ct_type_str (int);
char *ct_subtype_str (int, int);
+int ct_str_type (const char *);
+int ct_str_subtype (int, const char *);
const struct str2init *get_ct_init (int);
const char *ce_str (int);
const struct str2init *get_ce_method (const char *);
*
*/
void unquote_string(const char *input, char *output);
-int uprf (char *, char *);
+int uprf (const char *, const char *);
int vfgets (FILE *, char **);
/*
-.TH MH-PROFILE %manext5% "April 18, 2014" "%nmhversion%"
+.TH MH-PROFILE %manext5% "December 21, 2014" "%nmhversion%"
.\"
.\" %nmhwarning%
.\"
component can only appear once. Multiple appearances with trigger a
warning that all appearances after the first are ignored.
.PP
+Some MH programs, including
+.BR mhbuild ,
+.BR mhshow ,
+and
+.BR mhstore ,
+have specific profile components that are described in their respective
+man pages. Each component name begins with the name of the program and
+is followed by a dash.
+.PP
.BR Path :
Mail
.RS 5
.SH "SEE ALSO"
.IR environ (5),
.IR mh-sequence (5),
+.IR mhbuild (1),
+.IR mhshow (1),
+.IR mhstore (1),
.IR nmh (7)
.SH HISTORY
The
-.TH MHFIXMSG %manext1% "November 30, 2014" "%nmhversion%"
+.TH MHFIXMSG %manext1% "December 25, 2014" "%nmhversion%"
.\"
.\" %nmhwarning%
.\"
.RB [ \-replacetextplain " | " \-noreplacetextplain ]
.RB [ \-fixboundary " | " \-nofixboundary ]
.RB [ \-fixcte " | " \-nofixcte ]
+.RB [ \-fixtype
+.IR mimetype ]
.RB [ \-outfile
.IR outfile ]
.RB [ \-rmmproc
.B nmh
programs that parse MIME messages.
.PP
+The
+.B \-fixtype
+switch ensures that each part of the message has the correct MIME type
+shown in its Content-Type header. It may be repeated. It is
+typically used to replace \*(lqapplication/octet-stream\*(rq with a
+more descriptive MIME type. It may not be used for multipart and
+message types.
+.PP
.B mhfixmsg
applies one transformation unconditionally: it removes an extraneous
trailing semicolon from the parameter lists of MIME header fields.
\-reformat text parts that are not text/plain
\-fixboundary outermost multipart part
\-fixcte multipart part
+\-fixtype all except multipart and message parts
.fi
.RE
.PP
charstring_push_back (rev, '?');
} else if (num < 0 && wid > 0) {
/* Shouldn't need the wid > 0 check, that's why the condition
- at the top checks wid < max-1 when num < 0. */
- charstring_push_back (rev, '-');
+ at the top checks wid < max-1 when num < 0. */
--wid;
+ if (fill == ' ') {
+ charstring_push_back (rev, '-');
+ }
}
while (wid-- > 0 && fill != 0) {
charstring_push_back (rev, fill);
}
+ if (num < 0 && fill == '0') {
+ charstring_push_back (rev, '-');
+ }
{
/* Output the string in reverse. */
#include <h/mh.h>
#include <h/signals.h>
-#include <setjmp.h>
#ifdef READLINE_SUPPORT
#include <readline/readline.h>
if ((mimeencoding = get_file_info(MIMEENCODINGPROC, file_name))) {
content_type = concat(mimetype, "; charset=", mimeencoding,
NULL);
+ free (mimetype);
} else {
- content_type = strdup(mimetype);
+ content_type = mimetype;
}
} else {
- content_type = strdup(mimetype);
+ content_type = mimetype;
}
#else /* MIMEENCODINGPROC */
- content_type = strdup(mimetype);
+ content_type = mimetype;
#endif /* MIMEENCODINGPROC */
}
#endif /* MIMETYPEPROC */
int
-uprf (char *c1, char *c2)
+uprf (const char *c1, const char *c2)
{
int c, mask;
-# Common helper routines for test shell scripts -- intended to be sourced by them
+# Common helper routines for test shell scripts -- to be sourced by them
# @configure_input@
-#### The following exported variables are set by "make check". Ensure
+#### The following variables are set by "make check". Ensure
#### that they are set here so that individual tests can be run
#### outside of make. Requires that MH_OBJ_DIR be set on entry.
test -z "$MH_TEST_DIR" && MH_TEST_DIR="$MH_OBJ_DIR/test/testdir"
+test -z "$MH_INST_DIR" && MH_INST_DIR="${MH_TEST_DIR}/inst"
test -z "$prefix" && prefix=@prefix@
test -z "$datarootdir" && datarootdir=@datarootdir@
test -z "$exec_prefix" && exec_prefix=@exec_prefix@
-test -z "$nmhexecdir" && nmhexecdir="@libexecdir@/nmh"
test -z "$bindir" && bindir="@bindir@"
test -z "$mandir" && mandir="@mandir@"
test -z "$nmhetcdir" && nmhetcdir="@sysconfdir@/nmh"
+#### The following doesn't support running the distcheck version of
+#### test-mhparam standalone, but only via make distcheck.
+test -z "$nmhetcdirinst" && nmhetcdirinst="@nmhetcdirinst@$nmhetcdir"
+test -z "$nmhlibexecdir" && nmhlibexecdir="@libexecdir@/nmh"
test -z "$supported_locks" && supported_locks="@supported_locks@"
test -z "$default_locking" && default_locking="@default_locking@"
test -z "$MULTIBYTE_ENABLED" && MULTIBYTE_ENABLED="@MULTIBYTE_ENABLED@"
test -z "$ICONV_ENABLED" && ICONV_ENABLED="@ICONV_ENABLED@"
-export MH_TEST_DIR nmhexecdir bindir mandir nmhetcdir
-export MULTIBYTE_ENABLED ICONV_ENABLED
-
-test -z "$MH_INST_DIR" && MH_INST_DIR="${MH_TEST_DIR}/inst"
-export MH_INST_DIR
unset MAILDROP MHBUILD MHCONTEXT MHMTSUSERCONF MHN MHSHOW MHSTORE
unset MHLDEBUG MHPDEBUG MHWDEBUG PAGER
{
MH="${MH_TEST_DIR}/Mail/.mh_profile"
MHMTSCONF="${MH_INST_DIR}${nmhetcdir}/mts.conf"
- MH_LIBEXEC_DIR="${MH_INST_DIR}${nmhexecdir}"
+ MH_LIBEXEC_DIR="${MH_INST_DIR}${nmhlibexecdir}"
export MH MHMTSCONF MH_LIBEXEC_DIR
#
showproc: ${MH_LIBEXEC_DIR}/mhl
EOF
- for f in MailAliases components digestcomps distcomps forwcomps \
- mhical.12hour mhical.24hour mhl.body mhl.digest mhl.format \
- mhl.forward mhl.headers mhl.reply mhl.replywithoutbody \
- mhn.defaults rcvdistcomps replcomps replgroupcomps \
- scan.MMDDYY scan.YYYYMMDD scan.curses scan.default \
- scan.highlighted scan.mailx scan.nomime scan.size scan.time \
- scan.timely scan.unseen
- do
- cp "${MH_INST_DIR}${nmhetcdir}/${f}" "${MH_TEST_DIR}/Mail" || exit 1
- done
+ if test -z '@nmhetcdirinst@'; then
+ #### This isn't used with make distcheck, so that we can use it to
+ #### be sure that etc files are not used from an existing nmh
+ #### installation.
+ #### posh doesn't like "${MH_INST_DIR}${nmhetcdir}"/*, so cd to
+ #### the directory and provide an argument without quotes to cp.
+ (cd "${MH_INST_DIR}${nmhetcdir}/" && cp * "${MH_TEST_DIR}/Mail")
+ fi
folder -create +inbox > /dev/null
# create 10 basic messages
check $expected $actual 'keep first'
# check -form
-run_prog $fmtdump -form "$MH_TEST_DIR/Mail/scan.default" >$actual 2>&1
+run_prog $fmtdump -form "$MH_INST_DIR${nmhetcdir}/scan.default" >$actual 2>&1
check $expected $actual
# check -format
. "$MH_OBJ_DIR/test/common.sh"
setup_test
-expected="$MH_TEST_DIR/$$.expected"
-actual="$MH_TEST_DIR/$$.actual"
+expected="$MH_TEST_DIR/test-functions$$.expected"
+actual="$MH_TEST_DIR/test-functions$$.actual"
# check sday when day of week is specified
-echo 1 >"$expected"
+printf '1\n' >"$expected"
fmttest -raw -format '%(sday{text})' 'Fri Sep 12 20:02 2014' >"$actual"
check "$expected" "$actual"
# check sday when day of week is not specified
-echo 0 >"$expected"
+printf '0\n' >"$expected"
fmttest -raw -format '%(sday{text})' 'Sep 12 20:02 2014' >"$actual"
check "$expected" "$actual"
+# check negative number, without padding
+printf '%s\n' ' -42' >"$expected"
+fmttest -raw -format '%4(minus -42)' 0 >"$actual"
+check "$expected" "$actual"
+
+# check negative number, with padding
+# Output was "0-42" with nmh 1.6 and earlier.
+printf '%s\n' -042 >"$expected"
+fmttest -raw -format '%04(minus -42)' 0 >"$actual"
+check "$expected" "$actual"
+
exit $failed
MH_OBJ_DIR=`cd $srcdir && pwd`; export MH_OBJ_DIR
fi
-. "${srcdir}/test/post/test-post-common.sh"
+. "${MH_OBJ_DIR}/test/common.sh"
+
+setup_test
#### Make sure that html-to-text conversion is what we expect.
require_locale en_US.utf-8 en_US.utf8
actual="$MH_TEST_DIR/test-mhfixmsg$$.actual"
actual_err="$MH_TEST_DIR/test-mhfixmsg$$.actual_err"
-if grep mhfixmsg-format-text/html "${MH_TEST_DIR}/Mail/mhn.defaults" \
+mhn_defaults="$MH_INST_DIR${nmhetcdir}/mhn.defaults"
+
+if grep mhfixmsg-format-text/html "${mhn_defaults}" \
>/dev/null; then
can_reformat_texthtml=1
- if grep 'mhfixmsg-format-text/html.*w3m' "${MH_TEST_DIR}/Mail/mhn.defaults" \
+ if grep 'mhfixmsg-format-text/html.*w3m' "${mhn_defaults}" \
>/dev/null; then
#### w3m uses $HOME/.w3m/, and creates it if it doesn't exist. To
#### support testing with non-writeable $HOME, and to not leave
# check -help
-# Verified behavior consistent with compiled sendmail.
cat >"$expected" <<EOF
Usage: mhfixmsg [+folder] [msgs] [switches]
switches are:
-[no]replacetextplain
-[no]fixboundary
-[no]fixcte
+ -fixtype mimetype
-file file
-outfile file
-rmmproc program
# check -version
-# Verified same behavior as compiled mhfixmsg.
case `mhfixmsg -version` in
mhfixmsg\ --*) ;;
*) printf '%s: mhfixmsg -version generated unexpected output\n' "$0" >&2
fi
+# check -fixtype
+cat >"$expected" <<EOF
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg with incorrect Content-Type
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0"
+
+------- =_aaaaaaaaaa0
+Content-Type: text/plain; name="plaintext.txt"
+
+this is plain text
+
+------- =_aaaaaaaaaa0--
+EOF
+
+cat >`mhpath new` <<EOF
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg with incorrect Content-Type
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0"
+
+------- =_aaaaaaaaaa0
+Content-Type: application/octet-stream; name="plaintext.txt"
+
+this is plain text
+
+------- =_aaaaaaaaaa0--
+EOF
+
+mhfixmsg -fixtype application/octet-stream last
+check "$expected" `mhpath last`
+
+
# make sure there are no tmp files left over
find "$MH_TEST_DIR/Mail" \( -name 'mhfix*' -o -name ',mhfix*' \) -print \
>"$actual"
$bindir/inc
more
$bindir/mhmail
-$MH_INST_DIR$nmhexecdir/mhl
+$MH_INST_DIR$nmhlibexecdir/mhl
cat
600
$bindir/packf
-$MH_INST_DIR$nmhexecdir/post
+$MH_INST_DIR$nmhlibexecdir/post
$bindir/send
$bindir/mhshow
-$MH_INST_DIR$nmhexecdir/mhl
+$MH_INST_DIR$nmhlibexecdir/mhl
nmh-`cat ${srcdir}/VERSION`
$bindir/whatnow
$bindir/whom
-$nmhetcdir
+$nmhetcdirinst
$MH_LIBEXEC_DIR
fcntl
${default_locking}
set +e
whatnowtest=`echo cd | whatnow -prompt ''`
set -e
-
case ${whatnowtest} in
cd) cat > "$expected" <<EOF
cd ${MH_TEST_DIR}/foo\'s\ bar
pwd
$SPDIR
EOF
+ # If path to $SPDIR is too long, readline will wrap and disturb
+ # the actual output. It obeys COLUMNS, so set that to a value
+ # that should be longer that $SPDIR plus a bit more.
+ COLUMNS=`getconf PATH_MAX . 2>/dev/null` || COLUMNS=8192
+ export COLUMNS
;;
"") cat > "$expected" <<EOF
$SPDIR
X("nofixboundary", 0, NFIXBOUNDARYSW) \
X("fixcte", 0, FIXCTESW) \
X("nofixcte", 0, NFIXCTESW) \
+ X("fixtype mimetype", 0, FIXTYPESW) \
X("file file", 0, FILESW) \
X("outfile file", 0, OUTFILESW) \
X("rmmproc program", 0, RPROCSW) \
typedef struct fix_transformations {
int fixboundary;
int fixcte;
+ svector_t fixtypes;
int reformat;
int replacetextplain;
int decodetext;
static int fix_boundary (CT *, int *);
static int get_multipart_boundary (CT, char **);
static int replace_boundary (CT, char *, char *);
+static int fix_types (CT, svector_t, int *);
+static char *replace_substring (char **, const char *, const char *);
static int fix_multipart_cte (CT, int *);
static int set_ce (CT, int);
static int ensure_text_plain (CT *, CT, int *, int);
int status = OK;
fix_transformations fx;
fx.reformat = fx.fixcte = fx.fixboundary = 1;
+ fx.fixtypes = NULL;
fx.replacetextplain = 0;
fx.decodetext = CE_8BIT;
fx.textcharset = NULL;
case NFIXCTESW:
fx.fixcte = 0;
continue;
+ case FIXTYPESW:
+ if (! (cp = *argp++) || (*cp == '-' && cp[1]))
+ adios (NULL, "missing argument to %s", argp[-2]);
+ if (! strncasecmp (cp, "multipart/", 10) ||
+ ! strncasecmp (cp, "message/", 8)) {
+ adios (NULL, "-fixtype %s not allowed", cp);
+ } else if (! strchr (cp, '/')) {
+ adios (NULL, "-fixtype requires type/subtype");
+ }
+ if (fx.fixtypes == NULL) { fx.fixtypes = svector_create (10); }
+ svector_push_back (fx.fixtypes, cp);
+ continue;
case REFORMATSW:
fx.reformat = 1;
continue;
status = 1;
}
+ if (fx.fixtypes != NULL) { svector_free (fx.fixtypes); }
free (outfile);
free (file);
if (status == OK && fx->fixboundary) {
status = fix_boundary (ctp, &message_mods);
}
+ if (status == OK && fx->fixtypes != NULL) {
+ status = fix_types (*ctp, fx->fixtypes, &message_mods);
+ }
if (status == OK && fx->fixcte) {
status = fix_multipart_cte (*ctp, &message_mods);
}
}
+static int
+fix_types (CT ct, svector_t fixtypes, int *message_mods) {
+ int status = OK;
+
+ switch (ct->c_type) {
+ case CT_MULTIPART: {
+ struct multipart *m = (struct multipart *) ct->c_ctparams;
+ struct part *part;
+
+ for (part = m->mp_parts; status == OK && part; part = part->mp_next) {
+ status = fix_types (part->mp_part, fixtypes, message_mods);
+ }
+ break;
+ }
+
+ case CT_MESSAGE:
+ if (ct->c_subtype == MESSAGE_EXTERNAL) {
+ struct exbody *e = (struct exbody *) ct->c_ctparams;
+
+ status = fix_types (e->eb_content, fixtypes, message_mods);
+ }
+ break;
+
+ default: {
+ char **typep, *type;
+
+ if (ct->c_ctinfo.ci_type && ct->c_ctinfo.ci_subtype) {
+ for (typep = svector_strs (fixtypes);
+ typep && (type = *typep);
+ ++typep) {
+ char *type_subtype =
+ concat (ct->c_ctinfo.ci_type, "/", ct->c_ctinfo.ci_subtype,
+ NULL);
+
+ if (! strcasecmp (type, type_subtype) &&
+ decode_part (ct) == OK &&
+ ct->c_cefile.ce_file != NULL) {
+ char *ct_type_subtype = mime_type (ct->c_cefile.ce_file);
+ char *cp;
+
+ if ((cp = strchr (ct_type_subtype, ';'))) {
+ /* Truncate to remove any parameter list from
+ mime_type () result. */
+ *cp = '\0';
+ }
+
+ if (strcasecmp (type, ct_type_subtype)) {
+ char *ct_type, *ct_subtype;
+ HF hf;
+
+ /* The Content-Type header does not match the
+ content, so update these struct Content
+ fields to match:
+ * c_type, c_subtype
+ * c_ctinfo.ci_type, c_ctinfo.ci_subtype
+ * c_ctline
+ */
+ /* Extract type and subtype from type/subtype. */
+ ct_type = getcpy (ct_type_subtype);
+ if ((cp = strchr (ct_type, '/'))) {
+ *cp = '\0';
+ ct_subtype = getcpy (++cp);
+ } else {
+ advise (NULL, "missing / in MIME type of %s %s",
+ ct->c_file, ct->c_partno);
+ free (ct_type);
+ return NOTOK;
+ }
+
+ ct->c_type = ct_str_type (ct_type);
+ ct->c_subtype = ct_str_subtype (ct->c_type, ct_subtype);
+
+ free (ct->c_ctinfo.ci_type);
+ ct->c_ctinfo.ci_type = ct_type;
+ free (ct->c_ctinfo.ci_subtype);
+ ct->c_ctinfo.ci_subtype = ct_subtype;
+ if (! replace_substring (&ct->c_ctline, type,
+ ct_type_subtype)) {
+ advise (NULL, "did not find %s in %s",
+ type, ct->c_ctline);
+ }
+
+ /* Update Content-Type header field. */
+ for (hf = ct->c_first_hf; hf; hf = hf->next) {
+ if (! strcasecmp (TYPE_FIELD, hf->name)) {
+ if (replace_substring (&hf->value, type,
+ ct_type_subtype)) {
+ ++*message_mods;
+ if (verbosw) {
+ report (NULL, ct->c_partno, ct->c_file,
+ "change Content-Type in header "
+ "from %s to %s",
+ type, ct_type_subtype);
+ }
+ break;
+ } else {
+ advise (NULL, "did not find %s in %s",
+ type, hf->value);
+ }
+ }
+ }
+ }
+ free (ct_type_subtype);
+ }
+ free (type_subtype);
+ }
+ }
+ }}
+
+ return status;
+}
+
+char *
+replace_substring (char **str, const char *old, const char *new) {
+ char *cp;
+
+ if ((cp = strstr (*str, old))) {
+ char *remainder = cp + strlen (old);
+ char *prefix, *new_str;
+
+ if (cp - *str) {
+ prefix = getcpy (*str);
+ *(prefix + (cp - *str)) = '\0';
+ new_str = concat (prefix, new, remainder, NULL);
+ free (prefix);
+ } else {
+ new_str = concat (new, remainder, NULL);
+ }
+
+ free (*str);
+
+ return *str = new_str;
+ } else {
+ return NULL;
+ }
+}
+
+
static int
fix_multipart_cte (CT ct, int *message_mods) {
int status = OK;
if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, NULL)) == NULL) {
advise (NULL, "unable to create temporary file in %s",
get_temp_dir());
- }
- tmp_plain_file = add (tempfile, NULL);
- if (reformat_part (tp_part, tmp_plain_file,
- tp_part->c_ctinfo.ci_type,
- tp_part->c_ctinfo.ci_subtype,
- tp_part->c_type) == OK) {
- return tp_part;
+ } else {
+ tmp_plain_file = add (tempfile, NULL);
+ if (reformat_part (tp_part, tmp_plain_file,
+ tp_part->c_ctinfo.ci_type,
+ tp_part->c_ctinfo.ci_subtype,
+ tp_part->c_type) == OK) {
+ return tp_part;
+ }
}
}
static void
process (char *folder, char *fname, int ofilen, int ofilec)
{
- char *cp = NULL;
- FILE *fp = NULL;
+ /* static to prevent "might be clobbered" warning from gcc 4.9.2: */
+ static char *cp;
+ static FILE *fp;
struct mcomp *c1;
struct stat st;
struct arglist *ap;
/* volatile to prevent "might be clobbered" warning from gcc: */
char *volatile fname2 = fname ? fname : "(stdin)";
+ cp = NULL;
+ fp = NULL;
+
switch (setjmp (env)) {
case OK:
if (fname) {
if (arglist_head)
fmt_free(NULL, 1);
- default:
+ default:
if (ontty != PITTY)
SIGNAL (SIGINT, SIG_IGN);
- if (mhl_action == NULL && fp != stdin)
+ if (mhl_action == NULL && fp != stdin && fp != NULL)
fclose (fp);
- free (cp);
+ free (cp);
if (holder.c_text) {
free (holder.c_text);
holder.c_text = NULL;
char *chset = NULL;
char *cp;
PM pm;
- struct k2v *kv;
struct text *t;
CI ci = &ct->c_ctinfo;
ci->ci_subtype = add ("plain", ci->ci_subtype);
/* match subtype */
- for (kv = SubText; kv->kv_key; kv++)
- if (!strcasecmp (ci->ci_subtype, kv->kv_key))
- break;
- ct->c_subtype = kv->kv_value;
+ ct->c_subtype = ct_str_subtype (CT_TEXT, ci->ci_subtype);
/* allocate text character set structure */
if ((t = (struct text *) mh_xcalloc (1, sizeof(*t))) == NULL)
size_t buflen;
ssize_t gotlen;
struct multipart *m;
- struct k2v *kv;
struct part *part, **next;
CI ci = &ct->c_ctinfo;
CT p;
}
/* match subtype */
- for (kv = SubMultiPart; kv->kv_key; kv++)
- if (!strcasecmp (ci->ci_subtype, kv->kv_key))
- break;
- ct->c_subtype = kv->kv_value;
+ ct->c_subtype = ct_str_subtype (CT_MULTIPART, ci->ci_subtype);
/*
* Check for "boundary" parameter, which is
static int
InitMessage (CT ct)
{
- struct k2v *kv;
CI ci = &ct->c_ctinfo;
if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) {
ci->ci_subtype = add ("rfc822", ci->ci_subtype);
/* match subtype */
- for (kv = SubMessage; kv->kv_key; kv++)
- if (!strcasecmp (ci->ci_subtype, kv->kv_key))
- break;
- ct->c_subtype = kv->kv_value;
+ ct->c_subtype = ct_str_subtype (CT_MESSAGE, ci->ci_subtype);
switch (ct->c_subtype) {
case MESSAGE_RFC822:
static int
InitApplication (CT ct)
{
- struct k2v *kv;
CI ci = &ct->c_ctinfo;
/* match subtype */
- for (kv = SubApplication; kv->kv_key; kv++)
- if (!strcasecmp (ci->ci_subtype, kv->kv_key))
- break;
- ct->c_subtype = kv->kv_value;
+ ct->c_subtype = ct_str_subtype (CT_APPLICATION, ci->ci_subtype);
return OK;
}
}
+int
+ct_str_type (const char *type) {
+ struct str2init *s2i;
+
+ for (s2i = str2cts; s2i->si_key; ++s2i) {
+ if (! strcasecmp (type, s2i->si_key)) {
+ break;
+ }
+ }
+ if (! s2i->si_key && ! uprf (type, "X-")) {
+ ++s2i;
+ }
+
+ return s2i->si_val;
+}
+
+
+int
+ct_str_subtype (int type, const char *subtype) {
+ struct k2v *kv;
+
+ switch (type) {
+ case CT_APPLICATION:
+ for (kv = SubApplication; kv->kv_key; ++kv) {
+ if (! strcasecmp (subtype, kv->kv_key)) {
+ break;
+ }
+ }
+ return kv->kv_value;
+ case CT_MESSAGE:
+ for (kv = SubMessage; kv->kv_key; ++kv) {
+ if (! strcasecmp (subtype, kv->kv_key)) {
+ break;
+ }
+ }
+ return kv->kv_value;
+ case CT_MULTIPART:
+ for (kv = SubMultiPart; kv->kv_key; ++kv) {
+ if (! strcasecmp (subtype, kv->kv_key)) {
+ break;
+ }
+ }
+ return kv->kv_value;
+ case CT_TEXT:
+ for (kv = SubText; kv->kv_key; ++kv) {
+ if (! strcasecmp (subtype, kv->kv_key)) {
+ break;
+ }
+ }
+ return kv->kv_value;
+ default:
+ return 0;
+ }
+}
+
+
/* Find the content type and InitFunc for the CT. */
const struct str2init *
get_ct_init (int type) {
#include <fcntl.h>
#include <h/signals.h>
#include <h/md5.h>
-#include <setjmp.h>
#include <h/mts.h>
#include <h/tws.h>
#include <h/mime.h>
char *cp;
static int quoting = 0;
- cp = buffer;
- *cp = 0;
+ *buffer = 0;
switch (setjmp (sigenv)) {
case OK:
return NOTOK;
}
+ cp = buffer;
+ *cp = 0;
+
for (;;) {
switch (c = getchar ()) {
case EOF:
annotate(drft, ATTACH_FIELD, file, 1, 0, -2, 1);
if (verbose) {
ctype = mime_type(file);
- }
-
- if (verbose) {
printf ("Attaching %s as a %s\n", file, ctype);
free (ctype);
}