Bug 117848 - Interpret old-fashioned time zone in email Date header
Summary: Interpret old-fashioned time zone in email Date header
Status: RESOLVED FIXED
Alias: None
Product: kmail
Classification: Applications
Component: general (show other bugs)
Version: 1.8.3
Platform: Ubuntu Linux
: NOR normal
Target Milestone: ---
Assignee: kdepim bugs
URL:
Keywords:
: 115829 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-12-07 11:16 UTC by Jaap Weel
Modified: 2009-08-30 18:25 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jaap Weel 2005-12-07 11:16:05 UTC
Version:           1.8.3 (using KDE KDE 3.4.3)
Installed from:    Ubuntu Packages
OS:                Linux

I regularly get email from someone with this type of header:

Date: Wed, 7 Dec 2005 10:21:09 CET

Kmail displays this time in the message index as 14:21. Both the sender and I are in the CET (+0100) time zone. It seems that kmail thinks that CET means -0300.

I understand that this is not standard according to RFC2822. Therefore, according to RFC2822, this should be interpreted as +0000. Alternatively, it might be reasonable, for compatibility with certain older MUAs that generate this header, to interpret the time zone as +0100 (Central European Time). I do not see any reason for -0300.

Note that this report is different from reports that merely complain about kmail interpreting weird time zones as +0000 .
Comment 1 Martin Koller 2006-01-06 13:12:51 UTC
SVN commit 494852 by mkoller:

BUG:117848
Improve parsing of non-standard date strings.
It now parses in addition date strings in the format 
 "WWW MMM dd HH:MM:SS [Z] YYYY"  zone is optional
 e.g.: Fri Oct 14 09:21:49 CEST 2005
 or:   Tue Mar 23 18:00:02 2004



 M  +3 -0      datetime.cpp  
 M  +103 -32   dw_date.cpp   [POSSIBLY UNSAFE: scanf]


--- branches/KDE/3.5/kdepim/mimelib/datetime.cpp #494851:494852
@@ -45,6 +45,7 @@
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
 
 extern "C" int ParseRfc822Date(const char *str, struct tm *tms, int *z);
+extern "C" int ParseDate(const char *str, struct tm *tms, int *z);
 static DwInt32 ymd_to_jdnl(int year, int mon, int day, int julian);
 static void jdnl_to_ymd(DwInt32 jdn, int *year, int *mon, int *day, int julian);
 static DwUint32 my_inv_gmtime(struct tm* ptms);
@@ -282,6 +283,8 @@
     struct tm tms;
     int zone;
     int err = ParseRfc822Date(str, &tms, &zone);
+    if ( err == -1 )  // try another format
+        err = ParseDate(str, &tms, &zone);
     if (!err) {
         mYear   = tms.tm_year + 1900;
         mMonth  = tms.tm_mon+1;
--- branches/KDE/3.5/kdepim/mimelib/dw_date.cpp #494851:494852
@@ -526,10 +526,6 @@
         if (str[pos+1] == 'T' || str[pos+1] == 't') {
             zone = 0;
         }
-        else {
-            /* Military time zone */
-            zone = 480;
-        }
         break;
     case 'G':
     case 'g':
@@ -537,10 +533,6 @@
             && (str[pos+2] == 'T' || str[pos+2] == 't')) {
             zone = 0;
         }
-        else {
-            /* Military time zone */
-            zone = -420;
-        }
         break;
     case 'E':
     case 'e':
@@ -552,10 +544,6 @@
             && (str[pos+2] == 'T' || str[pos+2] == 't')) {
             zone = -240;
         }
-        else {
-            /* Military time zone */
-            zone = -300;
-        }
         break;
     case 'C':
     case 'c':
@@ -567,10 +555,15 @@
             && (str[pos+2] == 'T' || str[pos+2] == 't')) {
             zone = -300;
         }
-        else {
-            /* Military time zone */
-            zone = -180;
+        else if ((str[pos+1] == 'E' || str[pos+1] == 'e')    // allow non-RFC822 "CET"
+            && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+            zone = 60;
         }
+        else if ((str[pos+1] == 'E' || str[pos+1] == 'e')    // allow non-RFC822 "CEST"
+            && (str[pos+2] == 'S' || str[pos+2] == 's')
+            && (str[pos+3] == 'T' || str[pos+3] == 't')) {
+            zone = 120;
+        }
         break;
     case 'M':
     case 'm':
@@ -582,10 +575,6 @@
             && (str[pos+2] == 'T' || str[pos+2] == 't')) {
             zone = -360;
         }
