do not add spaces to references header (#1634294),
[squirrelmail.git] / class / mime / Message.class.php
index de6530f43b97dc6abdabbb36c36cdffac2917444..569cd67fb7461ee279846d977ce8296a011c790a 100644 (file)
@@ -3,11 +3,10 @@
 /**
  * Message.class.php
  *
- * Copyright (c) 2003-2005 The SquirrelMail Project Team
- * Licensed under the GNU GPL. For full terms see the file COPYING.
- *
- * This contains functions needed to handle mime messages.
+ * This file contains functions needed to handle mime messages.
  *
+ * @copyright © 2003-2007 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  * @version $Id$
  * @package squirrelmail
  * @subpackage mime
  */
 
 /**
- * The object that contains a message
+ * The object that contains a message.
  *
- * message is the object that contains messages.  It is a recursive
- * object in that through the $entities variable, it can contain
- * more objects of type message.  See documentation in mime.txt for
- * a better description of how this works.
+ * message is the object that contains messages. It is a recursive object in
+ * that through the $entities variable, it can contain more objects of type
+ * message. See documentation in mime.txt for a better description of how this
+ * works.
  * @package squirrelmail
  * @subpackage mime
  * @since 1.3.0
  */
 class Message {
-    var $rfc822_header = '',
-        $mime_header = '',
-        $flags = '',
-        $type0='',
-        $type1='',
-        $entities = array(),
-        $entity_id = '',
-        $parent_ent, $entity,
-        $parent = '', $decoded_body='',
-        $is_seen = 0, $is_answered = 0, $is_deleted = 0, $is_flagged = 0,
-        $is_mdnsent = 0,
-        $body_part = '',
-        $offset = 0,  /* for fetching body parts out of raw messages */
-        $length = 0,  /* for fetching body parts out of raw messages */
-        $att_local_name = ''; /* location where the tempory attachment
-                             is stored. For future usage in smtp.php */
-
-    /**
-     * @param mixed $ent entity id
+    /**
+     * rfc822header object
+     * @var object
+     */
+    var $rfc822_header = '';
+    /**
+     * MessageHeader object
+     * @var object
+     */
+    var $mime_header = '';
+    /**
+     * @var mixed
+     */
+    var $flags = '';
+    /**
+     * Media type
+     * @var string
+     */
+    var $type0='';
+    /**
+     * Media subtype
+     * @var string
+     */
+    var $type1='';
+    /**
+     * Nested mime parts
+     * @var array
+     */
+    var $entities = array();
+    /**
+     * Message part id
+     * @var string
+     */
+    var $entity_id = '';
+    /**
+     * Parent message part id
+     * @var string
+     */
+    var $parent_ent;
+    /**
+     * @var mixed
+     */
+    var $entity;
+    /**
+     * @var mixed
+     */
+    var $parent = '';
+    /**
+     * @var string
+     */
+    var $decoded_body='';
+    /**
+     * Message \seen status
+     * @var boolean
+     */
+    var $is_seen = 0;
+    /**
+     * Message \answered status
+     * @var boolean
+     */
+    var $is_answered = 0;
+    /**
+     * Message \deleted status
+     * @var boolean
+     */
+    var $is_deleted = 0;
+    /**
+     * Message \flagged status
+     * @var boolean
+     */
+    var $is_flagged = 0;
+    /**
+     * Message mdn status
+     * @var boolean
+     */
+    var $is_mdnsent = 0;
+    /**
+     * Message text body
+     * @var string
+     */
+    var $body_part = '';
+    /**
+     * Message part offset
+     * for fetching body parts out of raw messages
+     * @var integer
+     */
+    var $offset = 0;
+    /**
+     * Message part length
+     * for fetching body parts out of raw messages
+     * @var integer
+     */
+    var $length = 0;
+    /**
+     * Local attachment filename location where the tempory attachment is
+     * stored. For use in delivery class.
+     * @var string
+     */
+    var $att_local_name = '';
+
+    /**
+     * @param string $ent entity id
      */
     function setEnt($ent) {
         $this->entity_id= $ent;
     }
 
     /**
-     * @param mixed $msg
+     * Add nested message part
+     * @param object $msg
      */
     function addEntity ($msg) {
         $this->entities[] = $msg;
@@ -113,6 +196,7 @@ class Message {
 
     /**
      * @param string $ent
+     * @return mixed (object or string?)
      */
     function getEntity($ent) {
         $cur_ent = $this->entity_id;
@@ -574,14 +658,25 @@ class Message {
     }
 
     /**
+     * function parseQuote
+     *
+     * This extract the string value from a quoted string. After the end-quote
+     * character is found it returns the string. The offset $i when calling
+     * this function points to the first double quote. At the end it points to
+     * The ending quote. This function takes care of escaped double quotes.
+     * "some \"string\""
+     * ^               ^
+     * initial $i      end position $i
+     *
      * @param string $read
-     * @param integer $i
-     * @return string
-     * @todo document me
+     * @param integer $i offset in $read
+     * @return string string inbetween the double quotes
+     * @author Marc Groot Koerkamp
      */
     function parseQuote($read, &$i) {
         $s = '';
         $iPos = ++$i;
+        $iPosStart = $iPos;
         while (true) {
             $iPos = strpos($read,'"',$iPos);
             if (!$iPos) break;
@@ -589,6 +684,38 @@ class Message {
                 $s = substr($read,$i,($iPos-$i));
                 $i = $iPos;
                 break;
+            } else if ($iPos > 1 && $read{$iPos -1} == '\\' && $read{$iPos-2} == '\\') {
+                // This is an unique situation where the fast detection of the string
+                // fails. If the quote string ends with \\ then we need to iterate
+                // through the entire string to make sure we detect the unexcaped
+                // double quotes correctly.
+                $s = '';
+                $bEscaped = false;
+                $k = 0;
+                 for ($j=$iPosStart,$iCnt=strlen($read);$j<$iCnt;++$j) {
+                    $cChar = $read{$j};
+                    switch ($cChar) {
+                        case '\\':
+                           $bEscaped = !$bEscaped;
+                            $s .= $cChar;
+                            break;
+                         case '"':
+                            if ($bEscaped) {
+                                $s .= $cChar;
+                                $bEscaped = false;
+                            } else {
+                                $i = $j;
+                                break 3;
+                            }
+                            break;
+                         default:
+                            if ($bEscaped) {
+                               $bEscaped = false;
+                            }
+                            $s .= $cChar;
+                            break;
+                    }
+                }
             }
             ++$iPos;
             if ($iPos > strlen($read)) {
@@ -655,7 +782,6 @@ class Message {
                 $disp->properties = $arg_a[1];
             }
         }
-
         return (is_object($disp) ? $disp : '');
     }
 
@@ -683,7 +809,6 @@ class Message {
                 $lang->properties = $arg_a[1];
             }
         }
-
         return (is_object($lang) ? $lang : '');
     }
 
@@ -712,7 +837,7 @@ class Message {
      * @param string $read
      * @param string $type0 message part type
      * @param string $type1 message part subtype
-     * @return string
+     * @return string (only when type0 is not message or multipart)
      */
     function parseMessage($read, $type0, $type1) {
         switch ($type0) {
@@ -813,9 +938,9 @@ class Message {
             } else { /* Treat as multipart/mixed */
                 foreach ($this->entities as $ent) {
                     if(!(is_object($ent->header->disposition) && strtolower($ent->header->disposition->name) == 'attachment') &&
-                (!isset($ent->header->parameters['filename'])) &&
-                (!isset($ent->header->parameters['name'])) &&
-                       (($ent->type0 != 'message') && ($ent->type1 != 'rfc822'))) {
+                            (!isset($ent->header->parameters['filename'])) &&
+                            (!isset($ent->header->parameters['name'])) &&
+                            (($ent->type0 != 'message') && ($ent->type1 != 'rfc822'))) {
                         $entity = $ent->findDisplayEntity($entity, $alt_order, $strict);
                         $found = true;
                     }
@@ -827,10 +952,10 @@ class Message {
             foreach ($alt_order as $alt) {
                 if( ($alt == $type) && isset($this->entity_id) ) {
                     if ((count($this->entities) == 0) &&
-                (!isset($this->header->parameters['filename'])) &&
-                (!isset($this->header->parameters['name'])) &&
-                isset($this->header->disposition) && is_object($this->header->disposition) &&
-                        !(is_object($this->header->disposition) && strtolower($this->header->disposition->name) == 'attachment')) {
+                            (!isset($this->header->parameters['filename'])) &&
+                            (!isset($this->header->parameters['name'])) &&
+                            isset($this->header->disposition) && is_object($this->header->disposition) &&
+                            !(is_object($this->header->disposition) && strtolower($this->header->disposition->name) == 'attachment')) {
                         $entity[] = $this->entity_id;
                         $found = true;
                     }
@@ -884,7 +1009,6 @@ class Message {
                 }
             }
         }
-
         return $entity;
     }
 
@@ -975,6 +1099,18 @@ class Message {
         $attachment->mime_header = $mime_header;
         $this->entities[]=$attachment;
     }
-}
 
-?>
\ No newline at end of file
+    /**
+     * Delete all attachments from this object from disk.
+     * @since 1.5.1
+     */
+    function purgeAttachments() {
+        if ($this->att_local_name && file_exists($this->att_local_name)) {
+            unlink($this->att_local_name);
+        }
+        // recursively delete attachments from entities contained in this object
+        for ($i=0, $entCount=count($this->entities);$i< $entCount; ++$i) {
+            $this->entities[$i]->purgeAttachments();
+        }
+    }
+}