Example #1
0
 /**
  * Build message part object
  *
  * @param array  $part
  * @param int    $count
  * @param string $parent
  */
 protected function structure_part($part, $count = 0, $parent = '', $mime_headers = null)
 {
     $struct = new rcube_message_part();
     $struct->mime_id = empty($parent) ? (string) $count : "{$parent}.{$count}";
     // multipart
     if (is_array($part[0])) {
         $struct->ctype_primary = 'multipart';
         /* RFC3501: BODYSTRUCTURE fields of multipart part
                part1 array
                part2 array
                part3 array
                ....
                1. subtype
                2. parameters (optional)
                3. description (optional)
                4. language (optional)
                5. location (optional)
            */
         // find first non-array entry
         for ($i = 1; $i < count($part); $i++) {
             if (!is_array($part[$i])) {
                 $struct->ctype_secondary = strtolower($part[$i]);
                 // read content type parameters
                 if (is_array($part[$i + 1])) {
                     $struct->ctype_parameters = array();
                     for ($j = 0; $j < count($part[$i + 1]); $j += 2) {
                         $param = strtolower($part[$i + 1][$j]);
                         $struct->ctype_parameters[$param] = $part[$i + 1][$j + 1];
                     }
                 }
                 break;
             }
         }
         $struct->mimetype = 'multipart/' . $struct->ctype_secondary;
         // build parts list for headers pre-fetching
         for ($i = 0; $i < count($part); $i++) {
             if (!is_array($part[$i])) {
                 break;
             }
             // fetch message headers if message/rfc822
             // or named part (could contain Content-Location header)
             if (!is_array($part[$i][0])) {
                 $tmp_part_id = $struct->mime_id ? $struct->mime_id . '.' . ($i + 1) : $i + 1;
                 if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
                     $mime_part_headers[] = $tmp_part_id;
                 } else {
                     if (in_array('name', (array) $part[$i][2]) && empty($part[$i][3])) {
                         $mime_part_headers[] = $tmp_part_id;
                     }
                 }
             }
         }
         // pre-fetch headers of all parts (in one command for better performance)
         // @TODO: we could do this before _structure_part() call, to fetch
         // headers for parts on all levels
         if ($mime_part_headers) {
             $mime_part_headers = $this->conn->fetchMIMEHeaders($this->folder, $this->msg_uid, $mime_part_headers);
         }
         $struct->parts = array();
         for ($i = 0, $count = 0; $i < count($part); $i++) {
             if (!is_array($part[$i])) {
                 break;
             }
             $tmp_part_id = $struct->mime_id ? $struct->mime_id . '.' . ($i + 1) : $i + 1;
             $struct->parts[] = $this->structure_part($part[$i], ++$count, $struct->mime_id, $mime_part_headers[$tmp_part_id]);
         }
         return $struct;
     }
     /* RFC3501: BODYSTRUCTURE fields of non-multipart part
            0. type
            1. subtype
            2. parameters
            3. id
            4. description
            5. encoding
            6. size
          -- text
            7. lines
          -- message/rfc822
            7. envelope structure
            8. body structure
            9. lines
          --
            x. md5 (optional)
            x. disposition (optional)
            x. language (optional)
            x. location (optional)
        */
     // regular part
     $struct->ctype_primary = strtolower($part[0]);
     $struct->ctype_secondary = strtolower($part[1]);
     $struct->mimetype = $struct->ctype_primary . '/' . $struct->ctype_secondary;
     // read content type parameters
     if (is_array($part[2])) {
         $struct->ctype_parameters = array();
         for ($i = 0; $i < count($part[2]); $i += 2) {
             $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i + 1];
         }
         if (isset($struct->ctype_parameters['charset'])) {
             $struct->charset = $struct->ctype_parameters['charset'];
         }
     }
     // #1487700: workaround for lack of charset in malformed structure
     if (empty($struct->charset) && !empty($mime_headers) && $mime_headers->charset) {
         $struct->charset = $mime_headers->charset;
     }
     // read content encoding
     if (!empty($part[5])) {
         $struct->encoding = strtolower($part[5]);
         $struct->headers['content-transfer-encoding'] = $struct->encoding;
     }
     // get part size
     if (!empty($part[6])) {
         $struct->size = intval($part[6]);
     }
     // read part disposition
     $di = 8;
     if ($struct->ctype_primary == 'text') {
         $di += 1;
     } else {
         if ($struct->mimetype == 'message/rfc822') {
             $di += 3;
         }
     }
     if (is_array($part[$di]) && count($part[$di]) == 2) {
         $struct->disposition = strtolower($part[$di][0]);
         if (is_array($part[$di][1])) {
             for ($n = 0; $n < count($part[$di][1]); $n += 2) {
                 $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n + 1];
             }
         }
     }
     // get message/rfc822's child-parts
     if (is_array($part[8]) && $di != 8) {
         $struct->parts = array();
         for ($i = 0, $count = 0; $i < count($part[8]); $i++) {
             if (!is_array($part[8][$i])) {
                 break;
             }
             $struct->parts[] = $this->structure_part($part[8][$i], ++$count, $struct->mime_id);
         }
     }
     // get part ID
     if (!empty($part[3])) {
         $struct->content_id = $part[3];
         $struct->headers['content-id'] = $part[3];
         if (empty($struct->disposition)) {
             $struct->disposition = 'inline';
         }
     }
     // fetch message headers if message/rfc822 or named part (could contain Content-Location header)
     if ($struct->ctype_primary == 'message' || $struct->ctype_parameters['name'] && !$struct->content_id) {
         if (empty($mime_headers)) {
             $mime_headers = $this->conn->fetchPartHeader($this->folder, $this->msg_uid, true, $struct->mime_id);
         }
         if (is_string($mime_headers)) {
             $struct->headers = rcube_mime::parse_headers($mime_headers) + $struct->headers;
         } else {
             if (is_object($mime_headers)) {
                 $struct->headers = get_object_vars($mime_headers) + $struct->headers;
             }
         }
         // get real content-type of message/rfc822
         if ($struct->mimetype == 'message/rfc822') {
             // single-part
             if (!is_array($part[8][0])) {
                 $struct->real_mimetype = strtolower($part[8][0] . '/' . $part[8][1]);
             } else {
                 for ($n = 0; $n < count($part[8]); $n++) {
                     if (!is_array($part[8][$n])) {
                         break;
                     }
                 }
                 $struct->real_mimetype = 'multipart/' . strtolower($part[8][$n]);
             }
         }
         if ($struct->ctype_primary == 'message' && empty($struct->parts)) {
             if (is_array($part[8]) && $di != 8) {
                 $struct->parts[] = $this->structure_part($part[8], ++$count, $struct->mime_id);
             }
         }
     }
     // normalize filename property
     $this->set_part_filename($struct, $mime_headers);
     return $struct;
 }