It is safer to always accept HH:MM times as well as HH:MM:SS ones. This
patch replaces my earlier one and also applies to the snapshot source of
20130825 (with some lines offset because some code was inserted
elsewhere).

Volker

-- 
Volker Kuhlmann
http://volker.dnsalias.net/     Please do not CC list postings to me.
Allow "From " lines of the form

  From <return-path> <weekday>, <day> <month> <year> <time> <timezone>

as produced by kmail2 4.10.5 with mixedmaildir resources.

16, 21 Aug 2013  Volker Kuhlmann


--- mutt-1.5.21/from.c.orig	2008-03-20 09:07:06.000000000 +1300
+++ mutt-1.5.21/from.c	2013-08-22 00:01:15.929309325 +1200
@@ -43,11 +43,12 @@
   return (-1); /* error */
 }
 
+/* Compare 3 letters of day name, which must be followed by space or comma. */
 static int is_day_name (const char *s)
 {
   int i;
 
-  if ((strlen (s) < 3) || !*(s + 3) || !ISSPACE (*(s+3)))
+  if ((strlen (s) < 3) || !*(s + 3) || !(ISSPACE (*(s+3)) || ',' == *(s+3)) )
     return 0;
   for (i=0; i<7; i++)
     if (mutt_strncasecmp (s, Weekdays[i], 3) == 0)
@@ -59,6 +60,10 @@
  * A valid message separator looks like:
  *
  * From [ <return-path> ] <weekday> <month> <day> <time> [ <timezone> ] <year>
+ *
+ * kmail2 (4.10.5) writes this into mixedmaildir folder files:
+ * From [email protected] Thu, 15 Aug 2013 15:27:08 +1200
+ * From <return-path> <weekday>, <day> <month> <year> <time> <timezone>
  */
 
 int is_from (const char *s, char *path, size_t pathlen, time_t *tp)
@@ -78,6 +83,7 @@
 
   dprint (3, (debugfile, "\nis_from(): parsing: %s", s));
 
+  /* Return path + weekday */
   if (!is_day_name (s))
   {
     const char *p;
@@ -135,53 +141,113 @@
   }
 
   /* now we should be on the month. */
-  if ((tm.tm_mon = mutt_check_month (s)) < 0) return 0;
-
-  /* day */
-  s = next_word (s);
-  if (!*s) return 0;
-  if (sscanf (s, "%d", &tm.tm_mday) != 1) return 0;
-
-  /* time */
-  s = next_word (s);
-  if (!*s) return 0;
+  tm.tm_mon = mutt_check_month (s);
+  if (tm.tm_mon >= 0) {
+    /* Continue looking for mutt's accepted "From " line. */
+    
+    /* day */
+    s = next_word (s);
+    if (!*s) return 0;
+    if (sscanf (s, "%d", &tm.tm_mday) != 1) return 0;
 
-  /* Accept either HH:MM or HH:MM:SS */
-  if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 3);
-  else if (sscanf (s, "%d:%d", &tm.tm_hour, &tm.tm_min) == 2)
-    tm.tm_sec = 0;
-  else
-    return 0;
+    /* time */
+    s = next_word (s);
+    if (!*s) return 0;
 
-  s = next_word (s);
-  if (!*s) return 0;
+    /* Accept either HH:MM or HH:MM:SS */
+    if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 3)
+      ;
+    else if (sscanf (s, "%d:%d", &tm.tm_hour, &tm.tm_min) == 2)
+      tm.tm_sec = 0;
+    else
+      return 0;
 
-  /* timezone? */
-  if (isalpha ((unsigned char) *s) || *s == '+' || *s == '-')
-  {
     s = next_word (s);
     if (!*s) return 0;
 
-    /*
-     * some places have two timezone fields after the time, e.g.
-     *      From [email protected] Wed Aug  2 00:39:12 MET DST 1995
-     */
-    if (isalpha ((unsigned char) *s))
+    /* timezone? */
+    /* A zone name is permitted, but is ignored.
+       The time stamp is always interpreted as UTC. */
+    if (isalpha ((unsigned char) *s) || *s == '+' || *s == '-')
     {
       s = next_word (s);
       if (!*s) return 0;
+
+      /*
+       * some places have two timezone fields after the time, e.g.
+       *      From [email protected] Wed Aug  2 00:39:12 MET DST 1995
+       */
+      if (isalpha ((unsigned char) *s))
+      {
+	s = next_word (s);
+	if (!*s) return 0;
+      }
     }
-  }
 
-  /* year */
-  if (sscanf (s, "%d", &yr) != 1) return 0;
-  tm.tm_year = yr > 1900 ? yr - 1900 : (yr < 70 ? yr + 100 : yr);
-  
-  dprint (3,(debugfile, "is_from(): month=%d, day=%d, hr=%d, min=%d, sec=%d, yr=%d.\n",
-	     tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year));
+    /* year */
+    if (sscanf (s, "%d", &yr) != 1) return 0;
+    tm.tm_year = yr > 1900 ? yr - 1900 : (yr < 70 ? yr + 100 : yr);
+
+    tm.tm_isdst = -1;
+    if (tp) *tp = mutt_mktime (&tm, 0);
+
+    dprint (3,(debugfile, "is_from(): month=%d, day=%d, hr=%d, min=%d, sec=%d, yr=%d, time_t=%d.\n",
+	       tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year, *tp));
+  } else {
+    /* Look for kmail's "From " line. */
 
-  tm.tm_isdst = -1;
+    int zone;
+    dprint (3, (debugfile, "is_from(): kmail: '%s'\n", s));
+    
+    /* day */
+    if (sscanf (s, "%d", &tm.tm_mday) != 1) return 0;
+
+    /* month */
+    s = next_word (s);
+    if (!*s) return 0;
+    tm.tm_mon = mutt_check_month (s);
+    if (tm.tm_mon < 0) return 0;
+
+    s = next_word (s);
+    if (!*s) return 0;
+
+    /* year */
+    if (sscanf (s, "%d", &yr) != 1) return 0;
+    tm.tm_year = yr > 1900 ? yr - 1900 : (yr < 70 ? yr + 100 : yr);
+
+    /* time */
+    s = next_word (s);
+    if (!*s) return 0;
 
-  if (tp) *tp = mutt_mktime (&tm, 0);
+    /* Accept either HH:MM or HH:MM:SS */
+    if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 3)
+      ;
+    else if (sscanf (s, "%d:%d", &tm.tm_hour, &tm.tm_min) == 2)
+      tm.tm_sec = 0;
+    else
+      return 0;
+
+    s = next_word (s);
+    if (!*s) return 0;
+
+    /* timezone */
+    if (sscanf (s, "%d", &zone) != 1) return 0;
+    
+    tm.tm_isdst = -1;
+    
+    /* mutt assumes the "From " line time to be in UTC; it is in local time, but
+       there is no time zone info available. However, kmail has zone info, so:
+       Convert for UTC, then adjust by zone offset. Result is in UTC, accurately
+       reflecting the zone offset indicated in the time stamp.
+       The offset is in [+-]HHMM. */
+    if (tp) {
+      *tp = mutt_mktime (&tm, 0);
+      *tp -= 60 * (zone % 60) + 3600 * zone / 100;
+    }
+
+    dprint (3,(debugfile, "is_from(): month=%d, day=%d, hr=%d, min=%d, sec=%d, yr=%d, zone=%d, time_t=%d.\n",
+      tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year, zone, *tp));
+  }
+  
   return 1;
 }

Reply via email to