Hey,

Every now and then I would receive truncated emails. It wasn't until
later that I realised that missing parts of the emails were being
delivered as separate messages devoid of headers (mutt puts such
messages at the top of the list, so I hadn't noticed them). One mail I
received got split into 17 separate messages.

Lots of inspection and it's a bug in fdm's mbox parser. Here's a fix
that Nick and I devised.

I think this is important enough to go in for 5.9 (fdm is destructively
modifying messages read from mbox). Later I will make a patch to
5.8-stable.

OK?


Index: Makefile
===================================================================
RCS file: /home/edd/cvsync/ports/mail/fdm/Makefile,v
retrieving revision 1.20
diff -u -p -r1.20 Makefile
--- Makefile    3 Dec 2015 14:21:33 -0000       1.20
+++ Makefile    18 Feb 2016 15:29:03 -0000
@@ -3,6 +3,7 @@
 COMMENT=       fetch, filter and deliver mail
 
 V=             1.9
+REVISION =     0
 DISTNAME=      fdm-$V
 CATEGORIES=    mail
 
Index: patches/patch-fetch-mbox_c
===================================================================
RCS file: patches/patch-fetch-mbox_c
diff -N patches/patch-fetch-mbox_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-fetch-mbox_c  18 Feb 2016 15:32:36 -0000
@@ -0,0 +1,64 @@
+Fix a bug in mbox parser.
+
+Some tools only escape "From " lines in mboxs if they follow a blank line. fdm
+would split at lines beginning "From " unconditionally.
+
+From upstream 91df796046ee2c36bccc9cfda27860b5bb9dd36d
+
+$OpenBSD$
+--- fetch-mbox.c.orig  Fri Jun  5 19:30:34 2015
++++ fetch-mbox.c       Thu Feb 18 15:30:05 2016
+@@ -404,9 +404,9 @@ fetch_mbox_state_mail(struct account *a, struct fetch_
+       struct mail                     *m = fctx->mail;
+       struct fetch_mbox_mbox          *fmbox;
+       struct fetch_mbox_mail          *aux;
+-      char                            *line, *ptr, *lptr;
+-      size_t                           llen;
+-      int                              flushing;
++      char                            *line, *ptr, *last_line, *lptr;
++      size_t                           llen, n;
++      int                              flushing, from;
+ 
+       /* Find current mbox and check for EOF. */
+       fmbox = ARRAY_ITEM(&data->fmboxes, data->index);
+@@ -443,7 +443,7 @@ fetch_mbox_state_mail(struct account *a, struct fetch_
+        * trimmed later with minimal penalty).
+        */
+       flushing = 0;
+-      for (;;) {
++      for (last_line = NULL;; last_line = line) {
+               /* Check for EOF. */
+               if (data->off == fmbox->size) {
+                       aux->size = data->off - aux->off;
+@@ -459,10 +459,27 @@ fetch_mbox_state_mail(struct account *a, struct fetch_
+               } else
+                       data->off += ptr - line + 1;
+ 
+-              /* Check if the line is "From ". */
+-              if (line > fmbox->base &&
+-                  ptr - line >= 5 && strncmp(line, "From ", 5) == 0) {
+-                      /* End of mail. */
++              /*
++               * Check if we have reached the end of this message at the next
++               * message's "From " line. To allow "From " inside message
++               * bodes, they can be escaped by prepending with '>'. Some
++               * tools escape all "From " lines; others only escape if they
++               * immediately follow a blank line. We accept only "From" lines
++               * which follow a blank line (\n or \r\n).
++               */
++              from = 1;
++              if (line == fmbox->base || last_line == NULL)
++                      from = 0;
++              else {
++                      n = line - last_line;
++                      if (n != 1 && n != 2)
++                              from = 0;
++                      else if (n == 1 && *last_line != '\n')
++                              from = 0;
++                      else if (n == 2 && memcmp(last_line, "\r\n", 2) != 0)
++                              from = 0;
++              }
++              if (from && ptr - line >= 5 && memcmp(line, "From ", 5) == 0) {
+                       aux->size = (line - fmbox->base) - aux->off;
+                       break;
+               }


-- 
Best Regards
Edd Barrett

http://www.theunixzoo.co.uk

Reply via email to