I have extended mutt to also recognise the "From " line format created
by kmail 2.x. That format includes time zone information (mutt so far
always reads it as UTC) so it's better (and easier...) to change mutt
than kmail.

This patch makes it possible to share mbox files between mutt and kmail.
kmail has to be configured to use the "mixedmaildir" resource.

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 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-16 19:17:26.731217663 +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,108 @@
   }
 
   /* 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 HH:MM:SS */
+    if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3)
+      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