Note a bug
[squirrelmail.git] / functions / mime.php
index bcd174090636b6b2fb5427085cec4e5f7b4bef7c..3ed5ab82b127b7bcd2905cf956fc9de85fb025ee 100644 (file)
@@ -6,7 +6,7 @@
  * This contains the functions necessary to detect and decode MIME
  * messages.
  *
- * @copyright 1999-2009 The SquirrelMail Project Team
+ * @copyright 1999-2012 The SquirrelMail Project Team
  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  * @version $Id$
  * @package squirrelmail
@@ -63,7 +63,7 @@ function mime_structure ($bodystructure, $flags=array()) {
         displayPageHeader( $color, $mailbox );
         $errormessage  = _("SquirrelMail could not decode the bodystructure of the message");
         $errormessage .= '<br />'._("The bodystructure provided by your IMAP server:").'<br /><br />';
-        $errormessage .= '<pre>' . htmlspecialchars($read) . '</pre>';
+        $errormessage .= '<pre>' . sm_encode_html_special_chars($read) . '</pre>';
         plain_error_message( $errormessage );
         echo '</body></html>';
         exit;
@@ -137,7 +137,13 @@ function mime_fetch_body($imap_stream, $id, $ent_id=1, $fetch_size=0) {
     $data = sqimap_run_command ($imap_stream, $cmd, true, $response, $message, TRUE);
     do {
         $topline = trim(array_shift($data));
-    } while($topline && ($topline[0] == '*') && !preg_match('/\* [0-9]+ FETCH.*/i', $topline)) ;
+    } while($topline && ($topline[0] == '*') && !preg_match('/\* [0-9]+ FETCH .*BODY.*/i', $topline)) ;
+    // Matching with "BODY" above is difficult: in most cases "FETCH \(BODY" would work
+    // but some servers may put other things in the same result, perhaps something such
+    // as "* 23 FETCH (FLAGS (\Seen) BODY[1] {174}".  There is some small chance that
+    // if the character sequence "BODY" appears in a response where it isn't actually
+    // a FETCH response data item name, the current regex will break things.  The better
+    // way to do this would be to parse the response correctly and not use a regex.
 
     $wholemessage = implode('', $data);
     if (preg_match('/\{([^\}]*)\}/', $topline, $regs)) {
@@ -575,9 +581,9 @@ function buildAttachmentArray($message, $exclude_id, $mailbox, $id) {
         }
 
         /* This executes the attachment hook with a specific MIME-type.
-         * If that doesn't have results, it tries if there's a rule
-         * for a more generic type. Finally, a hook for ALL attachment
-         * types is run as well.
+         * It also allows plugins to run if there's a rule for a more
+         * generic type. Finally, a hook for ALL attachment types is
+         * run as well.
          */
         // First remember the default link.
         $defaultlink_orig = $defaultlink;
@@ -587,19 +593,23 @@ function buildAttachmentArray($message, $exclude_id, $mailbox, $id) {
            argument, and arguments are passed by reference, so instead of
            returning any changes, changes should simply be made to the original
            arguments themselves. */
-        $temp = array(&$links, &$startMessage, &$id, &$urlMailbox, &$ent, 
+        $temp = array(&$links, &$startMessage, &$id, &$urlMailbox, &$ent,
                     &$defaultlink, &$display_filename, &$where, &$what);
         do_hook("attachment $type0/$type1", $temp);
-        if(count($links) <= 1 && $defaultlink == $defaultlink_orig) {
-            /* The API for this hook has changed as of 1.5.2 so that all plugin
-               arguments are passed in an array instead of each their own plugin
-               argument, and arguments are passed by reference, so instead of
-               returning any changes, changes should simply be made to the original
-               arguments themselves. */
-            $temp = array(&$links, &$startMessage, &$id, &$urlMailbox, &$ent, 
-                          &$defaultlink, &$display_filename, &$where, &$what);
-            do_hook("attachment $type0/*", $temp);
+        /* The API for this hook has changed as of 1.5.2 so that all plugin
+           arguments are passed in an array instead of each their own plugin
+           argument, and arguments are passed by reference, so instead of
+           returning any changes, changes should simply be made to the original
+           arguments themselves. */
+        $temp = array(&$links, &$startMessage, &$id, &$urlMailbox, &$ent,
+                      &$defaultlink, &$display_filename, &$where, &$what);
+        // Do not let a generic plugin change the default link if a more
+        // specialized one already did it...
+        if ($defaultlink != $defaultlink_orig) {
+            $dummy = '';
+            $temp[5] = &$dummy;
         }
+        do_hook("attachment $type0/*", $temp);
         /* The API for this hook has changed as of 1.5.2 so that all plugin
            arguments are passed in an array instead of each their own plugin
            argument, and arguments are passed by reference, so instead of
@@ -622,7 +632,7 @@ function buildAttachmentArray($message, $exclude_id, $mailbox, $id) {
         $this_attachment['DownloadHREF'] = $links['download link']['href'];
         $this_attachment['ViewHREF'] = isset($links['attachment_common']) ? $links['attachment_common']['href'] : '';
         $this_attachment['Size'] = $header->size;
-        $this_attachment['ContentType'] = htmlspecialchars($type0 .'/'. $type1);
+        $this_attachment['ContentType'] = sm_encode_html_special_chars($type0 .'/'. $type1);
         $this_attachment['OtherLinks'] = array();
         foreach ($links as $val) {
             if ($val['text']==_("Download") || $val['text'] == _("View"))
@@ -796,6 +806,7 @@ function decodeHeader ($string, $utfencode=true,$htmlsafe=true,$decide=false) {
     $iLastMatch = -2;
     $encoded = true;
 
+// FIXME: spaces are allowed inside quoted-printable encoding, but the following line will bust up any such encoded strings
     $aString = explode(' ',$string);
     $ret = '';
     foreach ($aString as $chunk) {
@@ -821,7 +832,7 @@ function decodeHeader ($string, $utfencode=true,$htmlsafe=true,$decide=false) {
             $iLastMatch = $i;
             $j = $i;
             if ($htmlsafe) {
-                $ret .= htmlspecialchars($res[1]);
+                $ret .= sm_encode_html_special_chars($res[1]);
             } else {
                 $ret .= $res[1];
             }
@@ -850,14 +861,15 @@ function decodeHeader ($string, $utfencode=true,$htmlsafe=true,$decide=false) {
                         }
                     } else {
                         if ($htmlsafe) {
-                            $replace = htmlspecialchars($replace);
+                            $replace = sm_encode_html_special_chars($replace);
                         }
                         $ret.= $replace;
                     }
                     break;
                 case 'Q':
                     $replace = str_replace('_', ' ', $res[4]);
-                    $replace = preg_replace('/=([0-9a-f]{2})/ie', 'chr(hexdec("\1"))',
+                    $replace = preg_replace_callback('/=([0-9a-f]{2})/i',
+                            create_function ('$matches', 'return chr(hexdec($matches[1]));'),
                             $replace);
                     if ($utfencode) {
                         if ($can_be_encoded) {
@@ -871,7 +883,7 @@ function decodeHeader ($string, $utfencode=true,$htmlsafe=true,$decide=false) {
                         }
                     } else {
                         if ($htmlsafe) {
-                            $replace = htmlspecialchars($replace);
+                            $replace = sm_encode_html_special_chars($replace);
                         }
                     }
                     $ret .= $replace;
@@ -891,7 +903,7 @@ function decodeHeader ($string, $utfencode=true,$htmlsafe=true,$decide=false) {
         }
 
         if (!$encoded && $htmlsafe) {
-            $ret .= htmlspecialchars($chunk);
+            $ret .= sm_encode_html_special_chars($chunk);
         } else {
             $ret .= $chunk;
         }
@@ -958,6 +970,7 @@ function encodeHeader ($string) {
     for($i = 0; $i < $j; ++$i) {
         switch($string{$i})
         {
+            case '"':
             case '=':
             case '<':
             case '>':
@@ -2006,7 +2019,7 @@ function sq_fix_url($attname, &$attvalue, $message, $id, $mailbox,$sQuote = '"')
                         break;
                 }
             } else {
-                if (!(isset($aUrl['path']) && $aUrl['path'] == $secremoveimg)) {
+                if (!isset($aUrl['path']) || $aUrl['path'] != $secremoveimg) {
                     // parse_url did not lead to satisfying result
                     $attvalue = $sQuote . SM_PATH . 'images/blank.png' . $sQuote;
                 }
@@ -2345,6 +2358,17 @@ function sq_sanitize($body,
             list($free_content, $curpos) =
                 sq_fixstyle($body, $gt+1, $message, $id, $mailbox);
             if ($free_content != FALSE){
+                if ( !empty($attary) ) {
+                    $attary = sq_fixatts($tagname,
+                                         $attary,
+                                         $rm_attnames,
+                                         $bad_attvals,
+                                         $add_attr_to_tag,
+                                         $message,
+                                         $id,
+                                         $mailbox
+                                         );
+                }
                 $trusted .= sq_tagprint($tagname, $attary, $tagtype);
                 $trusted .= $free_content;
                 $trusted .= sq_tagprint($tagname, false, 2);