diff --git a/Changelog b/Changelog index ebe5e735..25fb4c22 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,48 @@ Version Changes for Hypermail ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +============================ +HYPERMAIL VERSION 2.4.1: +============================ + +2022-11-04 Jose Kahan + * src/Makefile.in + Some C linkers require libraries to be declared after functions in that + library are called, and not before. This was notably with -lm and + -ltrio, where -lm had to be declared after -ltrio. + (closes # 84) + +2021-11-17 David Hughes + * docs/hmrc.html src/parse.c + Added support for strftime (3) formatting in the append_filename configuration + option to allow for archived messages to be split over multiple directories + (monthly or yearly for example) + +2021-06-04 Baptiste Daroussin + * src/uudecode.c src/parse.c + Fixes for memory issues detected by libasan + +2020-06-19 Jose Kahan + * src/domains.c + valid_root_domains() was validating a domain name against the + historical DNS domains such as .org, .com. DNS has evolved and allows a + bigger variety of domains than those this function verified. That part + of the function has been invalidated and will be either eventually + removed or evolve to a user-configurable option. + +2020-06-12 Jose Kahan + * configure.ac + configure didn't signal an error if yacc was not installed + + * src/string.c + parseurl(): URLs were not detected and converted when they were + preceeded by a : that was not attached to a valid URL like + foo: https://example.com or : https://example.com + +2020-02-23 @cacsar + * Makefile.in + make install wasn't working + ============================ HYPERMAIL VERSION 2.4.0: ============================ diff --git a/Makefile.in b/Makefile.in index caeb383a..c679d37d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -47,14 +47,14 @@ support: @cd archive; $(MAKE) all CC="$(CC)" CFLAGS="$(CFLAGS)" CPPFLAGS="$(CPPFLAGS)" install: - @cd src; $(MAKE) install CC="$(CC)" CFLAGS="$(CFLAGS) \ - "CPPFLAGS="$(CPPFLAGS)" \ + @cd src; $(MAKE) install CC="$(CC)" CFLAGS="$(CFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" \ cgidir="$(cgidir)" bindir="$(bindir)" LIBS="$(LIBS)" @cd docs; $(MAKE) install CC="$(CC)" CFLAGS="$(CFLAGS)" \ - "CPPFLAGS="$(CPPFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" \ $(MAKEFLAGS) mandir="$(mandir)" htmldir="$(htmldir)" @cd archive; $(MAKE) install CC="$(CC)" CFLAGS="$(CFLAGS)" \ - "CPPFLAGS="$(CPPFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" \ bindir="$(bindir)" uninstall: diff --git a/configure b/configure index a9feaaad..7858d04e 100755 --- a/configure +++ b/configure @@ -709,6 +709,7 @@ LN_S INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM +YACC_CHECK YFLAGS YACC CPP @@ -3444,6 +3445,46 @@ fi done test -n "$YACC" || YACC="yacc" +# Extract the first word of "$YACC", so it can be a program name with args. +set dummy $YACC; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_YACC_CHECK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC_CHECK"; then + ac_cv_prog_YACC_CHECK="$YACC_CHECK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC_CHECK="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC_CHECK=$ac_cv_prog_YACC_CHECK +if test -n "$YACC_CHECK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC_CHECK" >&5 +$as_echo "$YACC_CHECK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test x"$YACC_CHECK" != x"yes"; then : + as_fn_error $? "Please install either bison or yacc and run configure again" "$LINENO" 5 +fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: diff --git a/configure.ac b/configure.ac index 2a3b7fa9..79714bfd 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,8 @@ dnl =========================================================================== AC_PROG_CC AC_PROG_CPP AC_PROG_YACC +AC_CHECK_PROG(YACC_CHECK,$YACC,yes) +AS_IF([test x"$YACC_CHECK" != x"yes"], [AC_MSG_ERROR([Please install either bison or yacc and run configure again])]) AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET diff --git a/docs/hmrc.html b/docs/hmrc.html index 399be3ed..4953123b 100644 --- a/docs/hmrc.html +++ b/docs/hmrc.html @@ -1301,9 +1301,11 @@

System miscellaneous

append = 1
append_filename = [ string ]
-
Specifies the filename to be used by the append option. $DIR -may be used to specify a name relative to the directory specified -in the -d or dir option.
+
Specifies the filename to be used by the append option. $DIR may +be used to specify a name relative to the directory specified in the +-d or dir option. The string will be passed to strftime(3) to allow +splitting the mailbox into yearly or monthy files, such as +"%Y-%m.mbox".

append_filename = $DIR/INBOX
diff --git a/src/Makefile.in b/src/Makefile.in index 7f54bad0..2838fa4b 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -40,7 +40,7 @@ CPPFLAGS=@CPPFLAGS@ @INCLUDES@ YACC=@YACC@ NETLIBS=@LIBS@ LDFLAGS=@LDFLAGS@ -MISC_LIBS= -lm -lpcre -ltrio +MISC_LIBS= -lpcre -ltrio -lm OPT_LIBS=@EXTRA_LIBS@ INCS= domains.h hypermail.h lang.h proto.h \ diff --git a/src/domains.c b/src/domains.c index be4ed92d..324a1322 100644 --- a/src/domains.c +++ b/src/domains.c @@ -18,6 +18,13 @@ int valid_root_domain(char *eaddr) if (!*name_to_check) return (0); + /* DNS has evolved and we have now a variety of new domains, hard + to track and that are not covered by this function. While temporary + waiting to see if we evolve this function to be user configurable, + we're going to return 1 (valid) all the time. 19/06/2020 -JK */ + return (1); + + for (ccptr = domain_codes; ccptr->domain != NULL; ccptr++) { if (strcasecmp(name_to_check, ccptr->domain) == 0) return (1); diff --git a/src/file.c b/src/file.c index cdfa67fe..5aafc834 100644 --- a/src/file.c +++ b/src/file.c @@ -53,9 +53,6 @@ #endif #endif /* HAVE_LIBFNV */ -extern int snprintf(char *str, size_t size, const char *format, ...); - - /* ** Does a file exist? */ diff --git a/src/hypermail.h b/src/hypermail.h index 6a63c102..38d71ac9 100644 --- a/src/hypermail.h +++ b/src/hypermail.h @@ -135,7 +135,7 @@ #define NUMSTRLEN 10 #define MAXLINE 1024 #define MAXFILELEN 256 -#define NAMESTRLEN 80 +#define NAMESTRLEN 320 #define MAILSTRLEN 80 #define DATESTRLEN 80 #define MSGDSTRLEN 256 diff --git a/src/parse.c b/src/parse.c index 36da5dfb..aad1740e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -924,7 +924,7 @@ static char *mdecodeRFC2047(char *string, int length, char *charsetsave) char charset[129]; char encoding[33]; char dummy[129]; - char *ptr; + char *ptr, *endptr; char *old_output; #ifdef NOTUSED @@ -959,6 +959,7 @@ static char *mdecodeRFC2047(char *string, int length, char *charsetsave) if (!strcasecmp("q", encoding)) { /* quoted printable decoding */ + endptr = ptr + strlen(ptr); #ifdef HAVE_ICONV char *orig2,*output2,*output3; @@ -967,7 +968,7 @@ static char *mdecodeRFC2047(char *string, int length, char *charsetsave) memset(output2,0,strlen(string)+1); old_output=output; - for (; *ptr; ptr++) { + for (; ptr < endptr; ptr++) { switch (*ptr) { case '=': sscanf(ptr + 1, "%02X", &value); @@ -991,7 +992,7 @@ static char *mdecodeRFC2047(char *string, int length, char *charsetsave) memcpy(charsetsave,charset,charsetlen); charsetsave[charsetlen] = '\0'; #else - for (; *ptr; ptr++) { + for (; ptr < endptr; ptr++) { switch (*ptr) { case '=': sscanf(ptr + 1, "%02X", &value); @@ -1086,6 +1087,11 @@ static char *mdecodeRFC2047(char *string, int length, char *charsetsave) } else { free(storage); +#ifdef HAVE_ICONV + /* make sure there are only ascii chars in the string + ** for messages that don't respect rfc2047 */ + i18n_replace_non_ascii_chars(string); +#endif return string; } } @@ -1540,6 +1546,8 @@ int parsemail(char *mbox, /* file name */ int require_filter_len, require_filter_full_len; struct hmlist *tlist; char filename[MAXFILELEN]; + char directory[MAXFILELEN]; + char pathname[MAXFILELEN]; struct emailinfo *emp; char *att_dir = NULL; /* directory name to store attachments in */ char *meta_dir = NULL; /* directory name where we're storing the meta data @@ -1654,21 +1662,36 @@ int parsemail(char *mbox, /* file name */ if(set_append) { /* add to an mbox as we read */ - - if(set_append_filename && strncmp(set_append_filename, "$DIR/", 5)) { - if(strlen(set_append_filename) >= sizeof(filename)) - progerr("append_filename too long"); - strcpy(filename, set_append_filename); + *directory = 0; + *filename = 0; + *pathname = 0; + if (set_append_filename) { + time_t curtime; + const struct tm *local_curtime; + + time(&curtime); + local_curtime = localtime(&curtime); + + if(strncmp(set_append_filename, "$DIR/", 5) == 0) { + strncpy(directory, dir, MAXFILELEN - 1); + strftime(filename, MAXFILELEN - 1, set_append_filename+5, + local_curtime); + } else { + strftime(filename, MAXFILELEN - 1, set_append_filename, + local_curtime); + } + } else { + strncpy(directory, dir, MAXFILELEN - 1); + strncpy(filename, "mbox", MAXFILELEN - 1); } - else if(trio_snprintf(filename, sizeof(filename), "%s%s", dir, - set_append_filename ? set_append_filename + 5 - : "mbox") - == sizeof(filename)) { + + if(trio_snprintf(pathname, sizeof(pathname), "%s%s", directory, + filename) == sizeof(pathname)) { progerr("Can't build mbox filename"); } - if(!(fpo = fopen(filename, "a"))) { + if(!(fpo = fopen(pathname, "a"))) { trio_snprintf(errmsg, sizeof(errmsg), "%s \"%s\".", - lang[MSG_CANNOT_OPEN_MAIL_ARCHIVE], filename); + lang[MSG_CANNOT_OPEN_MAIL_ARCHIVE], pathname); progerr(errmsg); } } @@ -1809,6 +1832,7 @@ int parsemail(char *mbox, /* file name */ if (head->header && !head->demimed) { head->line = mdecodeRFC2047(head->line, strlen(head->line),charsetsave); + head->demimed = TRUE; } if (head->parsedheader || head->attached || @@ -2378,6 +2402,7 @@ int parsemail(char *mbox, /* file name */ #endif if (charset) { free(charset); + charset = NULL; } charsetsave[0] = '\0'; diff --git a/src/proto.h b/src/proto.h index 9fe9fc3e..affe20de 100644 --- a/src/proto.h +++ b/src/proto.h @@ -99,6 +99,7 @@ char *unobfuscate_email_address (char *); char *i18n_convstring(char *, char *, char *, size_t *); char *i18n_utf2numref(char *, int); unsigned char *i18n_numref2utf(char *); +int i18n_replace_non_ascii_chars(char *); char *PushByte(struct Push *, char); char *PushString(struct Push *, const char *); diff --git a/src/setup.c b/src/setup.c index 3735391f..008d4b91 100644 --- a/src/setup.c +++ b/src/setup.c @@ -412,7 +412,9 @@ struct Config cfg[] = { {"append_filename", &set_append_filename, NULL, CFG_STRING, "# Specifies the filename to be used by the append option.\n" "# $DIR may be used to specify a name relative to the directory\n" - "# specified in the -d or dir option.\n", FALSE}, + "# specified in the -d or dir option.\n" + "# The string will be passed to strftime(3) to allow splitting the\n" + "# mailbox into yearly or monthy files, such as \"%Y-%m.mbox\".\n" , FALSE}, {"nonsequential", &set_nonsequential, BFALSE, CFG_SWITCH, "# Set this to On to generate filenames that are not sequential, but\n" diff --git a/src/string.c b/src/string.c index 6d7003b4..78ca1336 100644 --- a/src/string.c +++ b/src/string.c @@ -452,6 +452,26 @@ unsigned char *i18n_numref2utf(char *string){ return headofutfstr; } +/* replaces all non 7-bit ascii chars in string by a ? +** returns the number of replaced chars +*/ +int i18n_replace_non_ascii_chars(char *string) +{ + char *ptr = string; + int count = 0; + + while (*ptr) { + if (!isascii(*ptr) || + (*ptr < 0x20 && *ptr != 0x0a && *ptr != 0x0d && *ptr != 0x09)) { + *ptr = '?'; + count++; + } + ptr++; + } + + return count; +} + #endif /* end of I18N hack */ @@ -1802,22 +1822,40 @@ char *parseurl(char *input, char *charset) if (!input || !*input) return NULL; - c = strstr(input, ":"); + /* + * All our protocol prefixes have this ":" substring in them. Most + * of the lines we process don't have any URL. Let's not spend any + * time looking for URLs in lines that we can prove cheaply don't + * have any; it will be a big win for average input if we follow + * this trivial heuristic. + */ - if (!c /* not found */ - || c == input /* first char in line */ - || *(c+1) == '\0' /* last char in line */ - || !isalpha(*(c-1)) /* not between alpha/graph */ - || !isgraph(*(c+1))) { - /* - * All our protocol prefixes have this ":" substring in them. Most - * of the lines we process don't have any URL. Let's not spend any - * time looking for URLs in lines that we can prove cheaply don't - * have any; it will be a big win for average input if we follow - * this trivial heuristic. - */ + first = FALSE; + + c = strstr(input, ":"); + if (c == input) { /* first char in line */ + c++; + c = strstr(c, ":"); + } + + /* !c === not found */ + while (c) { + if (*(c+1) == '\0') /* last char in line */ + break; + else if ( !isalpha(*(c-1)) /* not between alpha/graph */ + || !isgraph(*(c+1))) { + c++; + c = strstr(c, ":"); + } else { + first = TRUE; + break; + } + } + + if (!first) { return convchars(input, charset); } + INIT_PUSH(buff); /* diff --git a/src/uudecode.c b/src/uudecode.c index 4b4310d2..c0c978a0 100644 --- a/src/uudecode.c +++ b/src/uudecode.c @@ -75,7 +75,7 @@ int uudecode(FILE *input, /* get file data from (if needed) */ if (init) { /* search for header line */ /* AUDIT biege: BOF in buf! */ - sprintf(scanfstring, "begin %%o %%%us", sizeof(buf)); + sprintf(scanfstring, "begin %%o %%%us", sizeof(buf) - 1); while (2 != sscanf(iptr, scanfstring, &mode, buf)) { if (!fgets(buf, MAXPATHLEN, input)) { return 2;