this is a fix for the LSUB with a % when getting the folder list. This makes the...
[squirrelmail.git] / functions / mime.php
index 95baa011839bf88db9a8cb9181657baae15c8fc4..68d82a4339a37a5757dde62169445d9f702209c8 100644 (file)
@@ -92,6 +92,7 @@ function mime_structure ($imap_stream, $header) {
  * to mime_get_elements()
  */
 function mime_parse_structure ($structure, $ent_id) {
+  global $mailbox;
   $properties = array();
   $msg = new message();
   if ($structure{0} == '(') {
@@ -101,38 +102,65 @@ function mime_parse_structure ($structure, $ent_id) {
      do {
         $start = $end+1;
         $end = mime_match_parenthesis ($start, $structure);
+
+       /* check if we are dealing with a new entity-level */
+       $i = strrpos($ent_id,'.');
+       if ($i>0) {
+           $ent = substr($ent_id, $i+1);
+       } else {
+           $ent = '';
+       }
         /* add "forgotten"  parent entities (alternative and relative) */
-       if (strpos($ent_id, '0')  || strpos($ent_id, '0') == 0) { 
-           $str = substr($structure, $end+1 );
-           $startprop = strrpos($str,'(');
-           $endprop   = strrpos($str,')');
-           $propstr = substr($str, $startprop + 1, ($endprop - $startprop)-1);
-
-           $type1 = trim(substr($str,0, $startprop));
-           $pos = strrpos($type1,' ');
-           $type1 = strtolower(trim(substr($type1,$pos +1)));
-           $cnt = strlen($type1);
-           $type1 = substr($type1,0,$cnt-1);
-     
-            $properties = mime_get_props($properties, $propstr);
+       if ($ent == '0') {
+           /* new entity levels have information about the type (type1) and 
+           *  the properties. This information is situated at the end of the 
+           *  structure string like for example (example between the brackets) 
+           *  [ "RELATED" ("BOUNDARY" "myboundary" "TYPE" "plain/html") ]
+           */
+           
+           /* get the involved properties for parsing to mime_get_properties */
+           $startprop = strrpos($structure,'(');
+           $properties_str = substr($structure,$startprop);
+           $endprop = mime_match_parenthesis ($startprop, $structure);
+           $propstr = substr($structure, $startprop + 1, ($endprop - $startprop)-1);
+           /* cut off the used properties */
+           if ($startprop) { 
+               $structure_end = substr($structure, $endprop+2);
+               $structure = trim(substr($structure,0,$startprop));
+           }
+           /* get type1 */
+           $pos = strrpos($structure,' ');
+           if ($structure{$pos+1} =='(') $pos++;
+           
+           $type1 = strtolower(substr($structure, $pos+2, (count($structure)-2)));
+           /* cut off  type1 */
+           if ($pos && $startprop) {
+               $structure = trim(substr($structure, 0, $pos));
+           }
+
+           /* process the found information */
+            $properties = mime_get_props($properties, $properties_str);
            if (count($properties)>0) {
                $msg->header->entity_id = $old_ent_id;
                $msg->header->type0 = 'multipart';
                $msg->header->type1 = $type1;
+               for ($i=0; $i < count($properties); $i++) {
+                   $msg->header->{$properties[$i]['name']} = $properties[$i]['value'];
+               }
            }
-           for ($i=0; $i < count($properties); $i++) {
-               $msg->header->{$properties[$i]['name']} = $properties[$i]['value'];
-               $name = $properties[$i]['name'];
-               $value = $properties[$i]['value'];
+           $structure = $structure . ' ' . $structure_end;
+       } 
+       $element = substr($structure, $start+1, ($end - $start)-1);
+       $ent_id = mime_increment_id ($ent_id);
+       $newmsg = mime_parse_structure ($element, $ent_id);
+       /* set mailbox in case of message/rfc822 entities */
+       if (isset($newmsg->header->type0) && isset($newmsg->header->type1)) {
+           if ($newmsg->header->type0 == 'message' && $newmsg->header->type1 == 'rfc822') {
+               $newmsg->header->mailbox=$mailbox;
            }
        }
+       $msg->addEntity ($newmsg);
 
-        $element = substr($structure, $start+1, ($end - $start)-1);
-       
-        $ent_id = mime_increment_id ($ent_id);
-        $newmsg = mime_parse_structure ($element, $ent_id);
-        $msg->addEntity ($newmsg);
-       
      } while ($structure{$end+1} == '(');
   } else {
      // parse the elements
@@ -141,6 +169,7 @@ function mime_parse_structure ($structure, $ent_id) {
   return $msg;
 }
 
+
 /* Increments the element ID.  An element id can look like any of
  * the following:  1, 1.2, 4.3.2.4.1, etc.  This function increments
  * the last number of the element id, changing 1.2 to 1.3.
@@ -200,6 +229,21 @@ function mime_get_element (&$structure, $msg, $ent_id) {
            $pos++;
         }
         $structure = substr($structure, strlen($text) + 2);
+     } else if ($char == '{') {
+         /**
+          * loop through until we find the matching quote, 
+          * and return that as a string
+          */
+         $pos = 1;
+         $len = '';
+         while (($char = $structure{$pos}) != '}' 
+                && $pos < strlen($structure)) {
+             $len .= $char;
+             $pos++;
+         }
+         $structure = substr($structure, strlen($len) + 4);
+         $text = substr($structure, 0, $len);
+         $structure = substr($structure, $len + 1);
      } else if ($char == '(') {
         // comment me
         $end = mime_match_parenthesis (0, $structure);
@@ -397,7 +441,7 @@ function mime_match_parenthesis ($pos, $structure) {
     return( $pos );
 }
 
-function mime_fetch_body($imap_stream, $id, $ent_id ) {
+function mime_fetch_body($imap_stream, $id, $ent_id) {
 
     /*
      * do a bit of error correction.  If we couldn't find the entity id, just guess
@@ -406,10 +450,9 @@ function mime_fetch_body($imap_stream, $id, $ent_id ) {
     if (!$ent_id) {
         $ent_id = 1;
     }
-
     $cmd = "FETCH $id BODY[$ent_id]";
-    $data = sqimap_run_command ($imap_stream, $cmd, true, $response, $message);
 
+    $data = sqimap_run_command ($imap_stream, $cmd, true, $response, $message);
     do {
         $topline = trim(array_shift( $data ));
     } while( $topline && $topline[0] == '*' && !preg_match( '/\* [0-9]+ FETCH.*/i', $topline )) ;
@@ -574,36 +617,49 @@ function getEntity ($message, $ent_id) {
  * figures out what entity to display and returns the $message object
  * for that entity.
  */
-function findDisplayEntity ($msg, $textOnly = 1)   {
+function findDisplayEntity ($msg, $textOnly = true, $entity = array() )   {
     global $show_html_default;
     
-    $entity = 0;
-    
+    $found = false;    
     if ($msg) {
-        if ( $msg->header->type0 == 'multipart' &&
-             ( $msg->header->type1 == 'alternative' ||
-               $msg->header->type1 == 'mixed' ||              
-               $msg->header->type1 == 'related' ) &&
-             $show_html_default && ! $textOnly ) {
-            $entity = findDisplayEntityHTML($msg);
-        }
-
-        // Show text/plain or text/html -- the first one we find.
-        if ( $entity == 0 &&
+        $type = $msg->header->type0.'/'.$msg->header->type1;
+        if ( $type == 'multipart/alternative') {
+           $msg = findAlternativeEntity($msg, $textOnly);
+           if (count($msg->entities) == 0) {
+               $entity[] = $msg->header->entity_id;
+           } else {
+               $found = true;
+                $entity =findDisplayEntity($msg,$textOnly, $entity);
+           }
+       } else  if ( $type == 'multipart/related') {
+            $msgs = findRelatedEntity($msg);
+           for ($i = 0; $i < count($msgs); $i++) {
+               $msg = $msgs[$i];
+               if (count($msg->entities) == 0) {
+                   $entity[] = $msg->header->entity_id;
+               } else {
+                   $found = true;
+                    $entity =findDisplayEntity($msg,$textOnly, $entity);
+               }
+           }
+       } else if ( count($entity) == 0 &&
              $msg->header->type0 == 'text' &&
              ( $msg->header->type1 == 'plain' ||
                $msg->header->type1 == 'html' ) &&
              isset($msg->header->entity_id) ) {
-            $entity = $msg->header->entity_id;
-        }
-    
-        $i = 0;
-        while ($entity == 0 && isset($msg->entities[$i]) ) {
-            $entity = findDisplayEntity($msg->entities[$i], $textOnly);
-            $i++;
-        }
+            if (count($msg->entities) == 0) {
+               $entity[] = $msg->header->entity_id;
+            } 
+        } 
+       $i = 0;
+       while ( isset($msg->entities[$i]) && count($entity) == 0 && !$found )  {
+           $entity = findDisplayEntity($msg->entities[$i], $textOnly, $entity);
+           $i++;
+       }
+    }
+    if ( !isset($entity[0]) ) {
+        $entity[]="";
     }
-    
     return( $entity );
 }
 
@@ -621,6 +677,7 @@ function findDisplayEntityHTML ($message) {
             isset($message->header->entity_id)) {
            return 0;
        }
+       
         $entity = findDisplayEntityHTML($message->entities[$i]);
         if ($entity != 0) {
             return $entity;
@@ -630,6 +687,46 @@ function findDisplayEntityHTML ($message) {
     return 0;
 }
 
+function findAlternativeEntity ($message, $textOnly) {
+    global $show_html_default;
+    /* if we are dealing with alternative parts then we choose the best 
+     * viewable message supported by SM.
+     */
+    if ($show_html_default && !$textOnly) {     
+       $alt_order = array ('text/plain','text/html');
+    } else {
+       $alt_order = array ('text/plain');
+    }
+    $best_view = 0;
+    $ent_id = 0;
+    $k = 0; 
+    for ($i = 0; $i < count($message->entities); $i ++) {
+        $type = $message->entities[$i]->header->type0.'/'.$message->entities[$i]->header->type1;
+       if ($type == 'multipart/related') {
+          $type = $message->entities[$i]->header->type;
+       }
+       for ($j = $k; $j < count($alt_order); $j++) {
+           if ($alt_order[$j] == $type && $j > $best_view) {
+               $best_view = $j;
+               $ent_id = $i;
+               $k = $j;
+           }
+       }
+    }
+    return $message->entities[$ent_id];
+}
+
+function findRelatedEntity ($message) {
+    $msgs = array(); 
+    for ($i = 0; $i < count($message->entities); $i ++) {
+        $type = $message->entities[$i]->header->type0.'/'.$message->entities[$i]->header->type1;
+        if ($message->header->type == $type) {
+           $msgs[] = $message->entities[$i];
+       }
+    }
+    return $msgs;
+}    
+
 /*
  * translateText
  * Extracted from strings.php 23/03/2002
@@ -721,11 +818,11 @@ be displayed as the actual message in the HTML. It contains
 everything needed, including HTML Tags, Attachments at the
 bottom, etc.
 */
-function formatBody($imap_stream, $message, $color, $wrap_at) {
+function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num) {
     // this if statement checks for the entity to show as the
     // primary message. To add more of them, just put them in the
     // order that is their priority.
-    global $startMessage, $username, $key, $imapServerAddress, $imapPort, $body,
+    global $startMessage, $username, $key, $imapServerAddress, $imapPort,
            $show_html_default, $has_unsafe_images, $view_unsafe_images, $sort;
 
     $has_unsafe_images = 0;
@@ -733,14 +830,12 @@ function formatBody($imap_stream, $message, $color, $wrap_at) {
     $id = $message->header->id;
 
     $urlmailbox = urlencode($message->header->mailbox);
-//    ListMyEntities($message); 
-    // Get the right entity and redefine message to be this entity
-    // Pass the 0 to mean that we want the 'best' viewable one
-    $ent_num = findDisplayEntity ($message, 0);
+
     $body_message = getEntity($message, $ent_num);
     if (($body_message->header->type0 == 'text') ||
         ($body_message->header->type0 == 'rfc822')) {
-        $body = mime_fetch_body ($imap_stream, $id, $ent_num);
+       $body = mime_fetch_body ($imap_stream, $id, $ent_num);
+       
         $body = decodeBody($body, $body_message->header->encoding);
         $hookResults = do_hook("message_body", $body);
         $body = $hookResults[1];
@@ -751,12 +846,11 @@ function formatBody($imap_stream, $message, $color, $wrap_at) {
                 $body = strip_tags( $body );
                 translateText($body, $wrap_at, $body_message->header->charset);
             } else {
-                $body = MagicHTML( $body, $id );
+                $body = magicHTML( $body, $id, $message );
             }
         } else {
             translateText($body, $wrap_at, $body_message->header->charset);
         }
-
         $body .= "<CENTER><SMALL><A HREF=\"../src/download.php?absolute_dl=true&amp;passed_id=$id&amp;passed_ent_id=$ent_num&amp;mailbox=$urlmailbox&amp;showHeaders=1\">". _("Download this as a file") ."</A></SMALL></CENTER><BR>";
         if ($has_unsafe_images) {
             if ($view_unsafe_images) {
@@ -767,8 +861,14 @@ function formatBody($imap_stream, $message, $color, $wrap_at) {
         }
 
         /** Display the ATTACHMENTS: message if there's more than one part **/
-        if (isset($message->entities[0])) {
-            $body .= formatAttachments ($message, $ent_num, $message->header->mailbox, $id);
+        if (isset($message->entities[1])) {
+           /* Header-type alternative means we choose the best one to display 
+              so don't show the alternatives as attachment. Header-type related
+              means that the attachments are already part of the related message.
+           */   
+           if ($message->header->type1 !='related' && $message->header->type1 !='alternative') {
+               $body .= formatAttachments ($message, $ent_num, $message->header->mailbox, $id);
+           }
         }
     } else {
         $body = formatAttachments ($message, -1, $message->header->mailbox, $id);
@@ -903,7 +1003,7 @@ function formatAttachments($message, $ent_id, $mailbox, $id) {
             $DefaultLink =
                 "../src/download.php?startMessage=$startMessage&amp;passed_id=$id&amp;mailbox=$urlMailbox&amp;passed_ent_id=$ent";
             if ($where && $what) {
-                $DefaultLink .= '&amp;where=' . urlencode($where) . '&amp;what=' . urlencode($what);
+              $DefaultLink = '&amp;where='. urlencode($where).'&amp;what='.urlencode($what);
             }
             $Links['download link']['text'] = _("download");
             $Links['download link']['href'] =
@@ -968,7 +1068,8 @@ function decodeBody($body, $encoding) {
 
   global $show_html_default;
 
-  if ($encoding == 'quoted-printable') {
+  if ($encoding == 'quoted-printable' ||
+      $encoding == 'quoted_printable') {
      $body = quoted_printable_decode($body);
 
 
@@ -1067,17 +1168,17 @@ function encodeHeader ($string) {
 function find_ent_id( $id, $message ) {
     $ret = '';
     for ($i=0; $ret == '' && $i < count($message->entities); $i++) {
-       if ( $message->entities[$i]->header->entity_id == '' || $message->entities[$i]->header->type ) {
-            $ret = find_ent_id( $id, $message->entities[$i] );
+       if (( $message->entities[$i]->header->type1 == 'alternative') ||         
+           ( $message->entities[$i]->header->type1 == 'related') ||     
+           ( $message->entities[$i]->header->type1 == 'mixed')) {       
+           $ret = find_ent_id( $id, $message->entities[$i] );
         } else {
             if ( strcasecmp( $message->entities[$i]->header->id, $id ) == 0 )
                 $ret = $message->entities[$i]->header->entity_id;
         }
 
     }
-
     return( $ret );
-
 }
 
 /**
@@ -1142,8 +1243,6 @@ function sq_skipspace($body, $offset){
     if (sizeof($matches{1})){
         $count = strlen($matches{1});
         $offset += $count;
-        if ($pos >= strlen($body)){
-        }
     }
     return $offset;
 }
@@ -1343,8 +1442,7 @@ function sq_getnxtag($body, $offset){
          * the end of the tag.
          */
         $matches = Array();
-        preg_match("%^(\s*)(>|/>)%s", substr($body, $pos), $matches);
-        if ($matches{0}){
+        if (preg_match("%^(\s*)(>|/>)%s", substr($body, $pos), $matches)) {
             /**
              * Yep. So we did.
              */
@@ -1401,7 +1499,7 @@ function sq_getnxtag($body, $offset){
                 $pos++;
                 $tagtype = 3;
             } else {
-                $gt = getnxstr($body, $pos, ">");
+                $gt = sq_findnxstr($body, $pos, ">");
                 $retary = Array(false, false, false, $lt, $gt);
                 return $retary;
             }
@@ -1786,11 +1884,6 @@ function sq_sanitize($body,
              * content before we apply it.
              */
             $free_content = sq_fixstyle($message, $id, $free_content);
-        } else if ($tagname == "body"){
-            $tagname = "div";
-            if ($tagtype == 1){
-                $attary = sq_body2div($attary);
-            }
         }
         if ($skip_content == false){
             $trusted .= $free_content;
@@ -1806,11 +1899,15 @@ function sq_sanitize($body,
                     $skip_content = false;
                 } else {
                     if ($skip_content == false){
-                        if (isset($open_tags{$tagname}) && 
-                            $open_tags{$tagname} > 0){
-                            $open_tags{$tagname}--;
+                        if ($tagname == "body"){
+                            $tagname = "div";
                         } else {
-                            $tagname = false;
+                            if (isset($open_tags{$tagname}) && 
+                                $open_tags{$tagname} > 0){
+                                $open_tags{$tagname}--;
+                            } else {
+                                $tagname = false;
+                            }
                         }
                     } else {
                     }
@@ -1862,6 +1959,13 @@ function sq_sanitize($body,
                                                      $id
                                                      );
                             }
+                            /**
+                             * Convert body into div.
+                             */
+                            if ($tagname == "body"){
+                                $tagname = "div";
+                                $attary = sq_body2div($attary, $message, $id);
+                            }
                         }
                     }
                 } else {
@@ -1895,9 +1999,9 @@ function sq_sanitize($body,
  * @param  $id    the id of the message
  * @return        a string with html safe to display in the browser.
  */
-function magicHTML($body, $id){
+function magicHTML($body, $id, $message){
     global $attachment_common_show_images, $view_unsafe_images,
-        $has_unsafe_images, $message;
+        $has_unsafe_images;
     /**
      * Don't display attached images in HTML mode.
      */