/RPM/
a.out.dSYM/
/config/version.c
+/etc/gen-ctype-checked
/etc/mhn.defaults
/etc/mts.conf
/man/*.[1578]
/man/mh-chart.man
/mts/libmts.a
/sbr/*.a
+/sbr/ctype-checked.*
/sbr/sigmsg.h
/test/testdir/
/uip/ali
/uip/dp
/uip/flist
/uip/fmtdump
+ /uip/fmttest
/uip/folder
/uip/forw
/uip/inc
/test/fakepop
/test/getfullname
/test/getfqdn
+/test/getcwidth
# Removed by mostlyclean:
*.o
## LDADD is included in the program-specific LDADD since we want to add
## to this list of libraries, not replace it.
##
-LDADD = sbr/libmh.a sbr/libdtimep.a
+LDADD = sbr/libmh.a
##
## These are used to create the default mhn.defaults config file
auxexecdir="$(auxexecdir)" bindir="$(bindir)" \
mandir="$(mandir)" sysconfdir="$(sysconfdir)" \
MULTIBYTE_ENABLED=$(MULTIBYTE_ENABLED) \
+ ICONV_ENABLED=$(ICONV_ENABLED) \
$(TESTS_SHELL) ## Keep at end of TESTS_ENVIRONMENT.
##
## Important note: the "cleanup" test should always be last
##
TESTS = test/ali/test-ali test/anno/test-anno \
test/bad-input/test-header \
- test/burst/test-burst \
+ test/burst/test-burst test/burst/test-burst-mime \
test/comp/test-comp-format test/dist/test-dist \
test/folder/test-create test/folder/test-packf \
test/folder/test-recurse test/folder/test-sortm \
test/format/test-dp test/format/test-fmtdump \
test/format/test-localmbox test/format/test-myname \
test/format/test-myhost test/format/test-mymbox \
+ test/format/test-rightjustify \
test/forw/test-forw-digest test/forw/test-forw-format \
test/inc/test-deb359167 test/inc/test-eom-align \
test/inc/test-inc-scanout test/inc/test-msgchk \
test/mhlist/test-mhlist test/mhmail/test-mhmail \
test/mhparam/test-mhparam test/mhpath/test-mhpath \
test/mhshow/test-cte-binary test/mhshow/test-qp \
- test/mhshow/test-subpart test/mhstore/test-mhstore \
- test/new/test-basic \
+ test/mhshow/test-subpart test/mhshow/test-msg-buffer-boundaries \
+ test/mhstore/test-mhstore test/new/test-basic \
test/pick/test-pick test/pick/test-stderr \
test/post/test-post-aliases test/post/test-post-basic \
test/post/test-post-multiple test/post/test-post-bcc \
test/cleanup ## The "cleanup" test should always be last.
check_SCRIPTS = test/common.sh
-check_PROGRAMS = test/getfullname test/getfqdn test/fakepop test/fakesmtp
+check_PROGRAMS = test/getfullname test/getfqdn test/fakepop test/fakesmtp \
+ test/getcwidth
DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1
##
## Stuff that should be cleaned via "make clean"
##
CLEANFILES = config/version.c sbr/sigmsg.h etc/mts.conf \
+ etc/gen-ctype-checked sbr/ctype-checked.h sbr/ctype-checked.c \
etc/mhn.defaults man/man.sed man/mh-chart.man $(man_MANS)
clean-local:
@rm -rf RPM a.out.dSYM uip/a.out.dSYM
##
## Files that need to be built before everything else
##
-BUILT_SOURCES = sbr/sigmsg.h
+BUILT_SOURCES = sbr/sigmsg.h sbr/ctype-checked.c
##
## This is a list of all programs that get installed in the "bin" directory
## the latter do not have $(EXEEXT) added on the end.
##
bin_PROGRAMS = uip/ali uip/anno uip/burst uip/comp uip/dist uip/flist \
- uip/folder uip/forw uip/inc uip/install-mh uip/mark \
- uip/mhbuild uip/mhlist uip/mhn uip/mhparam \
+ uip/fmttest uip/folder uip/forw uip/inc uip/install-mh \
+ uip/mark uip/mhbuild uip/mhlist uip/mhn uip/mhparam \
uip/mhpath uip/mhshow uip/mhstore uip/msgchk uip/msh uip/new \
uip/packf uip/pick uip/prompter uip/refile uip/repl uip/rmf \
uip/rmm uip/scan uip/send uip/show uip/sortm uip/whatnow \
auxexec_SCRIPTS = uip/spost
+##
+## Programs that MAY need to get built at some point; we need to list them
+## here if they don't appear in any other primary so Automake knows about
+## them and can properly record dependency information.
+##
+EXTRA_PROGRAMS = etc/gen-ctype-checked
+
##
## Internal libraries that we create as part of the build process
## but do not install
##
-noinst_LIBRARIES = sbr/libmh.a sbr/libdtimep.a mts/libmts.a
+noinst_LIBRARIES = sbr/libmh.a mts/libmts.a
##
## These are all of our header files. Right now we don't install any of
h/mh.h h/mhcachesbr.h h/mhparse.h h/mime.h h/msh.h \
h/mts.h h/nmh.h h/picksbr.h h/popsbr.h h/prototypes.h \
h/rcvmail.h h/scansbr.h h/signals.h h/tws.h h/utils.h \
- h/vmhsbr.h mts/smtp/smtp.h
+ h/vmhsbr.h mts/smtp/smtp.h sbr/ctype-checked.h
##
## Extra files we need to install in various places
##
man_MANS = man/ali.1 man/anno.1 man/ap.8 man/burst.1 man/comp.1 \
man/conflict.8 man/dist.1 man/dp.8 man/flist.1 man/flists.1 \
- man/fmtdump.8 man/fnext.1 man/folder.1 man/folders.1 \
+ man/fmtdump.8 man/fmttest.1 man/fnext.1 man/folder.1 man/folders.1 \
man/forw.1 man/fprev.1 man/inc.1 man/install-mh.1 man/mark.1 \
man/mh-alias.5 man/mh-chart.7 man/mh-draft.5 man/mh-format.5 \
man/mh-mail.5 man/mh-profile.5 man/mh_profile.5 man/mh-sequence.5 \
##
man_SRCS = man/ali.man man/anno.man man/ap.man man/burst.man man/comp.man \
man/conflict.man man/dist.man man/dp.man man/flist.man \
- man/flists.man man/fmtdump.man man/fnext.man man/folder.man \
- man/folders.man man/forw.man man/fprev.man man/inc.man \
- man/install-mh.man man/mark.man man/mh-alias.man \
+ man/flists.man man/fmtdump.man man/fmttest.man man/fnext.man \
+ man/folder.man man/folders.man man/forw.man man/fprev.man
+ man/inc.man man/install-mh.man man/mark.man man/mh-alias.man \
man/mh-chart-gen.sh man/mh-draft.man man/mh-format.man \
man/mh-mail.man man/mh-profile.man man/mh_profile.man \
man/mh-sequence.man man/mh-tailor.man man/mhbuild.man man/mhl.man \
uip_anno_SOURCES = uip/anno.c uip/annosbr.c
-uip_burst_SOURCES = uip/burst.c
+uip_burst_SOURCES = uip/burst.c uip/mhparse.c uip/mhmisc.c uip/mhfree.c \
+ uip/mhcachesbr.c uip/md5.c
uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
uip/annosbr.c uip/distsbr.c
uip_fmtdump_SOURCES = uip/fmtdump.c
uip_fmtdump_LDADD = $(LDADD) $(ICONVLIB)
+ uip_fmttest_SOURCES = uip/fmttest.c uip/termsbr.c
+ uip_fmttest_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB)
+
uip_mhl_SOURCES = uip/mhl.c uip/mhlsbr.c uip/termsbr.c
uip_mhl_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB)
test_fakesmtp_SOURCES = test/fakesmtp.c
test_fakesmtp_LDADD =
+test_getcwidth_SOURCES = test/getcwidth.c
+test_getcwidth_LDADD =
+
+etc_gen_ctype_checked_SOURCES = etc/gen-ctype-checked.c
+etc_gen_ctype_checked_LDADD =
+
##
## Our rebuild rules for files that aren't built via the normal mechanisms
##
sbr/sigmsg.h: $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H)
$(AWK) -f $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H) > $@
+sbr/ctype-checked.h: etc/gen-ctype-checked
+ etc/gen-ctype-checked
+
+sbr/ctype-checked.c: etc/gen-ctype-checked sbr/ctype-checked.h
+
etc/mts.conf: $(srcdir)/etc/mts.conf.in Makefile
@rm -f $@
$(SED) -e 's,%mts%,$(MTS),' \
sbr/context_replace.c sbr/context_save.c \
sbr/copy.c sbr/copyip.c sbr/cpydata.c \
sbr/cpydgst.c sbr/crawl_folders.c sbr/discard.c \
- sbr/done.c sbr/dtime.c sbr/escape_addresses.c \
+ sbr/done.c sbr/dtimep.l sbr/dtime.c \
+ sbr/escape_addresses.c \
sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \
sbr/folder_addmsg.c sbr/folder_delmsgs.c \
sbr/folder_free.c sbr/folder_pack.c \
sbr/showfile.c sbr/signals.c sbr/smatch.c \
sbr/snprintb.c sbr/ssequal.c sbr/strcasecmp.c \
sbr/strindex.c sbr/trimcpy.c sbr/uprf.c sbr/vfgets.c \
- sbr/fmt_def.c sbr/m_msgdef.c sbr/mf.c sbr/utils.c \
+ sbr/fmt_def.c sbr/mf.c sbr/utils.c sbr/ctype-checked.c \
sbr/m_mktemp.c sbr/getansreadline.c config/config.c \
config/version.c
-DSENDMAILPATH='"$(sendmailpath)"' -DNMHBINDIR='"$(bindir)"' \
-DNMHLIBDIR='"$(libdir)"'
-sbr_libdtimep_a_SOURCES = sbr/dtimep.l
-sbr_libdtimep_a_CFLAGS = $(sbr_libmh_a_CPPFLAGS) \
- $(DISABLE_UNUSED_MACROS_WARNING) \
- $(DISABLE_SIGN_COMPARE_WARNING)
-
mts_libmts_a_SOURCES = mts/smtp/smtp.c
##
## Don't include commit hashes in ChangeLog.
ChangeLog:
- @[ -d .git ] && git --no-pager log --abbrev-commit | \
- egrep -v '^commit [0-9a-f]+$$' > $@ || true
+ @[ -d $(srcdir)/.git ] && (cd $(srcdir); git --no-pager log --abbrev-commit | \
+ egrep -v '^commit [0-9a-f]+$$' > $@) || true
## Make ChangeLog phony so it will always get regenerated. But don't
## fail if we don't have a git repository in order to allow
## regeneration of distribution archive or RPM.
NMH MANPAGE STYLE GUIDE
-nmh manpages should be in this general form:
+nmh manpages should be in this general form and section order:
.TH COMP %manext1% "DATE" "%nmhversion%"
.\"
.\"
.SH NAME
comp \- compose a message
+.\"
.SH SYNOPSIS
+ .HP 5
+ .na
.B comp
.RI [ +folder ]
.RI [ msgs ]
.RB [ \-use " | " \-nouse ]
.RB [ \-version ]
.RB [ \-help ]
+ .ad
.SH DESCRIPTION
.B Comp
is used to create a new message to be mailed. It copies something.
-.SH FILES
-.TP
-filename1
-description of filename1
-.TP
-filename2
-description of filename2
+.\"
.SH "PROFILE COMPONENTS"
.TP
Path
.TP
moreproc
The pager command name
-.SH "SEE ALSO"
-.IR dist (1),
-.IR forw (1),
-.IR repl (1),
-.IR send (1),
-.IR whatnow (1),
-.IR mh-profile (5)
+.\"
.SH DEFAULTS
.TP
.RI + folder
.\"
.SH CONTEXT
None
+.\"
+.SH FILES
+.TP
+filename1
+description of filename1
+.TP
+filename2
+description of filename2
+.\"
+.SH "SEE ALSO"
+.IR dist (1),
+.IR forw (1),
+.IR repl (1),
+.IR send (1),
+.IR whatnow (1),
+.IR mh-profile (5)
.\" Leave out the BUGS section if there are none worth describing.
.SH BUGS
None
In the FILES section, prefer the default .TP indent. The pathnames are
variable and long, so any indentation value that works for you won't
-work for someone else.
+work for someone using a different directory layout.
Source files
CONTEXT
- Don't include a CONTEXT section when contexts are out of context.
+ Don't include a CONTEXT section when contexts are not
+ applicable.
AUTHOR and HISTORY sections
BUGS
- The BUGS section goes last.
+ The BUGS section goes last.
#define PUTC(c) do { NEW(FT_CHAR,0,0); fp->f_char = (c); } while (0)
static char *format_string;
-static unsigned char *usr_fstring; /* for CERROR */
+static char *usr_fstring; /* for CERROR */
#define CERROR(str) compile_error (str, cp)
for (i = errpos-errctx; i < errpos; i++) {
#ifdef LOCALE
- if (iscntrl(usr_fstring[i]))
+ if (iscntrl((unsigned char) usr_fstring[i]))
#else
if (usr_fstring[i] < 32)
#endif
free_comptable();
}
+ /*
+ * Free just the text strings from all of the component hash table entries
+ */
+
+ void
+ fmt_freecomptext(void)
+ {
+ unsigned int i;
+ struct comp *cm;
+
+ for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++)
+ for (cm = wantcomp[i]; cm; cm = cm->c_next)
+ if (cm->c_text) {
+ free(cm->c_text);
+ cm->c_text = NULL;
+ }
+ }
+
/*
* Find a component in our hash table. This is just a public interface to
* the FINDCOMP macro, so we don't have to expose our hash table.
#ifdef LOCALE
while ((c1 = *sub)) {
- c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
- while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2))
+ c1 = (isascii((unsigned char) c1) && isalpha((unsigned char) c1) &&
+ isupper((unsigned char) c1)) ? tolower((unsigned char) c1) : c1;
+ while ((c2 = *str++) && c1 != ((isascii((unsigned char) c2) &&
+ isalpha((unsigned char) c2) &&
+ isupper((unsigned char) c2)) ?
+ tolower((unsigned char) c2) : c2))
;
if (! c2)
return 0;
s1 = sub + 1; s2 = str;
- while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2))
+ while ((c1 = *s1++) && ((isascii((unsigned char) c1) &&
+ isalpha((unsigned char) c1) &&
+ isupper((unsigned char) c1)) ?
+ tolower(c1) : c1) ==
+ ((isascii((unsigned char) (c2 =*s2++)) &&
+ isalpha((unsigned char) c2) &&
+ isupper((unsigned char) c2)) ?
+ tolower((unsigned char) c2) : c2))
;
if (! c1)
return 1;
* no more than n bytes are copied
*/
static void
-cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n,
- size_t max) {
+cptrimmed(char **dest, char **ep, char *str, unsigned int wid, char fill,
+ char *epmax) {
int remaining; /* remaining output width available */
int c, ljust;
int end; /* number of input bytes remaining in str */
#endif
char *sp; /* current position in source string */
char *cp = *dest; /* current position in destination string */
- char *ep = cp + n; /* end of destination buffer based on desired width */
- char *epmax = cp + max; /* true end of destination buffer */
int prevCtrl = 1;
/* get alignment */
ljust++;
}
if ((sp = (str))) {
+#ifdef MULTIBYTE_SUPPORT
mbtowc(NULL, NULL, 0); /* reset shift state */
+#endif
end = strlen(str);
while (*sp && remaining > 0 && end > 0) {
#ifdef MULTIBYTE_SUPPORT
char_len = mbtowc(&wide_char, sp, end);
- /* Account for multibyte characters taking only one character's
- width of output. */
- if (char_len > 1 && epmax - ep >= char_len - 1) {
- ep += char_len - 1;
+ if (char_len <= 0)
+ break;
+
+ w = wcwidth(wide_char);
+
+ /*
+ * Multibyte characters can have a variable number of column
+ * widths, so use the column width to bump the end pointer when
+ * appropriate.
+ */
+ if (char_len > 1 && epmax - *ep >= char_len - w) {
+ *ep += char_len - w;
}
- if (char_len <= 0 || (cp + char_len > ep))
+ if (cp + w > *ep)
break;
end -= char_len;
end--;
/* isnctrl(), etc., take an int argument. Cygwin's ctype.h
intentionally warns if they are passed a char. */
- c = *sp;
+ c = (unsigned char) *sp;
if (iscntrl(c) || isspace(c)) {
sp++;
#endif
prevCtrl = 0;
#ifdef MULTIBYTE_SUPPORT
- w = wcwidth(wide_char);
if (w >= 0 && remaining >= w) {
strncpy(cp, sp, char_len);
cp += char_len;
}
if (ljust) {
- if (cp + remaining > ep)
- remaining = ep - cp;
- ep = cp + remaining;
+ char *endfield;
+ if (cp + remaining > *ep)
+ remaining = *ep - cp;
+ endfield = cp + remaining;
if (remaining > 0) {
/* copy string to the right */
while (--cp >= *dest)
for (c=remaining; c>0; c--)
*cp-- = fill;
}
- *dest = ep;
+ *dest = endfield;
} else {
/* pad remaining space */
- while (remaining-- > 0 && cp < ep)
+ while (remaining-- > 0 && cp < *ep)
*cp++ = fill;
*dest = cp;
}
}
static void
-cpstripped (char **dest, char *end, char *max, char *str)
+cpstripped (char **dest, char **end, char *max, char *str)
{
int prevCtrl = 1; /* This is 1 so we strip out leading spaces */
int len;
#ifdef MULTIBYTE_SUPPORT
- int char_len;
+ int char_len, w;
wchar_t wide_char;
#endif /* MULTIBYTE_SUPPORT */
* then deal with that here.
*/
- while (*str != '\0' && len > 0 && *dest < end) {
+ while (*str != '\0' && len > 0 && *dest < *end) {
#ifdef MULTIBYTE_SUPPORT
char_len = mbtowc(&wide_char, str, len);
-
- /* Account for multibyte characters taking only one character's
- width of output. */
- if (char_len > 1 && max - end >= char_len - 1) {
- end += char_len - 1;
+ w = wcwidth(wide_char);
+
+ /*
+ * Account for multibyte characters, and increment the end pointer
+ * by the number of "extra" bytes in this character. That's the
+ * character length (char_len) minus the column width (w).
+ */
+ if (char_len > 1 && max - *end >= char_len - w) {
+ *end += char_len - w;
}
- if (char_len <= 0 || *dest + char_len > end)
+ if (char_len <= 0 || *dest + char_len > *end)
break;
len -= char_len;
if (iswcntrl(wide_char) || iswspace(wide_char)) {
str += char_len;
#else /* MULTIBYTE_SUPPORT */
- int c = *str;
+ int c = (unsigned char) *str;
len--;
if (iscntrl(c) || isspace(c)) {
str++;
}
struct format *
- fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat)
+ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat,
+ struct fmt_callbacks *callbacks)
{
- char *cp, *ep;
- unsigned char *sp;
- char *savestr = NULL;
- unsigned char *str = NULL;
+ char *cp, *ep, *sp;
+ char *savestr = NULL, *str = NULL;
char buffer[BUFSIZ], buffer2[BUFSIZ];
int i, c, ljust, n;
int value = 0;
switch (fmt->f_type) {
case FT_COMP:
- cpstripped (&cp, ep, scanl + max - 1, fmt->f_comp->c_text);
+ cpstripped (&cp, &ep, scanl + max - 1, fmt->f_comp->c_text);
break;
case FT_COMPF:
- cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill,
- ep - cp, scanl - cp + max - 1);
+ cptrimmed (&cp, &ep, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill,
+ scanl + max - 1);
break;
case FT_LIT:
break;
case FT_STR:
- cpstripped (&cp, ep, scanl + max - 1, str);
+ cpstripped (&cp, &ep, scanl + max - 1, str);
break;
case FT_STRF:
- cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp,
- scanl - cp + max - 1);
+ cptrimmed (&cp, &ep, str, fmt->f_width, fmt->f_fill,
+ scanl + max - 1);
break;
case FT_STRLIT:
sp = str;
break;
case FT_DONE:
+ if (callbacks && callbacks->trace_func)
+ callbacks->trace_func(callbacks->trace_context, fmt, value,
+ str, scanl);
goto finished;
case FT_IF_S:
case FT_LS_TRIM:
if (str) {
- unsigned char *xp;
+ char *xp;
strncpy(buffer, str, sizeof(buffer));
buffer[sizeof(buffer)-1] = '\0';
str = buffer;
- while (isspace(*str))
+ while (isspace((unsigned char) *str))
str++;
ljust = 0;
if ((i = fmt->f_width) < 0) {
str[i] = '\0';
xp = str;
xp += strlen(str) - 1;
- while (xp > str && isspace(*xp))
+ while (xp > str && isspace((unsigned char) *xp))
*xp-- = '\0';
if (ljust && i > 0 && (int) strlen(str) > i)
str += strlen(str) - i;
case FT_FORMATADDR:
/* hook for custom address list formatting (see replsbr.c) */
- str = formataddr (savestr, str);
+ if (callbacks && callbacks->formataddr)
+ str = callbacks->formataddr (savestr, str);
+ else
+ str = formataddr (savestr, str);
break;
case FT_CONCATADDR:
/* The same as formataddr, but doesn't do duplicate suppression */
- str = concataddr (savestr, str);
+ if (callbacks && callbacks->concataddr)
+ str = callbacks->concataddr (savestr, str);
+ else
+ str = concataddr (savestr, str);
break;
case FT_PUTADDR:
* (e.g., "To: ")
*/
{
- unsigned char *lp;
- char *lastb;
+ char *lp, *lastb;
int indent, wid, len;
lp = str;
adios(NULL, "putaddr -- num register (%d) must be greater "
"than label width (%d)", value, indent);
}
- while( (c = *sp++) && cp < ep)
- *cp++ = c;
+ while( (c = (unsigned char) *sp++) && cp < ep)
+ *cp++ = (char) c;
while (len > wid) {
/* try to break at a comma; failing that, break at a
* space.
*/
lastb = 0; sp = lp + wid;
- while (sp > lp && (c = *--sp) != ',') {
+ while (sp > lp && (c = (unsigned char) *--sp) != ',') {
if (! lastb && isspace(c))
lastb = sp - 1;
}
if (sp == lp) {
if (! (sp = lastb)) {
sp = lp + wid - 1;
- while (*sp && *sp != ',' && !isspace(*sp))
+ while (*sp && *sp != ',' &&
+ !isspace((unsigned char) *sp))
sp++;
if (*sp != ',')
sp--;
len -= sp - lp + 1;
while (cp < ep && lp <= sp)
*cp++ = *lp++;
- while (isspace(*lp))
+ while (isspace((unsigned char) *lp))
lp++, len--;
if (*lp) {
if (cp < ep)
*cp++ = ' ';
}
}
- cpstripped (&cp, ep, scanl + max - 1, lp);
+ cpstripped (&cp, &ep, scanl + max - 1, lp);
}
break;
}
break;
}
+
+ /*
+ * Call our tracing callback function, if one was supplied
+ */
+
+ if (callbacks && callbacks->trace_func)
+ callbacks->trace_func(callbacks->trace_context, fmt, value,
+ str, scanl);
fmt++;
}
while (fmt->f_type != FT_DONE) {
if (fmt->f_type == FT_LS_LIT) {
str = fmt->f_text;
+ if (callbacks && callbacks->trace_func)
+ callbacks->trace_func(callbacks->trace_context, fmt, value,
+ str, scanl);
} else if (fmt->f_type == FT_STRLITZ) {
/* Don't want to emit part of an escape sequence. So if
there isn't enough room in the buffer for the entire
if (cp - scanl + strlen (str) + 1 < max) {
for (sp = str; *sp; *cp++ = *sp++) continue;
}
+ if (callbacks && callbacks->trace_func)
+ callbacks->trace_func(callbacks->trace_context, fmt, value,
+ str, scanl);
}
fmt++;
}
char *cc, char *fcc, char *subject, char *inputfile)
{
int in;
- int fmtsize, state, char_read = 0;
+ int fmtsize, state;
int i;
register char *nfs;
char *line, tmpfil[BUFSIZ], name[NAMESZ], **ap;
register struct comp *cptr;
struct format *fmt;
char *cp = NULL;
+ m_getfld_state_t gstate = 0;
/*
* Open the message we'll be scanning for components
* these routines?
*/
- for (state = FLD;;) {
- state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp);
+ for (;;) {
+ int msg_count = sizeof msgbuf;
+ state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp);
switch (state) {
case FLD:
case FLDPLUS:
i = fmt_addcomptext(name, msgbuf);
if (i != -1) {
- char_read += msg_count;
while (state == FLDPLUS) {
- state = m_getfld(state, name, msgbuf,
- sizeof(msgbuf), tmp);
+ msg_count = sizeof msgbuf;
+ state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp);
fmt_appendcomp(i, name, msgbuf);
- char_read += msg_count;
}
}
- while (state == FLDPLUS)
- state = m_getfld(state, name, msgbuf, sizeof(msgbuf), tmp);
+ while (state == FLDPLUS) {
+ msg_count = sizeof msgbuf;
+ state = m_getfld (&gstate, name, msgbuf, &msg_count, tmp);
+ }
break;
case LENERR:
*/
finished:
+ m_getfld_state_destroy (&gstate);
cptr = fmt_findcomp ("digest");
if (cptr) {
adios ("dup", "unable to");
line = mh_xmalloc ((unsigned) fmtsize);
- fmt_scan (fmt, line, fmtsize - 1, fmtsize, dat);
+ fmt_scan (fmt, line, fmtsize - 1, fmtsize, dat, NULL);
fputs (line, tmp);
free (line);
if (fclose (tmp))
static char *ovtxt;
-static unsigned char *onelp;
+static char *onelp;
static char *parptr;
static void mhladios (char *, char *, ...);
static void mhldone (int);
static void m_popen (char *);
-static void filterbody (struct mcomp *, char *, int, int, FILE *);
+static void filterbody (struct mcomp *, char *, int, int, FILE *,
+ m_getfld_state_t);
static void compile_formatfield(struct mcomp *);
static void compile_filterargs (void);
int state, bucket;
struct mcomp *c1, *c2, *c3;
char **ip, name[NAMESZ], buf[BUFSIZ];
+ m_getfld_state_t gstate = 0;
compile_filterargs();
}
}
- for (state = FLD;;) {
- switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
+ for (;;) {
+ int bufsz = sizeof buf;
+ switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) {
case FLD:
case FLDPLUS:
bucket = fmt_addcomptext(name, buf);
for (ip = ignores; *ip; ip++)
if (!mh_strcasecmp (name, *ip)) {
while (state == FLDPLUS) {
- state = m_getfld (state, name, buf, sizeof(buf), fp);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, fp);
fmt_appendcomp(bucket, name, buf);
}
break;
if (c1 == NULL)
c1 = add_queue (&msghd, &msgtl, name, buf, 0);
while (state == FLDPLUS) {
- state = m_getfld (state, name, buf, sizeof(buf), fp);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, fp);
c1->c_text = add (buf, c1->c_text);
fmt_appendcomp(bucket, name, buf);
}
if (dobody && !mh_strcasecmp (c1->c_name, "body")) {
if (c1->c_flags & FMTFILTER && state == BODY &&
formatproc != NULL) {
- filterbody(c1, buf, sizeof(buf), state, fp);
+ filterbody(c1, buf, sizeof(buf), state, fp, gstate);
} else {
holder.c_text = mh_xmalloc (sizeof(buf));
strncpy (holder.c_text, buf, sizeof(buf));
while (state == BODY) {
putcomp (c1, &holder, BODYCOMP);
- state = m_getfld (state, name, holder.c_text,
- sizeof(buf), fp);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, holder.c_text,
+ &bufsz, fp);
}
free (holder.c_text);
holder.c_text = NULL;
break;
}
}
+ m_getfld_state_destroy (&gstate);
return;
case LENERR:
case FMTERR:
advise (NULL, "format error in message %s", mname);
exitstat++;
+ m_getfld_state_destroy (&gstate);
return;
default:
if (!cp[1])
*cp = 0;
- fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1, dat);
+ fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1,
+ dat, NULL);
/* Don't need to append a newline, dctime() already did */
c2->c_text = getcpy (buffer);
p->pq_error = NULL;
}
- fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1, dat);
+ fmt_scan (c1->c_fmt, buffer, sizeof buffer - 1, sizeof buffer - 1,
+ dat, NULL);
if (*buffer) {
if (c2->c_text)
c2->c_text = add (",\n", c2->c_text);
putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
{
int count, cchdr;
- unsigned char *cp;
+ char *cp;
cchdr = 0;
lm = 0;
if (!(c1->c_flags & HDROUTPUT) && !(c1->c_flags & NOCOMPONENT)) {
if (c1->c_flags & UPPERCASE) /* uppercase component also */
for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++)
- if (islower (*cp))
- *cp = toupper (*cp);
+ if (islower ((unsigned char) *cp))
+ *cp = toupper ((unsigned char) *cp);
putstr (c1->c_text ? c1->c_text : c1->c_name, c1->c_flags);
if (flag != BODYCOMP) {
putstr (": ", c1->c_flags);
&& !(c2->c_flags & NOCOMPONENT)) {
if (c1->c_flags & UPPERCASE)
for (cp = c2->c_name; *cp; cp++)
- if (islower (*cp))
- *cp = toupper (*cp);
+ if (islower ((unsigned char) *cp))
+ *cp = toupper ((unsigned char) *cp);
putstr (c2->c_name, c1->c_flags);
putstr (": ", c1->c_flags);
if (!(c1->c_flags & SPLIT))
}
if (c1->c_flags & UPPERCASE)
for (cp = c2->c_text; *cp; cp++)
- if (islower (*cp))
- *cp = toupper (*cp);
+ if (islower ((unsigned char) *cp))
+ *cp = toupper ((unsigned char) *cp);
count = 0;
if (cchdr) {
term = 0;
if (flags & COMPRESS) {
for (spc = 1, cp = ret; *onelp; onelp++)
- if (isspace (*onelp)) {
+ if (isspace ((unsigned char) *onelp)) {
if (*onelp == '\n' && (!onelp[1] || (flags & ADDRFMT))) {
term = '\n';
*onelp++ = 0;
m_popen (char *name)
{
int pd[2];
+ char *file;
+ char **arglist;
if (mhl_action && (sd = dup (fileno (stdout))) == NOTOK)
adios ("standard output", "unable to dup()");
if (pipe (pd) == NOTOK)
adios ("pipe", "unable to");
- switch (m_pid = vfork()) {
+ switch (m_pid = fork()) {
case NOTOK:
adios ("fork", "unable to");
dup2 (pd[0], fileno (stdin));
close (pd[0]);
}
- execlp (name, r1bindex (name, '/'), NULL);
+ arglist = argsplit(name, &file, NULL);
+ execvp (file, arglist);
fprintf (stderr, "unable to exec ");
perror (name);
_exit (-1);
*/
static void
-filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp)
+filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp,
+ m_getfld_state_t gstate)
{
struct mcomp holder;
char name[NAMESZ];
*/
while (state == BODY) {
+ int bufsz2 = bufsz;
write(fdinput[1], buf, strlen(buf));
- state = m_getfld(state, name, buf, bufsz, fp);
+ state = m_getfld (&gstate, name, buf, &bufsz2, fp);
}
/*
*/
switch (filterpid = fork()) {
- char **args;
+ char **args, *program;
struct arglist *a;
- int i, dat[5], s;
+ int i, dat[5], s, argp;
case 0:
/*
- * Allocate an argument array for us
+ * Configure an argument array for us
*/
- args = (char **) mh_xmalloc((filter_nargs + 2) * sizeof(char *));
- args[0] = formatproc;
- args[filter_nargs + 1] = NULL;
+ args = argsplit(formatproc, &program, &argp);
+ args[argp + filter_nargs] = NULL;
dat[0] = 0;
dat[1] = 0;
dat[2] = 0;
* Pull out each argument and scan them.
*/
- for (a = arglist_head, i = 1; a != NULL; a = a->a_next, i++) {
+ for (a = arglist_head, i = argp; a != NULL; a = a->a_next, i++) {
args[i] = mh_xmalloc(BUFSIZ);
- fmt_scan(a->a_fmt, args[i], BUFSIZ - 1, BUFSIZ, dat);
+ fmt_scan(a->a_fmt, args[i], BUFSIZ - 1, BUFSIZ, dat, NULL);
/*
* fmt_scan likes to put a trailing newline at the end of the
* format string. If we have one, get rid of it.
main (int argc, char **argv)
{
pid_t child_id;
- int i, vecp = 1;
- char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ];
- char **argp, **arguments, *vec[MAXARGS];
+ int i, vecp;
+ char *addrs = NULL, *cp, *form = NULL, buf[BUFSIZ], *program;
+ char **argp, **arguments, **vec;
FILE *fp;
char *tfile = NULL;
/* read user profile/context */
context_read();
+ /*
+ * Configure this now, since any unknown switches to rcvdist get
+ * sent to postproc
+ */
+
+ vec = argsplit(postproc, &program, &vecp);
+
mts_init (invo_name);
arguments = getarguments (invo_name, argc, argv, 1);
argp = arguments;
if (distout (drft, tmpfil, backup) == NOTOK)
done (1);
- vec[0] = r1bindex (postproc, '/');
vec[vecp++] = "-dist";
vec[vecp++] = drft;
if ((cp = context_find ("mhlproc"))) {
case NOTOK:
admonish (NULL, "unable to fork");/* fall */
case OK:
- execvp (postproc, vec);
+ execvp (program, vec);
fprintf (stderr, "unable to exec ");
perror (postproc);
_exit (1);
char *cp, *scanl, name[NAMESZ], tmpbuf[SBUFSIZ];
register struct comp *cptr;
FILE *out;
+ m_getfld_state_t gstate = 0;
if (!(out = fopen (drft, "w")))
adios (drft, "unable to create");
if (cptr)
cptr->c_text = addrs;
- for (state = FLD;;) {
- switch (state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb)) {
+ for (;;) {
+ int msg_count = SBUFSIZ;
+ switch (state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb)) {
case FLD:
case FLDPLUS:
i = fmt_addcomptext(name, tmpbuf);
if (i != -1) {
char_read += msg_count;
while (state == FLDPLUS) {
- state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
+ msg_count = SBUFSIZ;
+ state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
fmt_appendcomp(i, name, tmpbuf);
char_read += msg_count;
}
}
- while (state == FLDPLUS)
- state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
+ while (state == FLDPLUS) {
+ msg_count = SBUFSIZ;
+ state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
+ }
break;
case LENERR:
}
}
finished: ;
+ m_getfld_state_destroy (&gstate);
i = format_len + char_read + 256;
scanl = mh_xmalloc ((size_t) i + 2);
dat[0] = dat[1] = dat[2] = dat[4] = 0;
dat[3] = outputlinelen;
- fmt_scan (fmt, scanl, i + 1, i, dat);
+ fmt_scan (fmt, scanl, i + 1, i, dat, NULL);
fputs (scanl, out);
if (ferror (out))
*/
static int insert (struct mailname *);
static void replfilter (FILE *, FILE *, char *, int);
+ static char *replformataddr(char *, char *);
+ static char *replconcataddr(char *, char *);
void
struct format *fmt;
register char **ap;
int char_read = 0, format_len, mask;
- char name[NAMESZ], *scanl;
- unsigned char *cp;
+ char name[NAMESZ], *scanl, *cp;
static int dat[5]; /* aux. data for format routine */
+ m_getfld_state_t gstate = 0;
+ struct fmt_callbacks cb;
FILE *out;
NMH_UNUSED (msg);
/*
* pick any interesting stuff out of msg "inb"
*/
- for (state = FLD;;) {
- state = m_getfld (state, name, tmpbuf, sizeof(tmpbuf), inb);
+ for (;;) {
+ int msg_count = sizeof tmpbuf;
+ state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
switch (state) {
case FLD:
case FLDPLUS:
if (i != -1) {
char_read += msg_count;
while (state == FLDPLUS) {
- state = m_getfld(state, name, tmpbuf,
- sizeof(tmpbuf), inb);
+ msg_count= sizeof tmpbuf;
+ state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
fmt_appendcomp(i, name, tmpbuf);
char_read += msg_count;
}
}
- while (state == FLDPLUS)
- state = m_getfld (state, name, tmpbuf, SBUFSIZ, inb);
+ while (state == FLDPLUS) {
+ msg_count= sizeof tmpbuf;
+ state = m_getfld (&gstate, name, tmpbuf, &msg_count, inb);
+ }
break;
case LENERR:
* format and output the header lines.
*/
finished:
+ m_getfld_state_destroy (&gstate);
/*
* if there's a "Subject" component, strip any "Re:"s off it
register char *sp = cp;
for (;;) {
- while (isspace(*cp))
+ while (isspace((unsigned char) *cp))
cp++;
if(uprf(cp, "re:"))
cp += 3;
dat[2] = 0;
dat[3] = outputlinelen;
dat[4] = 0;
- fmt_scan (fmt, scanl, i + 1, i, dat);
+ memset(&cb, 0, sizeof(cb));
+ cb.formataddr = replformataddr;
+ cb.concataddr = replconcataddr;
+ fmt_scan (fmt, scanl, i + 1, i, dat, &cb);
fputs (scanl, out);
if (badaddrs) {
fputs ("\nrepl: bad addresses:\n", out);
* don't call "getcpy") but still place no upper limit on the
* length of the result string.
*/
- char *
- formataddr (char *orig, char *str)
+ static char *
+ replformataddr (char *orig, char *str)
{
register int len;
char baddr[BUFSIZ], error[BUFSIZ];
* like formataddr, except that it does NOT suppress duplicate addresses
* between calls.
*
- * As an implementation detail: I thought about splitting out formataddr()
+ * As an implementation detail: I thought about splitting out replformataddr()
* into the generic part and duplicate-suppressing part, but the call to
* insert() was buried deep within a couple of loops and I didn't see a
* way to do it easily. So instead we simply set a special flag to stop
- * the duplicate check and call formataddr().
+ * the duplicate check and call replformataddr().
*/
- char *
- concataddr(char *orig, char *str)
+ static char *
+ replconcataddr(char *orig, char *str)
{
char *cp;
nodupcheck = 1;
- cp = formataddr(orig, str);
+ cp = replformataddr(orig, str);
nodupcheck = 0;
return cp;
}
int pid;
char *mhl;
char *errstr;
- char *arglist[7];
+ char **arglist;
+ int argnum;
if (filter == NULL)
return;
if (access (filter, R_OK) == NOTOK)
adios (filter, "unable to read");
- mhl = r1bindex (mhlproc, '/');
-
rewind (in);
lseek (fileno(in), (off_t) 0, SEEK_SET);
- switch (pid = vfork()) {
+ switch (pid = fork()) {
case NOTOK:
adios ("fork", "unable to");
dup2 (fileno (out), fileno (stdout));
closefds (3);
- arglist[0] = mhl;
- arglist[1] = "-form";
- arglist[2] = filter;
- arglist[3] = "-noclear";
+ /*
+ * We're not allocating the memory for the extra arguments,
+ * because we never call arglist_free(). But if we ever change
+ * that be sure to use getcpy() for the extra arguments.
+ */
+ arglist = argsplit(mhlproc, &mhl, &argnum);
+ arglist[argnum++] = "-form";
+ arglist[argnum++] = filter;
+ arglist[argnum++] = "-noclear";
switch (fmtproc) {
case 1:
- arglist[4] = "-fmtproc";
- arglist[5] = formatproc;
- arglist[6] = NULL;
+ arglist[argnum++] = "-fmtproc";
+ arglist[argnum++] = formatproc;
break;
case 0:
- arglist[4] = "-nofmtproc";
- arglist[5] = NULL;
+ arglist[argnum++] = "-nofmtproc";
break;
- default:
- arglist[4] = NULL;
}
- execvp (mhlproc, arglist);
+ arglist[argnum++] = NULL;
+
+ execvp (mhl, arglist);
errstr = strerror(errno);
write(2, "unable to exec ", 15);
write(2, mhlproc, strlen(mhlproc));
static int dat[5]; /* aux. data for format routine */
char *scanl = 0; /* text of most recent scanline */
+m_getfld_state_t gstate; /* for access by msh */
#define DIEWRERR() adios (scnmsg, "write error on")
int unseen, char *folder, long size, int noisy)
{
int i, compnum, encrypted, state;
- unsigned char *cp, *tmpbuf, *startbody;
- char **nxtbuf;
+ char *cp, *tmpbuf, *startbody, **nxtbuf;
char *saved_c_text = NULL;
struct comp *cptr;
struct comp **savecomp;
char *scnmsg = NULL;
FILE *scnout = NULL;
char name[NAMESZ];
+ int bufsz;
static int rlwidth, slwidth;
static size_t scanl_size;
* Get the first field. If the message is non-empty
* and we're doing an "inc", open the output file.
*/
- if ((state = m_getfld (FLD, name, tmpbuf, rlwidth, inb)) == FILEEOF) {
+ bufsz = rlwidth;
+ m_getfld_state_reset (&gstate);
+ if ((state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb)) == FILEEOF) {
if (ferror(inb)) {
advise("read", "unable to"); /* "read error" */
return SCNFAT;
}
/* scan - main loop */
- for (compnum = 1; ; state = m_getfld (state, name, tmpbuf, rlwidth, inb)) {
+ for (compnum = 1; ;
+ bufsz = rlwidth, state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb)) {
switch (state) {
case FLD:
case FLDPLUS:
cptr->c_text = tmpbuf;
for (cp = tmpbuf + strlen (tmpbuf) - 1;
cp >= tmpbuf; cp--)
- if (isspace (*cp))
+ if (isspace ((unsigned char) *cp))
*cp = 0;
else
break;
}
while (state == FLDPLUS) {
- state = m_getfld (state, name, tmpbuf, rlwidth, inb);
+ bufsz = rlwidth;
+ state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb);
if (outnum)
FPUTS (tmpbuf);
}
*/
if ((i = strlen(tmpbuf)) < rlwidth) {
- state = m_getfld (state, name, tmpbuf + i,
- rlwidth - i, inb);
+ bufsz = rlwidth - i;
+ state = m_getfld (&gstate, name, tmpbuf + i, &bufsz, inb);
}
if (! outnum) {
}
while (state == BODY) {
- state = m_getfld(state, name, tmpbuf, rlwidth, inb);
+ bufsz = rlwidth;
+ state = m_getfld (&gstate, name, tmpbuf, &bufsz, inb);
FPUTS(tmpbuf);
}
goto finished;
}
}
- fmt_scan (fmt, scanl, scanl_size, slwidth, dat);
+ fmt_scan (fmt, scanl, scanl_size, slwidth, dat, NULL);
if (bodycomp)
bodycomp->c_text = saved_c_text;
return (0);
}
+/* The following three functions allow access to the global gstate above. */
+void
+scan_finished () {
+ m_getfld_state_destroy (&gstate);
+}
+
+void
+scan_detect_mbox_style (FILE *f) {
+ m_unknown (&gstate, f);
+}
+
+void
+scan_eom_action (int (*action)()) {
+ m_eomsbr (gstate, action);
+}
+
+void
+scan_reset_m_getfld_state () {
+ m_getfld_state_reset (&gstate);
+}