Subject: Re: bin/3286: sendmail doesn't escape 'From'
To: None <netbsd-bugs@NetBSD.ORG>
From: Christoph Badura <bad@klicman.de>
List: netbsd-bugs
Date: 03/05/1997 21:31:57
Andrew Wheadon <andrew@wipux2.wifo.uni-mannheim.de> writes:
> > andrew@wipux2.wifo.uni-mannheim.DE (Andrew Wheadon) writes:
> > >Hmm, you're right, maybe mail.local should be changed to NOT expect
> > >a blank line beforehand and to only escape lines which could be
> > >valid From-lines otherwise ?

> > I still resent this.  It hasn't been shown that this is actually
> > necessary.  So far there have been only vague references to unnamed
> > mailers that might get it wrong.
> I don't resent it. I'm getting that problem for
> elm 2.4 pl25 and elm 2.4 pl3. I am only getting it for PURE elm.

So how do these From_ lines get into the folder in the first place?

> > The elm 2.4 PL22 I'm running on this machine doesn't have the bug you
> As soon as you put "filter" in your .forward file it 
> stops happening because filter escapes the From lines for you.
> Could it be that you are running filter ? What happens with
> your elm for a normal user with no special .forward file ?

No, filter wasn't the problem.  I copied a From_ line manually to to middle
of a message in a test folder.  I don't know yet why I couldn't reproduce
the problem on flatlin.  I can reproduce it on a different machine.

> > say your's has.  I suspect your version is either misconfigured or
> > a bug was introduced in a later version.  I guess, you'll need to
> > investigate locally.
> The only option I remember which has anything to do with it is
> "Honor Content-Length:" and I said "No".

Setting it to yes doesn't change the behavior if there isn't a Content-Length:
lines in the message that breaks.

Anyway, here's a patch to elm 2.4 PL25 that makes it ignore any valid
From_ line that isn't preceded by a blank line.

--- src/newmbox.c.orig	Mon Dec  4 16:50:56 1995
+++ src/newmbox.c	Wed Mar  5 20:05:17 1997
@@ -410,14 +410,14 @@
         int temp_handle;
 	struct header_rec *current_header = NULL;
 	char buffer[VERY_LONG_STRING], tbuffer[VERY_LONG_STRING], *c;
-	long fbytes = 0L, line_bytes = 0L, content_start = 0L,
+	long fbytes = 0L, line_bytes = 0L, last_line_bytes = 1L, content_start = 0L,
 	  content_remaining = -1L, lines_start = 0L;
 	register long line = 0;
 	register int count = 0, another_count,
 	  subj = 0, copyit = 0, in_header = FALSE;
 	int count_x, count_y = 17, err;
 	int in_to_list = FALSE, forwarding_mail = FALSE, first_line = TRUE,
-	  content_length_found = FALSE;
+	  content_length_found = FALSE, was_empty_line = TRUE;
 
 	static int first_read = 0;
 #ifdef MMDF
@@ -562,6 +562,10 @@
 	  if ((line_bytes = mail_gets(buffer, VERY_LONG_STRING, mailfile)) == 0)
 	    break;
 
+	  /** remember if last line was a blank line **/
+	  was_empty_line = last_line_bytes == 1L;
+	  last_line_bytes = line_bytes;
+	      	
 	  if (copyit)
 	    if (fwrite(buffer, 1, line_bytes, temp) != line_bytes) {
 		err = errno;
@@ -602,7 +606,7 @@
 	    }
 	    else
 	      first_line = FALSE;
-	      	
+	    
 #ifdef MMDF
 	    if (!forwarding_mail && strcmp(buffer, MSG_SEPARATOR) != 0 ) {
 #else
@@ -625,7 +629,7 @@
 	    if (strcmp(buffer, MSG_SEPARATOR) == 0) {
               newheader = !newheader;
 #else
-	    if (first_word(buffer,"From ")) {
+	    if (was_empty_line && first_word(buffer,"From ")) {
 #endif /* MMDF */
 	      /** allocate new header pointers, if needed... **/
 
--- utils/readmsg.c,0	Tue Aug  3 21:29:29 1993
+++ utils/readmsg.c	Wed Mar  5 21:13:30 1997
@@ -403,6 +403,7 @@
     long offset;
     int alloc_size;
     char buf[SLEN];
+    int line_bytes, last_line_bytes, was_empty_line;
 #ifdef MMDF
     int  newheader = 0;
 #endif /* MMDF */
@@ -411,14 +412,18 @@
     folder_size = 0;
     alloc_size = 0;
     folder_idx_list = NULL;
+    /* pretend there was an empty line before the first line of the mailbox */
+    last_line_bytes = 1;
 
     /* go through the folder a line at a time looking for messages */
     rewind(fp);
-    while (offset = ftell(fp), mail_gets(buf, sizeof(buf), fp) != 0) {
+    while (offset = ftell(fp), (line_bytes = mail_gets(buf, sizeof(buf), fp)) != 0) {
+	was_empty_line = last_line_bytes == 1;
+	last_line_bytes = line_bytes;
 #ifdef MMDF
 	if ((strcmp(buf, MSG_SEPARATOR) == 0) && (++newheader % 2) != 0)
 #else
-	if (first_word(buf, "From ") &&
+	if (was_empty_line && first_word(buf, "From ") &&
 	    real_from(buf, (struct header_rec *)NULL))
 #endif
 	{
@@ -447,6 +452,7 @@
     long offset, mssg_idx;
     char buf[SLEN];
     int look_for_pat;
+    int line_bytes, last_line_bytes, was_empty_line;
 #ifdef MMDF
     int  newheader = 0;
 #endif /* MMDF */
@@ -457,14 +463,18 @@
      * we get to the top of a message.
      */
     look_for_pat = FALSE;
+    /* pretend there was an empty line before the first line of the mailbox */
+    last_line_bytes = 1;
 
     rewind(fp);
-    while (offset = ftell(fp), mail_gets(buf, sizeof(buf), fp) != 0) {
+    while (offset = ftell(fp), (line_bytes = mail_gets(buf, sizeof(buf), fp)) != 0) {
 
+	was_empty_line = last_line_bytes == 1;
+	last_line_bytes = line_bytes;
 #ifdef MMDF
 	if ((strcmp(buf, MSG_SEPARATOR) == 0) && (++newheader % 2) != 0)
 #else
-	if (first_word(buf, "From ") &&
+	if (was_empty_line && first_word(buf, "From ") &&
 	    real_from(buf, (struct header_rec *)NULL))
 #endif
 	{
@@ -498,7 +508,7 @@
 int do_page_breaks;
 {
     char buf[SLEN];
-    int first_line, is_seperator, in_header, buf_len, newlines;
+    int first_line, is_seperator, in_header, buf_len, last_buf_len, newlines, was_empty_line;
     static int num_mssgs_listed = 0;
 
     in_header = TRUE;
@@ -521,14 +531,18 @@
 
     /* we will chop off newlines at the end of the message */
     newlines = 0;
+    /* pretend there was an empty line before the first line of the mailbox */
+    last_buf_len = 1;
 
     /* print the message a line at a time */
     while ((buf_len = mail_gets(buf, SLEN, fp)) != 0) {
+	was_empty_line = last_buf_len == 1;
+	last_buf_len = buf_len;
 
 #ifdef MMDF
 	is_seperator = (strcmp(buf, MSG_SEPARATOR) == 0);
 #else
-	is_seperator = first_word(buf, "From ") &&
+	is_seperator = was_empty_line && first_word(buf, "From ") &&
 		       real_from(buf, (struct header_rec *)NULL);
 #endif