-        else {
-            /* Military time zone */
-            zone = -720;
-        }
         break;
     case 'P':
     case 'p':
@@ -597,10 +586,6 @@
             && (str[pos+2] == 'T' || str[pos+2] == 't')) {
             zone = -420;
         }
-        else {
-            /* Military time zone */
-            zone = 180;
-        }
         break;
     case 'Z':
         /* Military time zone */
@@ -653,7 +638,16 @@
     return isValid ? 0 : -1;
 }
 
+const char* wdays[] = {
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
 
+const char* months[] = {
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+
 #ifdef DW_TESTING_DATEPARSER
 
 #include <stdio.h>
@@ -664,15 +658,6 @@
     ""
 };
 
-const char* wdays[] = {
-    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-const char* months[] = {
-    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
 int main()
 {
     struct tm *ptms, tms1, tms2;
@@ -723,3 +708,89 @@
 }
 
 #endif
+
+// try to parse a date/time string given in a format not
+// correctly specified in RFC822 format
+// Here we detect the following format:
+// "WWW MMM dd HH:MM:SS [Z] YYYY"  zone is optional
+// e.g.: Fri Oct 14 09:21:49 CEST 2005
+// or:   Tue Mar 23 18:00:02 2004
+
+#include <string.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+int ParseDate(const char *str, struct tm *tms, int *z)
+{
+    if ( !str )
+      return -1;
+
+    size_t len = strlen(str);
+
+    if ( len < 24 )  // at least "WWW MMM dd HH:MM:SS YYYY"
+      return -1;
+
+    int day=1, month=0, year=1970, hour=0, minute=0, second=0, zone=0;
+    int i;
+
+    for (i = 0; i < 7; i++)
+      if ( strncmp(str, wdays[i], 3) == 0 )
+        break;
+
+    if ( i == 7 )
+      return -1;
+
+    for (i = 0; i < 12; i++)
+      if ( strncmp(str+4, months[i], 3) == 0 )
+        break;
+
+    if ( i == 12 )
+      return -1;
+
+    month = i;
+
+    if ( sscanf(str+8, "%d %d:%d:%d", &day, &hour, &minute, &second) != 4 )
+      return -1;
+
+    if ( isdigit(str[20]) ) {   // year without zone info, as in ctime()
+      if ( sscanf(str+20, "%d", &year) != 1 )
+        return -1;
+    }
+    else {
+      if ( sscanf(str+20, "%*s %d", &year) != 1 )
+        return -1;
+
+      if      ( strncmp(str+20, "EST" , 3) == 0 ) zone = -5 * 60;
+      else if ( strncmp(str+20, "EDT" , 3) == 0 ) zone = -4 * 60;
+      else if ( strncmp(str+20, "CST" , 3) == 0 ) zone = -6 * 60;
+      else if ( strncmp(str+20, "CDT" , 3) == 0 ) zone = -5 * 60;
+      else if ( strncmp(str+20, "MST" , 3) == 0 ) zone = -7 * 60;
+      else if ( strncmp(str+20, "MDT" , 3) == 0 ) zone = -6 * 60;
+      else if ( strncmp(str+20, "PST" , 3) == 0 ) zone = -8 * 60;
+      else if ( strncmp(str+20, "PDT" , 3) == 0 ) zone = -7 * 60;
+      else if ( strncmp(str+20, "CET" , 3) == 0 ) zone = 60;
+      else if ( strncmp(str+20, "CEST", 4) == 0 ) zone = 120;
+    }
+
+    if ( (day    < 1) || (day    > 31) ||
+         (hour   < 0) || (hour   > 23) ||
+         (minute < 0) || (minute > 59) ||
+         (second < 0) || (second > 59) ||
+         (year   < 1900) )
+      return -1;
+
+    if ( tms ) {
+      tms->tm_year = year - 1900;
+      tms->tm_mon  = month;
+      tms->tm_mday = day;
+      tms->tm_hour = hour;
+      tms->tm_min  = minute;
+      tms->tm_sec  = second;
+    }
+
+    if ( z ) *z = zone;
+
+    return 0;
+}
Comment 2 Martin Koller 2009-08-30 18:25:12 UTC
*** Bug 115829 has been marked as a duplicate of this bug. ***