From: Ken Hornstein Date: Tue, 2 Dec 2014 18:12:45 +0000 (-0500) Subject: Merge commit '8206fbf', due to my screwup of committing it on a detached X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/d6b2ae5fa68b9a82ffc006c233aef64c5cdb3bd2?hp=8206fbfd5d6fefa94733293d5cb69deb82cf94d0 Merge commit '8206fbf', due to my screwup of committing it on a detached HEAD after a git-bisect. --- diff --git a/Makefile.am b/Makefile.am index 7ffcf9b0..1cc08753 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,7 +119,7 @@ clean-local: ## ## Stuff that should be cleaned via "make maintainer-clean" ## -MAINTAINERCLEANFILES = cscope.files cscope.out cscope.in.out cscope.po.out *.plist +MAINTAINERCLEANFILES = atags cscope.files cscope.out cscope.in.out cscope.po.out *.plist ## ## And our own superclean, to get everything left by maintainer-clean. @@ -478,8 +478,8 @@ etc_gen_ctype_checked_LDADD = $(POSTLINK) ## Hard-code the config/version.c target, instead of using $@, so this ## rule works for the distcheck target with Solaris (System V) make. ## distcheck uses VPATH, causes that make to prepend the VPATH to $@. -config/version.c: Makefile - sh $(srcdir)/config/version.sh $(VERSION) > ./config/version.c +config/version.c: Makefile $(srcdir)/config/version.sh + env srcdir="$(srcdir)" sh $(srcdir)/config/version.sh $(VERSION) > ./config/version.c sbr/sigmsg.h: $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H) $(AWK) -f $(srcdir)/sbr/sigmsg.awk $(SIGNAL_H) > $@ diff --git a/config/version.sh b/config/version.sh index 1ff7eed4..bf95447d 100755 --- a/config/version.sh +++ b/config/version.sh @@ -38,5 +38,12 @@ done IFS=" " -echo "char *version_str = \"nmh-$VERSION [compiled on $HOSTNAME at `date`]\";" +if [ -d "${srcdir}/.git" ] ; then + branch=`(git branch | grep '^\*' | tr -d '* ') || true` +fi +if [ "${branch}" -a "${branch}" != "master" ] ; then + echo "char *version_str = \"nmh-$VERSION [branch ${branch}] [compiled on $HOSTNAME at `date`]\";" +else + echo "char *version_str = \"nmh-$VERSION [compiled on $HOSTNAME at `date`]\";" +fi echo "char *version_num = \"nmh-$VERSION\";" diff --git a/docs/contrib/build_nmh b/docs/contrib/build_nmh index ba421bf3..499fadea 100755 --- a/docs/contrib/build_nmh +++ b/docs/contrib/build_nmh @@ -131,7 +131,7 @@ if install-mh -check >/dev/null 2>&1; then config_prefix=`cd $mhbin/.. && pwd` - mtsconf=`dirname "$mhbin"`/etc/mts.conf + mtsconf=`mhparam etcdir`/mts.conf if [ -f "$mtsconf" ]; then mts_entry=`grep '^mts:' "$mtsconf"` if [ "$mts_entry" ]; then diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 07c073ab..fe12e698 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -24,6 +24,10 @@ NEW FEATURES obsolete support programs that should be removed. - 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). +- mhfixmsg now removes an extraneous trailing semicolon from header + parameter lists. ----------------- OBSOLETE FEATURES diff --git a/etc/mhn.defaults.sh b/etc/mhn.defaults.sh index 298dae60..d9d35b00 100755 --- a/etc/mhn.defaults.sh +++ b/etc/mhn.defaults.sh @@ -46,6 +46,7 @@ expand | sed -e 's/^ //' -e 's/ *$//'" >> $TMP fi echo "mhstore-store-text: %m%P.txt" >> $TMP +echo "mhstore-store-text/html: %m%P.html" >> $TMP echo "mhstore-store-text/richtext: %m%P.rt" >> $TMP echo "mhstore-store-video/mpeg: %m%P.mpg" >> $TMP echo "mhstore-store-application/PostScript: %m%P.ps" >> $TMP @@ -314,10 +315,17 @@ fi # This entry is used to retrieve external-body types that use a "url" # access-type. -PGM=`$SEARCHPROG "$SEARCHPATH" curl` -if [ ! -z "$PGM" ]; then - echo "nmh-access-url: $PGM -L" >> $TMP -fi +case "`uname`" in + FreeBSD) + echo "nmh-access-url: fetch -o -" >> $TMP + ;; + *) + PGM=`$SEARCHPROG "$SEARCHPATH" curl` + if [ ! -z "$PGM" ]; then + echo "nmh-access-url: $PGM -L" >> $TMP + fi + ;; +esac # output a sorted version of the file sort < $TMP diff --git a/h/fmt_compile.h b/h/fmt_compile.h index b0c12c08..9e94b3c0 100644 --- a/h/fmt_compile.h +++ b/h/fmt_compile.h @@ -73,7 +73,7 @@ #define FT_LV_HOSTTYPE 63 /* set "value" to addr host type */ #define FT_LV_INGRPF 64 /* set "value" to addr in-group flag */ #define FT_LS_UNQUOTE 65 /* remove RFC 2822 quotes from "str" */ -#define FT_LV_NOHOSTF 66 /* set "value" to addr no-host flag */ +#define FT_LV_NOHOSTF 66 /* set "value" to addr no-host flag */ /* Date Coercion */ #define FT_LOCALDATE 67 /* Coerce date to local timezone */ @@ -85,26 +85,28 @@ #define FT_FORMATADDR 71 /* let external routine format addr */ #define FT_CONCATADDR 72 /* formataddr w/out duplicate removal */ #define FT_MYMBOX 73 /* do "mymbox" test on comp */ +#define FT_GETMYMBOX 74 /* return "mymbox" mailbox string */ +#define FT_GETMYADDR 75 /* return "mymbox" addr string */ /* conditionals & control flow (must be last) */ -#define FT_SAVESTR 74 /* save current str reg */ -#define FT_DONE 75 /* stop formatting */ -#define FT_PAUSE 76 /* pause */ -#define FT_NOP 77 /* nop */ -#define FT_GOTO 78 /* (relative) goto */ -#define FT_IF_S_NULL 79 /* test if "str" null */ -#define FT_IF_S 80 /* test if "str" non-null */ -#define FT_IF_V_EQ 81 /* test if "value" = literal */ -#define FT_IF_V_NE 82 /* test if "value" != literal */ -#define FT_IF_V_GT 83 /* test if "value" > literal */ -#define FT_IF_MATCH 84 /* test if "str" contains literal */ -#define FT_IF_AMATCH 85 /* test if "str" starts with literal */ -#define FT_S_NULL 86 /* V = 1 if "str" null */ -#define FT_S_NONNULL 87 /* V = 1 if "str" non-null */ -#define FT_V_EQ 88 /* V = 1 if "value" = literal */ -#define FT_V_NE 89 /* V = 1 if "value" != literal */ -#define FT_V_GT 90 /* V = 1 if "value" > literal */ -#define FT_V_MATCH 91 /* V = 1 if "str" contains literal */ -#define FT_V_AMATCH 92 /* V = 1 if "str" starts with literal */ +#define FT_SAVESTR 76 /* save current str reg */ +#define FT_DONE 77 /* stop formatting */ +#define FT_PAUSE 78 /* pause */ +#define FT_NOP 79 /* nop */ +#define FT_GOTO 80 /* (relative) goto */ +#define FT_IF_S_NULL 81 /* test if "str" null */ +#define FT_IF_S 82 /* test if "str" non-null */ +#define FT_IF_V_EQ 83 /* test if "value" = literal */ +#define FT_IF_V_NE 84 /* test if "value" != literal */ +#define FT_IF_V_GT 85 /* test if "value" > literal */ +#define FT_IF_MATCH 86 /* test if "str" contains literal */ +#define FT_IF_AMATCH 87 /* test if "str" starts with literal */ +#define FT_S_NULL 88 /* V = 1 if "str" null */ +#define FT_S_NONNULL 89 /* V = 1 if "str" non-null */ +#define FT_V_EQ 90 /* V = 1 if "value" = literal */ +#define FT_V_NE 91 /* V = 1 if "value" != literal */ +#define FT_V_GT 92 /* V = 1 if "value" > literal */ +#define FT_V_MATCH 93 /* V = 1 if "str" contains literal */ +#define FT_V_AMATCH 94 /* V = 1 if "str" starts with literal */ #define IF_FUNCS FT_S_NULL /* start of "if" functions */ diff --git a/h/fmt_scan.h b/h/fmt_scan.h index 2bcc265f..5f659d4c 100644 --- a/h/fmt_scan.h +++ b/h/fmt_scan.h @@ -114,6 +114,12 @@ struct fmt_callbacks { char *new_fs (char *form, char *format, char *default_fs); +/* + * Free memory allocated by new_fs(). It allocates to a static so + * no argument is necessary. + */ +void free_fs (); + /* * Compile a format string into a set of format instructions. Arguments are: * diff --git a/h/mh.h b/h/mh.h index f1568a48..b8c60ca8 100644 --- a/h/mh.h +++ b/h/mh.h @@ -1,4 +1,3 @@ - /* * mh.h -- main header file for all of nmh */ @@ -61,6 +60,7 @@ void charstring_push_back (charstring_t, const char); /* Append possibly multi-byte character(s): */ void charstring_push_back_chars (charstring_t, const char [], size_t, size_t); void charstring_append (charstring_t, const charstring_t); +void charstring_append_cstring (charstring_t, const char []); void charstring_clear (charstring_t); /* Don't store return value of charstring_buffer() and use later after intervening push_back's; use charstring_buffer_copy() instead. */ diff --git a/h/mhparse.h b/h/mhparse.h index b9e7b90e..371e671a 100644 --- a/h/mhparse.h +++ b/h/mhparse.h @@ -205,6 +205,7 @@ struct text { #define MULTI_ALTERNATE 0x02 #define MULTI_DIGEST 0x03 #define MULTI_PARALLEL 0x04 +#define MULTI_RELATED 0x05 /* Structure for subparts of a multipart content */ struct part { @@ -528,3 +529,13 @@ int show_content_aux(CT ct, int alternate, char *cp, char *cracked, struct format *fmt); extern int checksw; /* Add Content-MD5 field */ + +/* + * mhstore + * Put it here because it uses the CT typedef. + */ +typedef struct mhstoreinfo *mhstoreinfo_t; +mhstoreinfo_t mhstoreinfo_create(CT *, char *, const char *, int, int); +int mhstoreinfo_files_not_clobbered(const mhstoreinfo_t); +void mhstoreinfo_free(mhstoreinfo_t); +void store_all_messages (mhstoreinfo_t); diff --git a/h/mime.h b/h/mime.h index 92d6462a..9fcaf5d3 100644 --- a/h/mime.h +++ b/h/mime.h @@ -12,7 +12,9 @@ #define DESCR_FIELD "Content-Description" #define DISPO_FIELD "Content-Disposition" #define MD5_FIELD "Content-MD5" -#define ATTACH_FIELD "Attach" +#define PSEUDOHEADER_PREFIX "Nmh-" +#define ATTACH_FIELD PSEUDOHEADER_PREFIX "Attach" +#define ATTACH_FIELD_ALT "Attach" #define isatom(c) (isascii((unsigned char) c) \ && !isspace ((unsigned char) c) \ diff --git a/h/utils.h b/h/utils.h index 92c940de..cd696784 100644 --- a/h/utils.h +++ b/h/utils.h @@ -5,6 +5,7 @@ void *mh_xmalloc(size_t); void *mh_xrealloc(void *, size_t); +void *mh_xcalloc(size_t, size_t); char *pwd(void); char *add(const char *, char *); char *addlist(char *, const char *); diff --git a/man/mh-alias.man b/man/mh-alias.man index 7ebbf0f8..9a7776eb 100644 --- a/man/mh-alias.man +++ b/man/mh-alias.man @@ -1,4 +1,4 @@ -.TH MH-ALIAS %manext5% "Apr 18, 2014" "%nmhversion%" +.TH MH-ALIAS %manext5% "November 15, 2014" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -105,8 +105,8 @@ An approximation of the way aliases are resolved at posting time is: Build a list of all addresses from the message to be delivered, eliminating duplicate addresses. .IP 2) -If this draft originated on the local host, then for those addresses in -the message that have no host specified, perform alias resolution. +For those addresses in the message that have no host specified, +perform alias resolution. .IP 3) For each line in the alias file, compare \*(lqalias\*(rq against all of the existing addresses. If a match, remove the matched \*(lqalias\*(rq diff --git a/man/mh-format.man b/man/mh-format.man index 7ac0bc0d..1e2f41a5 100644 --- a/man/mh-format.man +++ b/man/mh-format.man @@ -1,4 +1,4 @@ -.TH MH-FORMAT %manext5% "November 4, 2012" "%nmhversion%" +.TH MH-FORMAT %manext5% "October 27, 2014" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -366,7 +366,7 @@ mon date integer month of the year month date string month of the year (abbrev.) lmonth date string month of the year year date integer year (may be > 100) -zone date integer timezone in hours +zone date integer timezone in minutes tzone date string timezone string szone date integer timezone explicit? (1=explicit,0=implicit,\-1=unknown) @@ -395,7 +395,11 @@ addr addr string mbox@host or host!mbox rendering* pers addr string the personal name* note addr string commentary text* mbox addr string the local mailbox* -mymbox addr integer List has the user's address? (0 or 1) +mymbox addr integer list has the user's address? (0 or 1) +getmymbox addr string the user's (first) address, + with personal name +getmyaddr addr string the user's (first) address, + without personal name host addr string the host domain* nohost addr integer no host was present (0 or 1)* type addr integer host type* (0=local,1=network, diff --git a/man/mhfixmsg.man b/man/mhfixmsg.man index 81d069ba..3bb8e84e 100644 --- a/man/mhfixmsg.man +++ b/man/mhfixmsg.man @@ -1,4 +1,4 @@ -.TH MHFIXMSG %manext1% "August 20, 2014" "%nmhversion%" +.TH MHFIXMSG %manext1% "November 30, 2014" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -28,6 +28,7 @@ mhfixmsg \- rewrite MIME messages with various transformations .RB [ \-rmmproc .IR program ] .RB [ \-normmproc ] +.RB [ \-changecur " | " \-nochangecur ] .RB [ \-verbose " | " \-noverbose ] .RB [ \-version ] .RB [ \-help ] @@ -148,12 +149,28 @@ and other .B nmh programs that parse MIME messages. .PP +.B mhfixmsg +applies one transformation unconditionally: it removes an extraneous +trailing semicolon from the parameter lists of MIME header fields. +.PP The .B \-verbose switch directs .B mhfixmsg to output informational message for each transformation applied. .PP +The return status of +.B mhfixmsg +is 0 if all of the requested transformations are performed, or +non-zero otherwise. +.RB ( mhfixmsg +will not decode to binary content, but a request to do so is +not considered a failure, and is noted with +.BR \-verbose .) +If a problem is detected with any one of multiple messages such that +the return status is non-zero, then none of the messages will be +modified. +.PP The .B \-file .I file @@ -261,12 +278,19 @@ call .B mhfixmsg immediately after a successful invocation of .BR inc . -For example, with bash: +One approach could be based on: .PP .RS 5 -alias inc='inc && mhfixmsg' +msgs=`inc -format '%(msg)'` && [ -n "$msgs" ] && scan $msgs && \ +mhfixmsg -nochangecur $msgs .RE .PP +Another approach would rely on adding a sequence to Unseen-Sequence, +which +.B inc +sets with the newly incorporated messages. Those could then be +supplied to +.BR mhfixmsg . .SS "Integration with procmail" By way of example, here is an excerpt from a procmailrc file that filters messages through @@ -346,12 +370,15 @@ is checked. .RB ` \-noreplacetextplain ' .RB ` \-fixboundary ' .RB ` \-fixcte ' +.RB ` \-changecur ' .RB ` \-noverbose ' .fi .SH CONTEXT If a folder is given, it will become the current folder. The last -message selected from a folder will become the current message. If +message selected from a folder will become the current message, unless the +.B \-nochangecur +switch is enabled. If the .B \-file switch or an absolute pathname is used, the context will not be modified. diff --git a/man/mhstore.man b/man/mhstore.man index fe50d253..fbdd3702 100644 --- a/man/mhstore.man +++ b/man/mhstore.man @@ -141,7 +141,6 @@ as a Content-MD5 header field), then will attempt to verify the integrity of the content. .SS "Storing the Contents" -The .B mhstore will store the contents of the named messages in \*(lqnative\*(rq (decoded) format. Two things must be determined: diff --git a/man/repl.man b/man/repl.man index 72325e50..208676e9 100644 --- a/man/repl.man +++ b/man/repl.man @@ -1,4 +1,4 @@ -.TH REPL %manext1% "April 18, 2014" "%nmhversion%" +.TH REPL %manext1% "November 4, 2014" "%nmhversion%" .\" .\" %nmhwarning% .\" @@ -9,7 +9,7 @@ repl \- reply to a message .na .B repl .RI [ +folder ] -.RI [ msgs ] +.RI [ msg ] .RB [ \-annotate " | " \-noannotate ] .RB [ \-group " | " \-nogroup ] .RB [ \-cc diff --git a/sbr/addrsbr.c b/sbr/addrsbr.c index 3028847a..23a7cb4c 100644 --- a/sbr/addrsbr.c +++ b/sbr/addrsbr.c @@ -11,6 +11,7 @@ #include #include #include +#include /* High level parsing of addresses: @@ -138,7 +139,7 @@ getm (char *str, char *dfhost, int dftype, char *eresult, size_t eresultsize) dftype = LOCALHOST; } - mp = (struct mailname *) calloc ((size_t) 1, sizeof(*mp)); + mp = (struct mailname *) mh_xcalloc ((size_t) 1, sizeof(*mp)); if (mp == NULL) { if (eresult) { strncpy (eresult, "insufficient memory to represent address", diff --git a/sbr/charstring.c b/sbr/charstring.c index d007e7b5..d94961aa 100644 --- a/sbr/charstring.c +++ b/sbr/charstring.c @@ -102,13 +102,25 @@ charstring_append (charstring_t dest, const charstring_t src) { const size_t num = src->cur - src->buffer; if (num > 0) { - charstring_reserve (dest, num + (dest->cur - dest->buffer)); + charstring_reserve (dest, dest->cur - dest->buffer + num); memcpy (dest->cur, src->buffer, num); dest->cur += num; dest->chars += src->chars; } } +void +charstring_append_cstring (charstring_t dest, const char src[]) { + const size_t num = strlen (src); + + if (num > 0) { + charstring_reserve (dest, dest->cur - dest->buffer + num); + memcpy (dest->cur, src, num); /* Exclude src's trailing newline. */ + dest->cur += num; + dest->chars += num; + } +} + void charstring_clear (charstring_t s) { s->cur = s->buffer; @@ -134,14 +146,12 @@ charstring_buffer (const charstring_t s) { char * charstring_buffer_copy (const charstring_t s) { - char *copy = strdup (charstring_buffer (s)); + char *copy = mh_xmalloc (s->cur - s->buffer + 1); - if (copy) { - return copy; - } else { - advise ("strdup", "unable to copy charstring buffer"); - return NULL; - } + /* Use charstring_buffer() to null terminate the buffer. */ + memcpy (copy, charstring_buffer (s), s->cur - s->buffer + 1); + + return copy; } size_t diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 62b27eac..dd43dc8a 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -223,6 +223,8 @@ static struct ftable functable[] = { { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, + { "getmymbox", TF_COMP, FT_STR, FT_GETMYMBOX, 0 }, + { "getmyaddr", TF_COMP, FT_LS_ADDR, FT_GETMYADDR, TFL_PUTS }, { "unquote", TF_EXPR, FT_LS_UNQUOTE, 0, TFL_PUTS }, @@ -284,7 +286,7 @@ static struct colormap colortable[] = { /* Add new component to the hash table */ #define NEWCOMP(cm,name) do { \ - cm = ((struct comp *) calloc(1, sizeof (struct comp)));\ + cm = ((struct comp *) mh_xcalloc (1, sizeof (struct comp)));\ cm->c_name = getcpy(name);\ cm->c_refcount++;\ ncomp++;\ @@ -406,7 +408,7 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable) */ i = strlen(fstring)/2 + 1; if (i==1) i++; - next_fp = formatvec = (struct format *)calloc ((size_t) i, + next_fp = formatvec = (struct format *)mh_xcalloc ((size_t) i, sizeof(struct format)); if (next_fp == NULL) adios (NULL, "unable to allocate format storage"); @@ -562,14 +564,19 @@ do_name(char *sp, int preprocess) if (cm->c_type & CT_ADDR) { CERROR("component used as both date and address"); } - cm->c_tws = (struct tws *) - calloc((size_t) 1, sizeof(*cm->c_tws)); + if (cm->c_tws) { + memset (cm->c_tws, 0, sizeof *cm->c_tws); + } else { + cm->c_tws = mh_xcalloc (1, sizeof *cm->c_tws); + } fp->f_type = preprocess; PUTCOMP(sp); cm->c_type |= CT_DATE; break; case FT_MYMBOX: + case FT_GETMYMBOX: + case FT_GETMYADDR: if (!primed) { ismymbox ((struct mailname *) 0); primed++; diff --git a/sbr/fmt_new.c b/sbr/fmt_new.c index 44a18b37..9ee89561 100644 --- a/sbr/fmt_new.c +++ b/sbr/fmt_new.c @@ -58,6 +58,13 @@ new_fs (char *form, char *format, char *default_fs) } +void +free_fs (){ + free (formats); + formats = 0; +} + + /* * Expand escapes in format strings */ diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 08405da1..5732af91 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -832,7 +832,7 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, value = -1; break; case FT_LV_DST: - value = fmt->f_comp->c_tws->tw_flags & TW_DST; + value = fmt->f_comp->c_tws->tw_flags & TW_DST ? 1 : 0; break; case FT_LS_822DATE: str = dasctime (fmt->f_comp->c_tws , TW_ZONE); @@ -1062,6 +1062,8 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, break; case FT_MYMBOX: + case FT_GETMYMBOX: + case FT_GETMYADDR: /* * if there's no component, we say true. Otherwise we * say "true" only if we can parse the address and it @@ -1073,24 +1075,46 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, if ((sp = comp->c_text) && (sp = getname(sp)) && (mn = getm (sp, NULL, 0, NULL, 0))) { comp->c_mn = mn; - if (ismymbox(mn)) + if (ismymbox(mn)) { comp->c_flags |= CF_TRUE; - else + /* Set str for use with FT_GETMYMBOX. With + FT_GETMYADDR, comp->c_mn will be run through + FT_LS_ADDR, which will strip off any pers + name. */ + str = mn->m_text; + } else { comp->c_flags &= ~CF_TRUE; + } while ((sp = getname(sp))) if ((comp->c_flags & CF_TRUE) == 0 && (mn = getm (sp, NULL, 0, NULL, 0))) - if (ismymbox(mn)) + if (ismymbox(mn)) { comp->c_flags |= CF_TRUE; + /* Set str and comp->c_text for use with + FT_GETMYMBOX. With FT_GETMYADDR, + comp->c_mn will be run through + FT_LS_ADDR, which will strip off any + pers name. */ + free (comp->c_text); + comp->c_text = str = strdup (mn->m_text); + comp->c_mn = mn; + } + comp->c_flags |= CF_PARSED; } else { while (getname("")) /* XXX */ ; if (comp->c_text == 0) comp->c_flags |= CF_TRUE; - else + else { comp->c_flags &= ~CF_TRUE; + } comp->c_mn = &fmt_mnull; } + if ((comp->c_flags & CF_TRUE) == 0 && + (fmt->f_type == FT_GETMYMBOX || fmt->f_type == FT_GETMYADDR)) { + /* Fool FT_LS_ADDR into not producing an address. */ + comp->c_mn = &fmt_mnull; comp->c_text = NULL; + } break; } diff --git a/sbr/m_getfld.c b/sbr/m_getfld.c index 902e9933..b0960547 100644 --- a/sbr/m_getfld.c +++ b/sbr/m_getfld.c @@ -825,7 +825,7 @@ m_unknown(m_getfld_state_t *gstate, FILE *iob) * separator) or the last char (since the matchc would have found it * if it was a real delim). */ - s->pat_map = (char **) calloc (256, sizeof(char *)); + s->pat_map = (char **) mh_xcalloc (256, sizeof(char *)); for (cp = s->fdelim + 1; cp < s->delimend; cp++ ) s->pat_map[(unsigned char)*cp] = cp; diff --git a/sbr/utils.c b/sbr/utils.c index 9dece994..c6f75e07 100644 --- a/sbr/utils.c +++ b/sbr/utils.c @@ -64,6 +64,24 @@ mh_xrealloc(void *ptr, size_t size) return memory; } +/* + * Safely call calloc + */ +void * +mh_xcalloc(size_t nmemb, size_t size) +{ + void *memory; + + if (nmemb == 0 || size == 0) + adios(NULL, "Tried to calloc 0 bytes"); + + if ((memory = calloc(nmemb, size))) { + return memory; + } else { + adios(NULL, "calloc failed"); + } +} + /* * Return the present working directory, if the current directory does not * exist, or is too long, make / the pwd. diff --git a/test/format/test-mymbox b/test/format/test-mymbox index 753f92e7..42f584c1 100755 --- a/test/format/test-mymbox +++ b/test/format/test-mymbox @@ -31,9 +31,9 @@ myname="Random User " #### Remove existing Local-Mailbox: profile component, if any. Then #### add one. -grep -v 'Local-Mailbox: ' ${MH} > ${MH}.new -mv -f ${MH}.new ${MH} -echo "Local-Mailbox: ${myname}" >> ${MH} +grep -v 'Local-Mailbox: ' "$MH" > "$MH".new +mv -f "$MH".new "$MH" +echo "Local-Mailbox: ${myname}" >> "$MH" run_test "echo \ `run_prog ${MH_LIBEXEC_DIR}/ap -format '%(mymbox{text})' "${myname}"`" \ @@ -50,4 +50,42 @@ run_test "echo \ `run_prog ${MH_LIBEXEC_DIR}/ap -format '%(mymbox{text})' "${myname}"`" \ 1 "Local-Mailbox with Alternate-Mailbox test" +# check getmymbox, without match +run_test 'fmttest -message -format %(getmymbox{from}) first' '' + +# check getmyaddr, without match +run_test 'fmttest -message -format %(getmyaddr{from}) first' '' + +grep -v 'Alternate-Mailboxes: ' "$MH" > "$MH".new +mv -f "$MH".new "$MH" +cat >>"$MH" <' + +# check getmyaddr, with match +run_test 'fmttest -message -format %(getmyaddr{from}) first' \ + 'test1@example.com' + +# check getmymbox and getmyaddr, with match of other than first address in +# component +cat >`mhpath new` <<'EOF' +From: Test11 +Cc: Test0 , Test3 , + Test1 , Test2 +To: Some User +Date: Fri, 29 Sep 2006 00:00:00 +Message-Id: 11@test.nmh +Subject: Testing message 11 + +This is message number 11 +EOF +run_test 'fmttest -message -format %(getmymbox{cc}) last' \ + 'Test1 ' +run_test 'fmttest -message -format %(getmyaddr{cc}) last' \ + 'test1@example.com' + exit $failed diff --git a/test/mhbuild/test-attach b/test/mhbuild/test-attach index 11e05512..3e20158a 100755 --- a/test/mhbuild/test-attach +++ b/test/mhbuild/test-attach @@ -1,7 +1,7 @@ #!/bin/sh ###################################################### # -# Test the use of the Attach: header +# Test the use of the Nmh-Attach: header # ###################################################### @@ -29,7 +29,7 @@ cat > "$draft" < cc: Fcc: +outbox -Attach: ${srcdir}/test/mhbuild/tiny.jpg +Nmh-Attach: ${srcdir}/test/mhbuild/tiny.jpg ------ EOF @@ -59,8 +59,8 @@ cat > "$draft" < cc: Fcc: +outbox -Attach: ${srcdir}/test/mhbuild/tiny.jpg -Attach: ${srcdir}/test/mhbuild/nulls +Nmh-Attach: ${srcdir}/test/mhbuild/tiny.jpg +Nmh-Attach: ${srcdir}/test/mhbuild/nulls ------ This is a test EOF @@ -108,7 +108,7 @@ cat > "$draft" < cc: Fcc: +outbox -Attach: +Nmh-Attach: ------ This is a test of an empty attach header. EOF @@ -243,7 +243,7 @@ check "$draft" "$expected" # # Two parts, one attachment; make sure mixing of multiparts at different -# levels works +# levels works. This also tests Attach: instead of Nmh-Attach:. # cat > "$draft" <"$expected" <`mhpath new` < -------=_nmh-multipart1-- - ------=_Part_90310_101292502.1 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -834,32 +823,7 @@ Your email client does not support HTML messages ------=_Part_90310_101292502.1-- EOF -cat >`mhpath new` < - - HTML Content - - - This is the real content. - - -------=_Part_90310_101292502.1 -Content-Type: text/plain; charset="us-ascii" -Content-Transfer-Encoding: 7bit - -Your email client does not support HTML messages -------=_Part_90310_101292502.1-- -EOF +cp -p `mhpath last` "$expected" if [ $can_reformat_texthtml -eq 1 ]; then #### lynx inserts multiple blank lines, so squeeze them. @@ -1065,6 +1029,58 @@ run_prog mhfixmsg last -replacetextplain -noreplacetextplain -outfile "$actual" check "$expected" "$actual" +# check removal of extraneous trailing semicolon from header parameter list +cat >"$expected" <`mhpath new` <"$MH_TEST_DIR/Mail/rmmproc" <<'EOF' mv "$1" "$1.backup" diff --git a/test/mhstore/test-mhstore b/test/mhstore/test-mhstore index 06dc4745..fdf950ab 100755 --- a/test/mhstore/test-mhstore +++ b/test/mhstore/test-mhstore @@ -212,7 +212,11 @@ check "$expected" 11.2.txt 'keep first' # check -nocheck, the default run_test 'mhstore last -part 2 -check -nocheck' \ 'storing message 11 part 2 as file 11.2.txt' -check "$expected" 11.2.txt +check "$expected" 11.2.txt 'keep first' + +# check -outfile - with -file +run_prog mhstore -noverbose -file `mhpath 11` -part 2 -outfile - >"$actual" 2>&1 +check "$expected" "$actual" # check reassembly of message/partial messages (RFC 1521, 7.3.2) msgfile=`mhpath new` diff --git a/test/repl/test-repl b/test/repl/test-repl index 63d99dde..e4856d08 100755 --- a/test/repl/test-repl +++ b/test/repl/test-repl @@ -29,8 +29,7 @@ Usage: repl: [+folder] [msg] [switches] switches are: -[no]group -[no]annotate - -cc all|to|cc|me - -nocc type + -[no]cc all|to|cc|me -draftfolder +folder -draftmessage msg -nodraftfolder diff --git a/uip/ap.c b/uip/ap.c index b231a0eb..b124c306 100644 --- a/uip/ap.c +++ b/uip/ap.c @@ -11,6 +11,7 @@ #include #include #include +#include #define NADDRS 100 @@ -154,7 +155,7 @@ process (char *arg, int length) (q = &pq)->pq_next = NULL; while ((cp = getname (arg))) { - if ((p = (struct pqpair *) calloc ((size_t) 1, sizeof(*p))) == NULL) + if ((p = (struct pqpair *) mh_xcalloc ((size_t) 1, sizeof(*p))) == NULL) adios (NULL, "unable to allocate pqpair memory"); if ((mp = getm (cp, NULL, 0, error, sizeof(error))) == NULL) { p->pq_text = getcpy (cp); diff --git a/uip/burst.c b/uip/burst.c index 71b226c1..5375f8a1 100644 --- a/uip/burst.c +++ b/uip/burst.c @@ -165,7 +165,7 @@ main (int argc, char **argv) seq_setprev (mp); /* set the previous-sequence */ smsgs = (struct smsg *) - calloc ((size_t) (MAXFOLDER + 2), sizeof(*smsgs)); + mh_xcalloc ((size_t) (MAXFOLDER + 2), sizeof(*smsgs)); if (smsgs == NULL) adios (NULL, "unable to allocate burst storage"); diff --git a/uip/dropsbr.c b/uip/dropsbr.c index 66edece3..f6d67a08 100644 --- a/uip/dropsbr.c +++ b/uip/dropsbr.c @@ -164,7 +164,7 @@ mbx_read (FILE *fp, long pos, struct drop **drops, int noisy) char buffer[BUFSIZ]; register struct drop *cp, *dp, *ep, *pp; - pp = (struct drop *) calloc ((size_t) (len = MAXFOLDER), sizeof(*dp)); + pp = (struct drop *) mh_xcalloc ((size_t) (len = MAXFOLDER), sizeof(*dp)); if (pp == NULL) { if (noisy) admonish (NULL, "unable to allocate drop storage"); @@ -504,7 +504,7 @@ map_read (char *file, long pos, struct drop **drops, int noisy) } msgp = mp->d_id; - dp = (struct drop *) calloc ((size_t) (msgp + 1), sizeof(*dp)); + dp = (struct drop *) mh_xcalloc ((size_t) (msgp + 1), sizeof(*dp)); if (dp == NULL) { close (md); return 0; diff --git a/uip/fmtdump.c b/uip/fmtdump.c index 86dbfefc..463c7edf 100644 --- a/uip/fmtdump.c +++ b/uip/fmtdump.c @@ -210,6 +210,8 @@ dumpone(struct format *fmt) case FT_LS_FRIENDLY: case FT_PARSEADDR: case FT_MYMBOX: + case FT_GETMYMBOX: + case FT_GETMYADDR: printf(", c_name "); litputs(fmt->f_comp->c_name); if (fmt->f_comp->c_type) @@ -413,6 +415,8 @@ f_typestr(int t) case FT_FORMATADDR: return("FORMATADDR"); case FT_CONCATADDR: return("CONCATADDR"); case FT_MYMBOX: return("MYMBOX"); + case FT_GETMYMBOX: return("GETMYMBOX"); + case FT_GETMYADDR: return("GETMYADDR"); case FT_SAVESTR: return("SAVESTR"); #ifdef FT_PAUSE case FT_PAUSE: return ("PAUSE"); diff --git a/uip/fmttest.c b/uip/fmttest.c index 90df1e9e..a7742bd1 100644 --- a/uip/fmttest.c +++ b/uip/fmttest.c @@ -420,7 +420,7 @@ process_addresses(struct format *fmt, struct msgs_array *addrs, for (i = 0; i < addrs->size; i++) { (q = &pq)->pq_next = NULL; while ((cp = getname(addrs->msgs[i]))) { - if ((p = (struct pqpair *) calloc ((size_t) 1, sizeof(*p))) == NULL) + if ((p = (struct pqpair *) mh_xcalloc ((size_t) 1, sizeof(*p))) == NULL) adios (NULL, "unable to allocate pqpair memory"); if ((mp = getm(cp, NULL, 0, error, sizeof(error))) == NULL) { p->pq_text = getcpy(cp); @@ -846,6 +846,8 @@ dumpone(struct format *fmt) case FT_LS_FRIENDLY: case FT_PARSEADDR: case FT_MYMBOX: + case FT_GETMYMBOX: + case FT_GETMYADDR: printf(", c_name "); litputs(fmt->f_comp->c_name); if (fmt->f_comp->c_type) @@ -1086,6 +1088,8 @@ f_typestr(int t) case FT_FORMATADDR: return("FORMATADDR"); case FT_CONCATADDR: return("CONCATADDR"); case FT_MYMBOX: return("MYMBOX"); + case FT_GETMYMBOX: return("GETMYMBOX"); + case FT_GETMYADDR: return("GETMYADDR"); #ifdef FT_ADDTOSEQ case FT_ADDTOSEQ: return("ADDTOSEQ"); #endif @@ -1334,8 +1338,8 @@ mlistfree(void) { struct mailname *mp, *mp2; - for (mp = mq.m_next; mp; mp = mp2->m_next) { - mp2 = mp; + for (mp = mq.m_next; mp; mp = mp2) { + mp2 = mp->m_next; mnfree(mp); } } diff --git a/uip/install-mh.c b/uip/install-mh.c index 2240f870..ce8e2940 100644 --- a/uip/install-mh.c +++ b/uip/install-mh.c @@ -208,6 +208,13 @@ query: */ if ((out = fopen (defpath, "w")) == NULL) adios (defpath, "unable to write"); + /* + * The main purpose of this first line is to fool file(1). + * Without it, if the first line of the profile is Path:, + * file 5.19 reports its type as message/news. With it, + * it reports the type as text/plain. + */ + fprintf (out, "MH-Profile-Version: 1.0\n"); for (np = m_defs; np; np = np->n_next) { if (!np->n_context) fprintf (out, "%s: %s\n", np->n_name, np->n_field); diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index 68c555d3..e046886f 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -145,7 +145,7 @@ build_mime (char *infile, int autobuild, int dist, int directives, /* * Allocate space for primary (outside) content */ - if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL) + if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL) adios (NULL, "out of memory"); /* @@ -205,7 +205,8 @@ build_mime (char *infile, int autobuild, int dist, int directives, * header; in that case, add it to our attach list */ - if (strcasecmp(ATTACH_FIELD, np) == 0) { + if (strcasecmp(ATTACH_FIELD, np) == 0 || + strcasecmp(ATTACH_FIELD_ALT, np) == 0) { struct attach_list *entry; char *s = vp, *e = vp + strlen(vp) - 1; free(np); @@ -295,7 +296,7 @@ finish_field: ct->c_type = CT_MULTIPART; ct->c_subtype = MULTI_MIXED; - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) + if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) m; pp = &m->mp_parts; @@ -315,7 +316,7 @@ finish_field: if (!p) continue; - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *pp = part; pp = &part->mp_next; @@ -336,7 +337,7 @@ finish_field: adios("reading", "Unable to open %s for", at_entry->filename); } - if ((p = (CT) calloc (1, sizeof(*p))) == NULL) + if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL) adios(NULL, "out of memory"); init_decoded_content(p, infile); @@ -349,7 +350,7 @@ finish_field: setup_attach_content(p, at_entry->filename); - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *pp = part; pp = &part->mp_next; @@ -370,7 +371,7 @@ finish_field: struct part *part; struct text *t; - if ((p = (CT) calloc (1, sizeof(*p))) == NULL) + if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL) adios(NULL, "out of memory"); init_decoded_content(p, infile); @@ -390,13 +391,13 @@ finish_field: p->c_begin = ftell(in); p->c_end = ftell(in); - if ((t = (struct text *) calloc (1, sizeof (*t))) == NULL) + if ((t = (struct text *) mh_xcalloc (1, sizeof (*t))) == NULL) adios (NULL, "out of memory"); t->tx_charset = CHARSET_SPECIFIED; p->c_ctparams = t; - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *pp = part; part->mp_part = p; @@ -544,7 +545,7 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename) } /* allocate basic Content structure */ - if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL) + if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL) adios (NULL, "out of memory"); *ctp = ct; @@ -776,7 +777,7 @@ use_forw: * reference, we need to create another Content structure * for the message/external-body to wrap it in. */ - if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL) + if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL) adios (NULL, "out of memory"); init_decoded_content(ct, infilename); *ctp = ct; @@ -785,7 +786,7 @@ use_forw: ct->c_type = CT_MESSAGE; ct->c_subtype = MESSAGE_EXTERNAL; - if ((e = (struct exbody *) calloc (1, sizeof(*e))) == NULL) + if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) e; @@ -895,7 +896,7 @@ use_forw: ct->c_type = CT_MULTIPART; ct->c_subtype = MULTI_DIGEST; - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) + if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) m; pp = &m->mp_parts; @@ -906,7 +907,7 @@ use_forw: CT p; CE pe; - if ((p = (CT) calloc (1, sizeof(*p))) == NULL) + if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL) adios (NULL, "out of memory"); init_decoded_content (p, infilename); pe = &p->c_cefile; @@ -920,7 +921,7 @@ use_forw: if (listsw && stat (pe->ce_file, &st) != NOTOK) p->c_end = (long) st.st_size; - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *pp = part; pp = &part->mp_next; @@ -981,7 +982,7 @@ use_forw: ct->c_type = CT_MULTIPART; ct->c_subtype = vrsn; - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) + if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) m; @@ -998,7 +999,7 @@ use_forw: if (!p) continue; - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *pp = part; pp = &part->mp_next; diff --git a/uip/mhfixmsg.c b/uip/mhfixmsg.c index 4d5083c6..8acd200e 100644 --- a/uip/mhfixmsg.c +++ b/uip/mhfixmsg.c @@ -30,6 +30,8 @@ X("outfile file", 0, OUTFILESW) \ X("rmmproc program", 0, RPROCSW) \ X("normmproc", 0, NRPRCSW) \ + X("changecur", 0, CHGSW) \ + X("nochangecur", 0, NCHGSW) \ X("verbose", 0, VERBSW) \ X("noverbose", 0, NVERBSW) \ X("version", 0, VERSIONSW) \ @@ -53,6 +55,9 @@ int debugsw; /* Needed by mhparse.c. */ extern int skip_mp_cte_check; /* flag to InitMultiPart */ extern int suppress_bogus_mp_content_warning; /* flag to InitMultiPart */ extern int bogus_mp_content; /* flag from InitMultiPart */ +/* flags to/from parse_header_attrs */ +extern int suppress_extraneous_trailing_semicolon_warning; +extern int extraneous_trailing_semicolon; /* mhoutsbr.c */ int output_message (CT, char *); @@ -83,6 +88,8 @@ static int replace_boundary (CT, char *, char *); static int fix_multipart_cte (CT, int *); static int set_ce (CT, int); static int ensure_text_plain (CT *, CT, int *, int); +static int find_textplain_sibling (CT, int, int *); +static int insert_new_text_plain_part (CT, int, CT); static CT build_text_plain_part (CT); static CT divide_part (CT); static void copy_ctinfo (CI, CI); @@ -97,6 +104,7 @@ static int decode_text_parts (CT, int, int *); static int content_encoding (CT, const char **); static int strip_crs (CT, int *); static int convert_charsets (CT, char *, int *); +static int fix_always (CT, int *); static int write_content (CT, char *, char *, int, int); static int remove_file (char *); static void report (char *, char *, char *, char *, ...); @@ -114,6 +122,7 @@ main (int argc, char **argv) { CT *ctp; FILE *fp; int using_stdin = 0; + int chgflag = 1; int status = OK; fix_transformations fx; fx.reformat = fx.fixcte = fx.fixboundary = 1; @@ -212,6 +221,12 @@ main (int argc, char **argv) { case NRPRCSW: rmmproc = NULL; continue; + case CHGSW: + chgflag = 1; + continue; + case NCHGSW: + chgflag = 0; + continue; case VERBSW: verbosw = 1; continue; @@ -247,6 +262,7 @@ main (int argc, char **argv) { } suppress_bogus_mp_content_warning = skip_mp_cte_check = 1; + suppress_extraneous_trailing_semicolon_warning = 1; if (! context_find ("path")) free (path ("./", TFOLDER)); @@ -285,7 +301,7 @@ main (int argc, char **argv) { } } - if (! (cts = (CT *) calloc ((size_t) 2, sizeof *cts))) { + if (! (cts = (CT *) mh_xcalloc ((size_t) 2, sizeof *cts))) { adios (NULL, "out of memory"); } ctp = cts; @@ -320,7 +336,8 @@ main (int argc, char **argv) { done (1); seq_setprev (mp); /* set the previous-sequence */ - if (! (cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof *cts))) { + if (! (cts = + (CT *) mh_xcalloc ((size_t) (mp->numsel + 1), sizeof *cts))) { adios (NULL, "out of memory"); } ctp = cts; @@ -334,7 +351,9 @@ main (int argc, char **argv) { } } - seq_setcur (mp, mp->hghsel); /* update current message */ + if (chgflag) { + seq_setcur (mp, mp->hghsel); /* update current message */ + } seq_save (mp); /* synchronize sequences */ context_replace (pfolder, folder);/* update current folder */ context_save (); /* save the context file */ @@ -391,6 +410,7 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { } reverse_alternative_parts (*ctp); + status = fix_always (*ctp, &message_mods); if (status == OK && fx->fixboundary) { status = fix_boundary (ctp, &message_mods); } @@ -408,7 +428,7 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { status = convert_charsets (*ctp, fx->textcharset, &message_mods); } - if (! (*ctp)->c_umask) { + if (status == OK && ! (*ctp)->c_umask) { /* Set the umask for the contents file. This currently isn't used but just in case it is in the future. */ struct stat st; @@ -462,7 +482,7 @@ fix_boundary (CT *ct, int *message_mods) { struct multipart *mp; int status = OK; - if (bogus_mp_content) { + if (ct && (*ct)->c_type == CT_MULTIPART && bogus_mp_content) { mp = (struct multipart *) (*ct)->c_ctparams; /* @@ -497,6 +517,7 @@ fix_boundary (CT *ct, int *message_mods) { "fix multipart boundary"); } } else { + *ct = NULL; advise (NULL, "unable to parse fixed part"); status = NOTOK; } @@ -829,69 +850,72 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) { switch ((*ct)->c_type) { case CT_TEXT: { - int has_text_plain = 0; - /* Nothing to do for text/plain. */ if ((*ct)->c_subtype == TEXT_PLAIN) { return OK; } if (parent && parent->c_type == CT_MULTIPART && parent->c_subtype == MULTI_ALTERNATE) { - struct multipart *mp = (struct multipart *) parent->c_ctparams; - struct part *part, *prev; int new_subpart_number = 1; + int has_text_plain = + find_textplain_sibling (parent, replacetextplain, + &new_subpart_number); - /* See if there is a sibling text/plain. */ - for (prev = part = mp->mp_parts; part; part = part->mp_next) { - ++new_subpart_number; - if (part->mp_part->c_type == CT_TEXT && - part->mp_part->c_subtype == TEXT_PLAIN) { - if (replacetextplain) { - struct part *old_part; - if (part == mp->mp_parts) { - old_part = mp->mp_parts; - mp->mp_parts = part->mp_next; - } else { - old_part = prev->mp_next; - prev->mp_next = part->mp_next; - } - if (verbosw) { - report (NULL, parent->c_partno, parent->c_file, - "remove text/plain part %s", - old_part->mp_part->c_partno); - } - free_content (old_part->mp_part); - free (old_part); - } else { - has_text_plain = 1; + if (! has_text_plain) { + /* Parent is a multipart/alternative. Insert a new + text/plain subpart. */ + const int inserted = + insert_new_text_plain_part (*ct, new_subpart_number, + parent); + if (inserted) { + ++*message_mods; + if (verbosw) { + report (NULL, parent->c_partno, parent->c_file, + "insert text/plain part"); } - break; + } else { + status = NOTOK; } - prev = part; + } + } else if (parent && parent->c_type == CT_MULTIPART && + parent->c_subtype == MULTI_RELATED) { + char *type_subtype = + concat ((*ct)->c_ctinfo.ci_type, "/", + (*ct)->c_ctinfo.ci_subtype, NULL); + const char *parent_type = + get_param (parent->c_ctinfo.ci_first_pm, "type", '?', 1); + int new_subpart_number = 1; + int has_text_plain = 0; + + /* Have to do string comparison on the subtype because we + don't enumerate all of them in c_subtype values. + parent_type will be NULL if the multipart/related part + doesn't have a type parameter. The type parameter must + be specified according to RFC 2387 Sec. 3.1 but not all + messages comply. */ + if (parent_type && strcasecmp (type_subtype, parent_type) == 0) { + /* The type of this part matches the root type of the + parent multipart/related. Look to see if there's + text/plain sibling. */ + has_text_plain = + find_textplain_sibling (parent, replacetextplain, + &new_subpart_number); } + free (type_subtype); + if (! has_text_plain) { /* Parent is a multipart/alternative. Insert a new text/plain subpart. */ - struct part *new_part = mh_xmalloc (sizeof *new_part); - - if ((new_part->mp_part = build_text_plain_part (*ct))) { - char buffer[16]; - snprintf (buffer, sizeof buffer, "%d", new_subpart_number); - - new_part->mp_next = mp->mp_parts; - mp->mp_parts = new_part; - new_part->mp_part->c_partno = - concat (parent->c_partno ? parent->c_partno : "1", ".", - buffer, NULL); - + const int inserted = + insert_new_text_plain_part (*ct, new_subpart_number, + parent); + if (inserted) { ++*message_mods; if (verbosw) { report (NULL, parent->c_partno, parent->c_file, "insert text/plain part"); } } else { - free_content (new_part->mp_part); - free (new_part); status = NOTOK; } } @@ -946,9 +970,8 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) { case CT_MESSAGE: if ((*ct)->c_subtype == MESSAGE_EXTERNAL) { - struct exbody *e; + struct exbody *e = (struct exbody *) (*ct)->c_ctparams; - e = (struct exbody *) (*ct)->c_ctparams; status = ensure_text_plain (&e->eb_content, *ct, message_mods, replacetextplain); } @@ -959,6 +982,71 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) { } +/* See if there is a sibling text/plain. */ +static int +find_textplain_sibling (CT parent, int replacetextplain, + int *new_subpart_number) { + struct multipart *mp = (struct multipart *) parent->c_ctparams; + struct part *part, *prev; + int has_text_plain = 0; + + for (prev = part = mp->mp_parts; part; part = part->mp_next) { + ++*new_subpart_number; + if (part->mp_part->c_type == CT_TEXT && + part->mp_part->c_subtype == TEXT_PLAIN) { + if (replacetextplain) { + struct part *old_part; + if (part == mp->mp_parts) { + old_part = mp->mp_parts; + mp->mp_parts = part->mp_next; + } else { + old_part = prev->mp_next; + prev->mp_next = part->mp_next; + } + if (verbosw) { + report (NULL, parent->c_partno, parent->c_file, + "remove text/plain part %s", + old_part->mp_part->c_partno); + } + free_content (old_part->mp_part); + free (old_part); + } else { + has_text_plain = 1; + } + break; + } + prev = part; + } + + return has_text_plain; +} + + +static int +insert_new_text_plain_part (CT ct, int new_subpart_number, CT parent) { + struct multipart *mp = (struct multipart *) parent->c_ctparams; + struct part *new_part = mh_xmalloc (sizeof *new_part); + + if ((new_part->mp_part = build_text_plain_part (ct))) { + char buffer[16]; + snprintf (buffer, sizeof buffer, "%d", new_subpart_number); + + new_part->mp_next = mp->mp_parts; + mp->mp_parts = new_part; + new_part->mp_part->c_partno = + concat (parent->c_partno ? parent->c_partno : "1", ".", + buffer, NULL); + + return 1; + } else { + free_content (new_part->mp_part); + free (new_part); + + return 0; + } +} + + static CT build_text_plain_part (CT encoded_part) { CT tp_part = divide_part (encoded_part); @@ -985,7 +1073,7 @@ build_text_plain_part (CT encoded_part) { } free_content (tp_part); - (void) m_unlink (tmp_plain_file); + if (tmp_plain_file) { (void) m_unlink (tmp_plain_file); } free (tmp_plain_file); return NULL; @@ -996,7 +1084,7 @@ static CT divide_part (CT ct) { CT new_part; - if ((new_part = (CT) calloc (1, sizeof *new_part)) == NULL) + if ((new_part = (CT) mh_xcalloc (1, sizeof *new_part)) == NULL) adios (NULL, "out of memory"); /* Just copy over what is needed for decoding. c_vrsn and @@ -1130,8 +1218,10 @@ reformat_part (CT ct, char *file, char *type, char *subtype, int c_type) { /* Identifies 7bit or 8bit content based on charset. */ static int charset_encoding (CT ct) { - int encoding = - strcasecmp (content_charset (ct), "US-ASCII") ? CE_8BIT : CE_7BIT; + char *ct_charset = content_charset (ct); + int encoding = strcasecmp (ct_charset, "US-ASCII") ? CE_8BIT : CE_7BIT; + + free (ct_charset); return encoding; } @@ -1148,11 +1238,11 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { struct multipart *m; const struct str2init *ctinit; - if ((ct = (CT) calloc (1, sizeof *ct)) == NULL) + if ((ct = (CT) mh_xcalloc (1, sizeof *ct)) == NULL) adios (NULL, "out of memory"); /* Set up the multipart/alternative part. These fields of *ct were - initialized to 0 by calloc(): + initialized to 0 by mh_xcalloc(): c_fp, c_unlink, c_begin, c_end, c_vrsn, c_ctline, c_celine, c_id, c_descr, c_dispo, c_partno, @@ -1249,20 +1339,20 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { } add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm, - "boundary", boundary, 0); + "boundary", boundary, 0); p = (struct part *) mh_xmalloc (sizeof *p); p->mp_next = (struct part *) mh_xmalloc (sizeof *p->mp_next); p->mp_next->mp_next = NULL; p->mp_next->mp_part = first_alt; - if ((m = (struct multipart *) calloc (1, sizeof (struct multipart))) == + if ((m = (struct multipart *) mh_xcalloc (1, sizeof (struct multipart))) == NULL) adios (NULL, "out of memory"); m->mp_start = concat (boundary, "\n", NULL); m->mp_stop = concat (boundary, "--\n", NULL); m->mp_parts = p; - ct->c_ctparams = (void *) m; + ct->c_ctparams = m; free (boundary); @@ -1482,9 +1572,8 @@ decode_text_parts (CT ct, int encoding, int *message_mods) { case CT_MESSAGE: if (ct->c_subtype == MESSAGE_EXTERNAL) { - struct exbody *e; + struct exbody *e = (struct exbody *) ct->c_ctparams; - e = (struct exbody *) ct->c_ctparams; status = decode_text_parts (e->eb_content, encoding, message_mods); } break; @@ -1701,6 +1790,8 @@ strip_crs (CT ct, int *message_mods) { } } + free (charset); + return status; } @@ -1715,14 +1806,18 @@ convert_charsets (CT ct, char *dest_charset, int *message_mods) { status = convert_charset (ct, dest_charset, message_mods); if (status == OK) { if (verbosw) { + char *ct_charset = content_charset (ct); + report (NULL, ct->c_partno, ct->c_file, - "convert %s to %s", - content_charset(ct), dest_charset); + "convert %s to %s", ct_charset, dest_charset); + free (ct_charset); } } else { + char *ct_charset = content_charset (ct); + report ("iconv", ct->c_partno, ct->c_file, - "failed to convert %s to %s", - content_charset(ct), dest_charset); + "failed to convert %s to %s", ct_charset, dest_charset); + free (ct_charset); } } break; @@ -1742,9 +1837,8 @@ convert_charsets (CT ct, char *dest_charset, int *message_mods) { case CT_MESSAGE: if (ct->c_subtype == MESSAGE_EXTERNAL) { - struct exbody *e; + struct exbody *e = (struct exbody *) ct->c_ctparams; - e = (struct exbody *) ct->c_ctparams; status = convert_charsets (e->eb_content, dest_charset, message_mods); } @@ -1758,6 +1852,73 @@ convert_charsets (CT ct, char *dest_charset, int *message_mods) { } +/* + * Fix various problems that aren't handled elsewhere. These + * are fixed unconditionally: there are no switches to disable + * them. (Currently, "problems" is just one: an extraneous + * semicolon at the end of a header parameter list.) + */ +static int +fix_always (CT ct, 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_always (part->mp_part, message_mods); + } + break; + } + + case CT_MESSAGE: + if (ct->c_subtype == MESSAGE_EXTERNAL) { + struct exbody *e = (struct exbody *) ct->c_ctparams; + + status = fix_always (e->eb_content, message_mods); + } + break; + + default: { + HF hf; + + for (hf = ct->c_first_hf; hf; hf = hf->next) { + size_t len = strlen (hf->value); + + /* whitespace following a trailing ';' will be nuked as well */ + if (hf->value[len - 1] == '\n') + while (isspace((unsigned char)(hf->value[len - 2]))) len--; + + if (hf->value[len - 2] == ';') { + /* Remove trailing ';' from parameter value. */ + hf->value[len - 2] = '\n'; + hf->value[len - 1] = '\0'; + + /* Also, if Content-Type parameter, remove trailing ';' + from ct->c_ctline. This probably isn't necessary + but can't hurt. */ + if (strcasecmp(hf->name, "Content-Type") == 0 && ct->c_ctline) { + size_t l = strlen(ct->c_ctline) - 1; + while (isspace((unsigned char)(ct->c_ctline[l])) || ct->c_ctline[l] == ';') + ct->c_ctline[l--] = '\0'; + } + + ++*message_mods; + if (verbosw) { + report (NULL, ct->c_partno, ct->c_file, + "remove trailing ; from %s parameter value", + hf->name); + } + } + } + }} + + return status; +} + + static int write_content (CT ct, char *input_filename, char *outfile, int modify_inplace, int message_mods) { diff --git a/uip/mhfree.c b/uip/mhfree.c index f2726d0f..89829be2 100644 --- a/uip/mhfree.c +++ b/uip/mhfree.c @@ -307,9 +307,10 @@ freects_done (int status) { CT *ctp; - if ((ctp = cts)) - for (; *ctp; ctp++) - free_content (*ctp); + for (ctp = cts; ctp && *ctp; ctp++) + free_content (*ctp); + + free (cts); exit (status); } diff --git a/uip/mhlist.c b/uip/mhlist.c index f09c1475..91b09841 100644 --- a/uip/mhlist.c +++ b/uip/mhlist.c @@ -248,7 +248,7 @@ do_cache: * check if message is coming from file */ if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) 2, sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; @@ -281,7 +281,7 @@ do_cache: done (1); seq_setprev (mp); /* set the previous-sequence */ - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; diff --git a/uip/mhlsbr.c b/uip/mhlsbr.c index 8d8fea17..28d48947 100644 --- a/uip/mhlsbr.c +++ b/uip/mhlsbr.c @@ -778,7 +778,7 @@ evalvar (struct mcomp *c1) return 1; } - args = (struct arglist *) calloc((size_t) 1, sizeof(struct arglist)); + args = (struct arglist *) mh_xcalloc ((size_t) 1, sizeof(struct arglist)); if (arglist_tail) arglist_tail->a_next = args; @@ -1184,7 +1184,7 @@ mcomp_format (struct mcomp *c1, struct mcomp *c2) (q = &pq)->pq_next = NULL; while ((cp = getname (ap))) { - if ((p = (struct pqpair *) calloc ((size_t) 1, sizeof(*p))) == NULL) + if ((p = (struct pqpair *) mh_xcalloc ((size_t) 1, sizeof(*p))) == NULL) adios (NULL, "unable to allocate pqpair memory"); else { if ((mp = getm (cp, NULL, 0, error, sizeof(error))) == NULL) { @@ -1240,7 +1240,7 @@ add_queue (struct mcomp **head, struct mcomp **tail, char *name, char *text, int { struct mcomp *c1; - if ((c1 = (struct mcomp *) calloc ((size_t) 1, sizeof(*c1))) == NULL) + if ((c1 = (struct mcomp *) mh_xcalloc ((size_t) 1, sizeof(*c1))) == NULL) adios (NULL, "unable to allocate comp memory"); else { c1->c_flags = flags & ~INIT; diff --git a/uip/mhn.c b/uip/mhn.c index 7363688f..39d86933 100644 --- a/uip/mhn.c +++ b/uip/mhn.c @@ -119,12 +119,6 @@ int part_ok (CT, int); int type_ok (CT, int); void flush_errors (void); -/* mhstoresbr.c */ -typedef struct mhstoreinfo *mhstoreinfo_t; -mhstoreinfo_t mhstoreinfo_create(CT *, char *, const char *, int, int); -void mhstoreinfo_free(mhstoreinfo_t); -void store_all_messages (mhstoreinfo_t); - /* mhcachesbr.c */ void cache_all_messages (CT *); @@ -446,7 +440,7 @@ do_cache: * check if message is coming from file */ if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) 2, sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; @@ -479,7 +473,7 @@ do_cache: done (1); seq_setprev (mp); /* set the previous-sequence */ - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; diff --git a/uip/mhoutsbr.c b/uip/mhoutsbr.c index ca1acf83..0c0a2975 100644 --- a/uip/mhoutsbr.c +++ b/uip/mhoutsbr.c @@ -407,6 +407,7 @@ three_print: putc ('\n', out); (*ct->c_ceclosefnx) (ct); + free (bufp); return OK; } diff --git a/uip/mhparse.c b/uip/mhparse.c index 548a9509..96af58e9 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -34,10 +34,14 @@ int checksw = 0; /* check Content-MD5 field */ * 1) Instruct parser not to detect invalid Content-Transfer-Encoding * in a multipart. * 2) Suppress the warning about bogus multipart content, and report it. + * 3) Suppress the warning about extraneous trailing ';' in header parameter + * lists, and report it. */ int skip_mp_cte_check; int suppress_bogus_mp_content_warning; int bogus_mp_content; +int suppress_extraneous_trailing_semicolon_warning; +int extraneous_trailing_semicolon; /* * Structures for TEXT messages @@ -59,6 +63,7 @@ struct k2v SubMultiPart[] = { { "alternative", MULTI_ALTERNATE }, { "digest", MULTI_DIGEST }, { "parallel", MULTI_PARALLEL }, + { "related", MULTI_RELATED }, { NULL, MULTI_UNKNOWN } /* this one must be last! */ }; @@ -283,7 +288,7 @@ get_content (FILE *in, char *file, int toplevel) m_getfld_state_t gstate = 0; /* allocate the content structure */ - if (!(ct = (CT) calloc (1, sizeof(*ct)))) + if (!(ct = (CT) mh_xcalloc (1, sizeof(*ct)))) adios (NULL, "out of memory"); ct->c_fp = in; @@ -1018,7 +1023,7 @@ InitText (CT ct) ct->c_subtype = kv->kv_value; /* allocate text character set structure */ - if ((t = (struct text *) calloc (1, sizeof(*t))) == NULL) + if ((t = (struct text *) mh_xcalloc (1, sizeof(*t))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) t; @@ -1126,7 +1131,7 @@ InitMultiPart (CT ct) } /* allocate primary structure for multipart info */ - if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL) + if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) m; @@ -1171,7 +1176,7 @@ InitMultiPart (CT ct) if (strcmp (bufp + 2, m->mp_start)) continue; next_part: - if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) adios (NULL, "out of memory"); *next = part; next = &part->mp_next; @@ -1179,7 +1184,6 @@ next_part: if (!(p = get_content (fp, ct->c_file, ct->c_subtype == MULTI_DIGEST ? -1 : 0))) { free(bufp); - fclose (ct->c_fp); ct->c_fp = NULL; return NOTOK; } @@ -1354,7 +1358,7 @@ InitMessage (CT ct) PM pm; struct partial *p; - if ((p = (struct partial *) calloc (1, sizeof(*p))) == NULL) + if ((p = (struct partial *) mh_xcalloc (1, sizeof(*p))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) p; @@ -1403,7 +1407,7 @@ invalid_param: CT p; FILE *fp; - if ((e = (struct exbody *) calloc (1, sizeof(*e))) == NULL) + if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL) adios (NULL, "out of memory"); ct->c_ctparams = (void *) e; @@ -2127,6 +2131,7 @@ ready_to_go: fclose (ct->c_fp); ct->c_fp = NULL; } + free (bufp); return fileno (ce->ce_fp); clean_up: @@ -2135,6 +2140,7 @@ clean_up: fclose (ct->c_fp); ct->c_fp = NULL; } + free (bufp); return NOTOK; } @@ -3148,6 +3154,8 @@ ct_subtype_str (int type, int subtype) { return "digest"; case MULTI_PARALLEL: return "parallel"; + case MULTI_RELATED: + return "related"; default: return "unknown_multipart_subtype"; } @@ -3272,10 +3280,13 @@ parse_header_attrs (const char *filename, const char *fieldname, } if (*cp == 0) { - advise (NULL, - "extraneous trailing ';' in message %s's %s: " - "parameter list", - filename, fieldname); + if (! suppress_extraneous_trailing_semicolon_warning) { + advise (NULL, + "extraneous trailing ';' in message %s's %s: " + "parameter list", + filename, fieldname); + } + extraneous_trailing_semicolon = 1; return DONE; } @@ -3550,6 +3561,7 @@ bad_quote: "%s's %s: field\n%*s(parameter %s)", sp->index, filename, fieldname, strlen(invo_name) + 2, "", nameptr); + free (nameptr); return NOTOK; } if (sp2->index < sp->index && @@ -3565,6 +3577,7 @@ bad_quote: "param in message %s's %s: field\n%*s(parameter %s)", filename, fieldname, strlen(invo_name) + 2, "", nameptr); + free (nameptr); return NOTOK; } } @@ -3640,21 +3653,16 @@ bad_quote: } /* - * Return the charset for a particular content type. Return pointer is - * only valid until the next call to content_charset(). + * Return the charset for a particular content type. */ char * content_charset (CT ct) { - static char *ret_charset = NULL; - - if (ret_charset != NULL) { - free(ret_charset); - } + char *ret_charset = NULL; ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0); - return ret_charset ? ret_charset : "US-ASCII"; + return ret_charset ? ret_charset : getcpy ("US-ASCII"); } diff --git a/uip/mhshow.c b/uip/mhshow.c index 98cab9d1..0227d0c2 100644 --- a/uip/mhshow.c +++ b/uip/mhshow.c @@ -314,7 +314,7 @@ do_cache: * check if message is coming from file */ if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) 2, sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; @@ -358,7 +358,7 @@ do_cache: seq_setprev (mp); /* set the Previous-Sequence */ seq_setunseen (mp, 1); /* unset the Unseen-Sequence */ - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index 6236352c..986ffb91 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -354,10 +354,12 @@ show_content_aux (CT ct, int alternate, char *cp, char *cracked, struct format * if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) return NOTOK; } else { + char *charset = content_charset (ct); admonish (NULL, "unable to convert character set%s%s to %s", ct->c_partno ? " of part " : "", ct->c_partno ? ct->c_partno : "", - content_charset (ct)); + charset); + free (charset); } } @@ -567,7 +569,7 @@ show_multi_internal (CT ct, int alternate, int concatsw, int textonly, int alternating, nowalternate, result; struct multipart *m = (struct multipart *) ct->c_ctparams; struct part *part; - int any_part_ok; + int request_matched; CT p; alternating = 0; @@ -578,13 +580,13 @@ show_multi_internal (CT ct, int alternate, int concatsw, int textonly, alternating = 1; } -/* - * alternate -> we are a part inside an multipart/alternative - * alternating -> we are a multipart/alternative - */ + /* + * alternate -> we are a part inside an multipart/alternative + * alternating -> we are a multipart/alternative + */ result = alternate ? NOTOK : OK; - any_part_ok = 0; + request_matched = 0; for (part = m->mp_parts; part; part = part->mp_next) { p = part->mp_part; @@ -592,7 +594,7 @@ show_multi_internal (CT ct, int alternate, int concatsw, int textonly, if (part_ok (p, 1) && type_ok (p, 1)) { int inneresult; - any_part_ok = 1; + request_matched = 1; inneresult = show_switch (p, nowalternate, concatsw, textonly, inlineonly, fmt); @@ -621,7 +623,7 @@ show_multi_internal (CT ct, int alternate, int concatsw, int textonly, } } - if (alternating && !part && any_part_ok) { + if (alternating && !part && request_matched) { if (!alternate) content_error (NULL, ct, "don't know how to display any of the contents"); result = NOTOK; @@ -629,7 +631,9 @@ show_multi_internal (CT ct, int alternate, int concatsw, int textonly, } out: - return result; + /* if no parts matched what was requested, there can't have been + * any display errors, so we report OK. */ + return request_matched ? result : OK; } @@ -1037,6 +1041,7 @@ convert_charset (CT ct, char *dest_charset, int *message_mods) { if ((conv_desc = iconv_open (dest_charset, src_charset)) == (iconv_t) -1) { advise (NULL, "Can't convert %s to %s", src_charset, dest_charset); + free (src_charset); return NOTOK; } @@ -1177,6 +1182,7 @@ iconv_start: #endif /* ! HAVE_ICONV */ } + free (src_charset); return status; } @@ -1201,9 +1207,8 @@ convert_content_charset (CT ct, char **file) { } else { status = NOTOK; } - - free (charset); } + free (charset); #else /* ! HAVE_ICONV */ NMH_UNUSED (ct); NMH_UNUSED (file); diff --git a/uip/mhstore.c b/uip/mhstore.c index 72079a81..17dcc01d 100644 --- a/uip/mhstore.c +++ b/uip/mhstore.c @@ -51,12 +51,6 @@ extern int wcachesw; extern char *cache_public; extern char *cache_private; -/* mhstoresbr.c */ -typedef struct mhstoreinfo *mhstoreinfo_t; -mhstoreinfo_t mhstoreinfo_create(CT *, char *, const char *, int, int); -int mhstoreinfo_files_not_clobbered(const mhstoreinfo_t); -void mhstoreinfo_free(mhstoreinfo_t); - /* mhmisc.c */ extern int npart; extern int ntype; @@ -75,9 +69,6 @@ int part_ok (CT, int); int type_ok (CT, int); void flush_errors (void); -/* mhstoresbr.c */ -void store_all_messages (mhstoreinfo_t); - /* mhfree.c */ extern CT *cts; void freects_done (int) NORETURN; @@ -269,14 +260,14 @@ do_cache: * check if message is coming from file */ if (file) { - if (!(cts = (CT *) calloc ((size_t) 2, sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) 2, sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; if ((ct = parse_mime (file))) { *ctp++ = ct; if (outfile) { - ct->c_storage = outfile; + ct->c_storage = add (outfile, NULL); } } } else { @@ -306,7 +297,7 @@ do_cache: done (1); seq_setprev (mp); /* set the previous-sequence */ - if (!(cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) + if (!(cts = (CT *) mh_xcalloc ((size_t) (mp->numsel + 1), sizeof(*cts)))) adios (NULL, "out of memory"); ctp = cts; diff --git a/uip/mhstoresbr.c b/uip/mhstoresbr.c index 3ca4c7c6..ae835fbf 100644 --- a/uip/mhstoresbr.c +++ b/uip/mhstoresbr.c @@ -41,8 +41,6 @@ struct mhstoreinfo { enum clobber_policy_t clobber_policy; /* -clobber selection */ }; -typedef struct mhstoreinfo *mhstoreinfo_t; - mhstoreinfo_t mhstoreinfo_create (CT *ct, char *pwd, const char *csw, int asw, int vsw) { mhstoreinfo_t info = mh_xmalloc (sizeof *info); @@ -61,6 +59,7 @@ mhstoreinfo_create (CT *ct, char *pwd, const char *csw, int asw, int vsw) { void mhstoreinfo_free (mhstoreinfo_t info) { free (info->cwd); + free (info->dir); free (info); } @@ -82,11 +81,6 @@ int part_ok (CT, int); int type_ok (CT, int); void flush_errors (void); -/* - * prototypes - */ -void store_all_messages (mhstoreinfo_t); - /* * static prototypes */ @@ -298,10 +292,9 @@ store_multi (CT ct, mhstoreinfo_t info) /* Support mhstore -outfile. The MIME parser doesn't load c_storage, so we know that p->c_storage is NULL here. */ - p->c_storage = ct->c_storage; + p->c_storage = add (ct->c_storage, NULL); } result = store_switch (p, info); - p->c_storage = NULL; if (result == OK && ct->c_subtype == MULTI_ALTERNATE) break; @@ -352,7 +345,7 @@ store_partial (CT ct, mhstoreinfo_t info) return NOTOK; } - if ((base = (CT *) calloc ((size_t) (i + 1), sizeof(*base))) == NULL) + if ((base = (CT *) mh_xcalloc ((size_t) (i + 1), sizeof(*base))) == NULL) adios (NULL, "out of memory"); ctq = base; @@ -465,10 +458,9 @@ store_external (CT ct, mhstoreinfo_t info) if (ct->c_storage) { /* Support mhstore -outfile. The MIME parser doesn't load c_storage, so we know that p->c_storage is NULL here. */ - p->c_storage = ct->c_storage; + p->c_storage = add (ct->c_storage, NULL); } result = store_switch (p, info); - p->c_storage = NULL; p->c_partno = NULL; return result; @@ -625,7 +617,7 @@ store_content (CT ct, CT p, mhstoreinfo_t info) } } else { /* The output filename was explicitly specified, so use it. */ - if ((ct->c_storage = clobber_check (add (ct->c_storage, NULL), info)) == + if ((ct->c_storage = clobber_check (ct->c_storage, info)) == NULL) { return NOTOK; } @@ -1240,6 +1232,10 @@ clobber_check (char *original_file, mhstoreinfo_t info) { char *cwd = NULL; int check_again; + if (! strcmp (original_file, "-")) { + return original_file; + } + if (info->clobber_policy == NMH_CLOBBER_ASK) { /* Save cwd for possible use in loop below. */ char *slash; @@ -1250,7 +1246,9 @@ clobber_check (char *original_file, mhstoreinfo_t info) { if (slash) { *slash = '\0'; } else { - /* original_file wasn't a full path, which shouldn't happen. */ + /* original_file isn't a full path, which should only happen if + it is -. */ + free (cwd); cwd = NULL; } } @@ -1350,9 +1348,7 @@ clobber_check (char *original_file, mhstoreinfo_t info) { original_file = file; } while (check_again); - if (cwd) { - free (cwd); - } + free (cwd); return file; } diff --git a/uip/picksbr.c b/uip/picksbr.c index d444cd68..3c2107c2 100644 --- a/uip/picksbr.c +++ b/uip/picksbr.c @@ -459,7 +459,7 @@ newnexus (int (*action)()) { register struct nexus *p; - if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL) + if ((p = (struct nexus *) mh_xcalloc ((size_t) 1, sizeof *p)) == NULL) adios (NULL, "unable to allocate component storage"); p->n_action = action; diff --git a/uip/repl.c b/uip/repl.c index f8437288..a9f03b3e 100644 --- a/uip/repl.c +++ b/uip/repl.c @@ -17,7 +17,7 @@ X("annotate", 0, ANNOSW) \ X("noannotate", 0, NANNOSW) \ X("cc all|to|cc|me", 0, CCSW) \ - X("nocc type", 0, NCCSW) \ + X("nocc all|to|cc|me", 0, NCCSW) \ X("draftfolder +folder", 0, DFOLDSW) \ X("draftmessage msg", 0, DMSGSW) \ X("nodraftfolder", 0, NDFLDSW) \ diff --git a/uip/scansbr.c b/uip/scansbr.c index afc09011..7391a3bd 100644 --- a/uip/scansbr.c +++ b/uip/scansbr.c @@ -126,10 +126,10 @@ scan (FILE *inb, int innum, int outnum, char *nfs, int width, int curflg, * and it's our responsibility to free it. */ - nxtbuf = compbuffers = (char **) calloc((size_t) ncomps, sizeof(char *)); + nxtbuf = compbuffers = (char **) mh_xcalloc ((size_t) ncomps, sizeof(char *)); if (nxtbuf == NULL) adios (NULL, "unable to allocate component buffers"); - used_buf = (struct comp **) calloc((size_t) (ncomps+1), + used_buf = (struct comp **) mh_xcalloc ((size_t) (ncomps+1), sizeof(struct comp *)); if (used_buf == NULL) adios (NULL, "unable to allocate component buffer stack"); @@ -327,7 +327,7 @@ finished: if (! datecomp->c_text) { if (datecomp->c_tws == NULL) datecomp->c_tws = (struct tws *) - calloc((size_t) 1, sizeof(*datecomp->c_tws)); + mh_xcalloc ((size_t) 1, sizeof(*datecomp->c_tws)); if (datecomp->c_tws == NULL) adios (NULL, "unable to allocate tws buffer"); *datecomp->c_tws = *dlocaltime ((time_t *) &st.st_mtime); diff --git a/uip/sortm.c b/uip/sortm.c index 84a49394..0b8e1853 100644 --- a/uip/sortm.c +++ b/uip/sortm.c @@ -253,7 +253,7 @@ main (int argc, char **argv) * the collection of messages with the same subj * given a message number. */ - il = (struct smsg ***) calloc (mp->hghsel+1, sizeof(*il)); + il = (struct smsg ***) mh_xcalloc (mp->hghsel+1, sizeof(*il)); if (! il) adios (NULL, "couldn't allocate msg list"); for (i = 0; i < nmsgs; i++) @@ -318,7 +318,7 @@ read_hdrs (struct msgs *mp, char *datesw) twscopy (&tb, dlocaltimenow ()); smsgs = (struct smsg *) - calloc ((size_t) (mp->hghsel - mp->lowsel + 2), + mh_xcalloc ((size_t) (mp->hghsel - mp->lowsel + 2), sizeof(*smsgs)); if (smsgs == NULL) adios (NULL, "unable to allocate sort storage");