Correct references trimming: array_walk can't in all PHP versions use
[squirrelmail.git] / class / deliver / Deliver.class.php
index 9cf091aaa832f162d9275760679f1333717da648..824086aae96b47ec63e641cd1eef2d55474b1cb9 100644 (file)
@@ -1,15 +1,15 @@
 <?php
+
 /**
  * Deliver.class.php
  *
- * Copyright (c) 1999-2005 The SquirrelMail Project Team
- * Licensed under the GNU GPL. For full terms see the file COPYING.
- *
  * This contains all the functions needed to send messages through
  * a delivery backend.
  *
+ * @author Marc Groot Koerkamp
+ * @copyright &copy; 1999-2006 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  * @version $Id$
- * @author  Marc Groot Koerkamp
  * @package squirrelmail
  */
 
@@ -179,7 +179,12 @@ class Deliver {
                 $filename = $message->att_local_name;
                 $file = fopen ($filename, 'rb');
                 while ($tmp = fread($file, 570)) {
-                   $body_part = chunk_split(base64_encode($tmp));
+                    $body_part = chunk_split(base64_encode($tmp));
+                    // Up to 4.3.10 chunk_split always appends a newline,
+                    // while in 4.3.11 it doesn't if the string to split
+                    // is shorter than the chunk length.
+                    if( substr($body_part, -1 , 1 ) != "\n" )
+                        $body_part .= "\n";
                     $length += $this->clean_crlf($body_part);
                     if ($stream) {
                         $this->writeToStream($stream, $body_part);
@@ -373,7 +378,8 @@ class Deliver {
      * @return string $header
      */
     function prepareRFC822_Header($rfc822_header, $reply_rfc822_header, &$raw_length) {
-        global $domain, $version, $username, $encode_header_key, $edit_identity, $hide_auth_header;
+        global $domain, $version, $username, $encode_header_key, 
+               $edit_identity, $hide_auth_header;
 
         /* if server var SERVER_NAME not available, use $domain */
         if(!sqGetGlobalVar('SERVER_NAME', $SERVER_NAME, SQ_SERVER)) {
@@ -421,26 +427,38 @@ class Deliver {
          * unless you understand all possible forging issues or your
          * webmail installation does not prevent changes in user's email address.
          * See SquirrelMail bug tracker #847107 for more details about it.
+         *
+         * Add $hide_squirrelmail_header as a candidate for config_local.php
+         * to allow completely hiding SquirrelMail participation in message
+         * processing; This is dangerous, especially if users can modify their 
+         * account information, as it makes mapping a sent message back to the
+         * original sender almost impossible.
          */
-        if (isset($encode_header_key) && 
+        $show_sm_header = ( defined('hide_squirrelmail_header') ? ! hide_squirrelmail_header : 1 );
+
+        if ( $show_sm_header ) {
+          if (isset($encode_header_key) &&
             trim($encode_header_key)!='') {
             // use encoded headers, if encryption key is set and not empty
-            $header[].= 'X-Squirrel-UserHash: '.OneTimePadEncrypt($username,base64_encode($encode_header_key)).$rn;
-            $header[].= 'X-Squirrel-FromHash: '.OneTimePadEncrypt($this->ip2hex($REMOTE_ADDR),base64_encode($encode_header_key)).$rn;
+            $header[] = 'X-Squirrel-UserHash: '.OneTimePadEncrypt($username,base64_encode($encode_header_key)).$rn;
+            $header[] = 'X-Squirrel-FromHash: '.OneTimePadEncrypt($this->ip2hex($REMOTE_ADDR),base64_encode($encode_header_key)).$rn;
             if (isset($HTTP_X_FORWARDED_FOR))
-                $header[].= 'X-Squirrel-ProxyHash:'.OneTimePadEncrypt($this->ip2hex($HTTP_X_FORWARDED_FOR),base64_encode($encode_header_key)).$rn;
-        } else {
+                $header[] = 'X-Squirrel-ProxyHash:'.OneTimePadEncrypt($this->ip2hex($HTTP_X_FORWARDED_FOR),base64_encode($encode_header_key)).$rn;
+          } else {
             // use default received headers
             $header[] = "Received: from $received_from" . $rn;
             if ($edit_identity || ! isset($hide_auth_header) || ! $hide_auth_header)
                 $header[] = "        (SquirrelMail authenticated user $username)" . $rn;
             $header[] = "        by $SERVER_NAME with HTTP;" . $rn;
             $header[] = "        $date" . $rn;
+          }
         }
 
         /* Insert the rest of the header fields */
         $header[] = 'Message-ID: '. $message_id . $rn;
-        if ($reply_rfc822_header->message_id) {
+        if (is_object($reply_rfc822_header) &&
+            isset($reply_rfc822_header->message_id) &&
+            $reply_rfc822_header->message_id) {
             $rep_message_id = $reply_rfc822_header->message_id;
         //        $this->strip_crlf($message_id);
             $header[] = 'In-Reply-To: '.$rep_message_id . $rn;
@@ -451,7 +469,8 @@ class Deliver {
         $header[] = 'Subject: '.encodeHeader($rfc822_header->subject) . $rn;
         $header[] = 'From: '. $rfc822_header->getAddr_s('from',",$rn ",true) . $rn;
 
-        // folding address list [From|To|Cc|Bcc] happens by using ",$rn<space>" as delimiter
+        // folding address list [From|To|Cc|Bcc] happens by using ",$rn<space>"
+        // as delimiter
         // Do not use foldLine for that.
 
         // RFC2822 if from contains more then 1 address
@@ -700,27 +719,36 @@ class Deliver {
     }
 
     /**
-     * function calculate_references - calculate correct Referer string
+     * function calculate_references - calculate correct References string
+     * Adds the current message ID, and makes sure it doesn't grow forever,
+     * to that extent it drops message-ID's in a smart way until the string
+     * length is under the recommended value of 1000 ("References: <986>\r\n").
+     * It always keeps the first and the last three ID's.
      *
      * @param   Rfc822Header $hdr    message header to calculate from
      *
-     * @return  string       $refer  concatenated and trimmed Referer string
+     * @return  string       $refer  concatenated and trimmed References string
      */
     function calculate_references($hdr) {
-        $refer = $hdr->references;
+        $aReferences = preg_split('/\s+/', $hdr->references);
         $message_id = $hdr->message_id;
         $in_reply_to = $hdr->in_reply_to;
-        if (strlen($refer) > 2) {
-            $refer .= ' ' . $message_id;
-        } else {
-            if ($in_reply_to) {
-                $refer .= $in_reply_to . ' ' . $message_id;
-            } else {
-                $refer .= $message_id;
-            }
+       
+        // if References already exists, add the current message ID at the end.
+        // no References exists; if we know a IRT, add that aswell
+        if (count($aReferences) == 0 && $in_reply_to) {
+            $aReferences[] = $in_reply_to;
+        }
+        $aReferences[] = $message_id;
+
+        // sanitize the array: trim whitespace, remove dupes
+        array_walk($aReferences, 'sq_trim_value');
+        $aReferences = array_unique($aReferences);
+
+        while ( count($aReferences) > 4 && strlen(implode(' ', $aReferences)) >= 986 ) {
+            $aReferences = array_merge(array_slice($aReferences,0,1),array_slice($aReferences,2));
         }
-        trim($refer);
-        return $refer;
+        return implode(' ', $aReferences);
     }
 
     /**
@@ -729,13 +757,13 @@ class Deliver {
      * Function is used to convert ipv4 and ipv6 addresses to hex strings.
      * It removes all delimiter symbols from ip addresses, converts decimal
      * ipv4 numbers to hex and pads strings in order to present full length
-     * address. ipv4 addresses are represented as 8 byte strings, ipv6 addresses 
+     * address. ipv4 addresses are represented as 8 byte strings, ipv6 addresses
      * are represented as 32 byte string.
      *
      * If function fails to detect address format, it returns unprocessed string.
      * @param string $string ip address string
      * @return string processed ip address string
-     * @since 1.5.1
+     * @since 1.5.1 and 1.4.5
      */
     function ip2hex($string) {
         if (preg_match("/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/",$string,$match)) {
@@ -784,4 +812,5 @@ class Deliver {
         return $ret;
     }
 }
-?>
\ No newline at end of file
+
+?>