[dev] [imp-patch] invalid date headers

Francois Marier francois at nit.ca
Tue Jul 27 17:36:23 PDT 2004


Here's the situation I am trying to improve:  someone sends you an
email with a broken mailer that either
  1- puts junk in the Date header (e.g. using a non-standard format
for the date and time)
  or
  2- doesn't put a Date line in the header at all

In both cases, the current code detects the invalid date and display
"Unknown Date" in the mailbox page.  This is very reasonable, however,
an even better solution would be to guess the date from the "Received
headers" like some email clients do.

Since the date is returned by the imap_fetch_overview function, I
wrote a wrapper function that will call this function and then fix the
date if necessary.

I wasn't sure exactly how to fit this in the current code so I chose
an approach that changes very little existing code.

Francois
-------------- next part --------------
diff -rpuN -X ../ignorelist ../build/imp/lib/Mailbox.php imp/lib/Mailbox.php
--- ../build/imp/lib/Mailbox.php	Mon Jun 28 11:30:57 2004
+++ imp/lib/Mailbox.php	Tue Jul 27 20:17:28 2004
@@ -8,6 +8,45 @@ define('IMP_MAILBOX_EXPUNGE', 5);
 define('IMP_MAILBOX_EMPTY', 6);
 define('IMP_MAILBOX_UPDATE', 7);
 
+function imap_fetch_overview2($imap_stream, $sequence)
+{
+    $overview = @imap_fetch_overview($imap_stream, $sequence, FT_UID);
+    while (list($key, $header) = each($overview)) {
+        # Fix invalid "Date:" headers
+        if (empty($header->date) || (strtotime($header->date) == -1)) {
+            $full_header = explode("\n",imap_fetchheader($imap_stream, $header->uid, FT_UID));
+            $in_received = false;
+            foreach ($full_header as $line) {
+                # Find out whether we are in a "Received:" field
+                if (substr($line, 0, 9) == 'Received:') {
+                    $in_received = true;
+                } else {
+                    $first_char = substr($line, 0, 1);
+                    if (($first_char != " ") && ($first_char != "\t")) {
+                        $in_received = false;
+                    }
+                }
+
+                # Extract date from the "Received:" field
+                if ($in_received) {
+                    if (($semicolon = strpos($line, ';')) != FALSE) {
+                        $candidate = substr($line, $semicolon + 1);
+                    } else {
+                        $candidate = $line;
+                    }
+
+                    $candidate = trim($candidate);
+                    if (!empty($candidate) && ($new_date = strtotime($candidate)) != -1) {
+                        $overview[$key]->date = $candidate;
+                        break; // choose the first "Received" date from the top
+                    }
+                }
+            }
+        }
+    }
+    return $overview;
+}
+
 /**
  * The IMP_Mailbox:: class contains all code related to handling mailbox
  * access.
@@ -266,7 +305,7 @@ class IMP_Mailbox {
         /* Retrieve information from each mailbox. */
         foreach ($mboxes as $mbox => $ids) {
             $imp_imap->changeMbox($mbox, OP_READONLY);
-            $imapOverview = @imap_fetch_overview($imp['stream'], implode(',', array_keys($ids)), FT_UID);
+            $imapOverview = imap_fetch_overview2($imp['stream'], implode(',', array_keys($ids)), FT_UID);
             foreach ($imapOverview as $header) {
                 $key = $ids[$header->uid];
                 $overview[$key] = array();
@@ -1017,7 +1056,7 @@ class IMP_Mailbox {
                     $this->_threadIndent[$val] = count($branches);
 
                     if ($this->_delhide) {
-                        $overview = @imap_fetch_overview($imp['stream'], $val, FT_UID);
+                        $overview = imap_fetch_overview2($imp['stream'], $val, FT_UID);
                         if (is_array($overview) &&
                             ($overview[0]->deleted == 0)) {
                             $sorted[] = $val;


More information about the dev mailing list