/** * Test parse_message() */ function test_parse_message() { $file = file_get_contents(__DIR__ . '/../src/html.msg'); $result = rcube_mime::parse_message($file); $this->assertInstanceOf('rcube_message_part', $result); $this->assertSame('multipart/alternative', $result->mimetype); $this->assertSame('1.0', $result->headers['mime-version']); $this->assertSame('=_68eeaf4ab95b5312965e45c33362338e', $result->ctype_parameters['boundary']); $this->assertSame('1', $result->parts[0]->mime_id); $this->assertSame(12, $result->parts[0]->size); $this->assertSame('text/plain', $result->parts[0]->mimetype); $this->assertSame("this is test", $result->parts[0]->body); $this->assertSame('2', $result->parts[1]->mime_id); $this->assertSame(0, $result->parts[1]->size); $this->assertSame('multipart/related', $result->parts[1]->mimetype); $this->assertCount(2, $result->parts[1]->parts); $this->assertSame('2.1', $result->parts[1]->parts[0]->mime_id); $this->assertSame(257, $result->parts[1]->parts[0]->size); $this->assertSame('text/html', $result->parts[1]->parts[0]->mimetype); $this->assertSame('UTF-8', $result->parts[1]->parts[0]->charset); $this->assertRegExp('/<html>/', $result->parts[1]->parts[0]->body); $this->assertSame('2.2', $result->parts[1]->parts[1]->mime_id); $this->assertSame(793, $result->parts[1]->parts[1]->size); $this->assertSame('image/jpeg', $result->parts[1]->parts[1]->mimetype); $this->assertSame('base64', $result->parts[1]->parts[1]->encoding); $this->assertSame('inline', $result->parts[1]->parts[1]->disposition); $this->assertSame('photo-mini.jpg', $result->parts[1]->parts[1]->filename); }
/** * Fetch message headers and body structure from the IMAP server and build * an object structure. * * @param int $uid Message UID to fetch * @param string $folder Folder to read from * * @return object rcube_message_header Message data */ public function get_message($uid, $folder = null) { if (!strlen($folder)) { $folder = $this->folder; } // decode combined UID-folder identifier if (preg_match('/^\\d+-.+/', $uid)) { list($uid, $folder) = explode('-', $uid, 2); } // Check internal cache if (!empty($this->icache['message'])) { if (($headers = $this->icache['message']) && $headers->uid == $uid) { return $headers; } } $headers = $this->get_message_headers($uid, $folder); // message doesn't exist? if (empty($headers)) { return null; } // structure might be cached if (!empty($headers->structure)) { return $headers; } $this->msg_uid = $uid; if (!$this->check_connection()) { return $headers; } if (empty($headers->bodystructure)) { $headers->bodystructure = $this->conn->getStructure($folder, $uid, true); } $structure = $headers->bodystructure; if (empty($structure)) { return $headers; } // set message charset from message headers if ($headers->charset) { $this->struct_charset = $headers->charset; } else { $this->struct_charset = $this->structure_charset($structure); } $headers->ctype = @strtolower($headers->ctype); // Here we can recognize malformed BODYSTRUCTURE and // 1. [@TODO] parse the message in other way to create our own message structure // 2. or just show the raw message body. // Example of structure for malformed MIME message: // ("text" "plain" NIL NIL NIL "7bit" 2154 70 NIL NIL NIL) if ($headers->ctype && !is_array($structure[0]) && $headers->ctype != 'text/plain' && strtolower($structure[0] . '/' . $structure[1]) == 'text/plain') { // A special known case "Content-type: text" (#1488968) if ($headers->ctype == 'text') { $structure[1] = 'plain'; $headers->ctype = 'text/plain'; } else { if (preg_match('/^(text|application)\\/(.*)/', $headers->ctype, $m)) { $structure[0] = $m[1]; $structure[1] = $m[2]; } else { // Try to parse the message using rcube_mime_decode. // We need a better solution, it parses message // in memory, which wouldn't work for very big messages, // (it uses up to 10x more memory than the message size) // it's also buggy and not actively developed if ($headers->size && rcube_utils::mem_check($headers->size * 10)) { $raw_msg = $this->get_raw_body($uid); $struct = rcube_mime::parse_message($raw_msg); } else { return $headers; } } } } if (empty($struct)) { $struct = $this->structure_part($structure, 0, '', $headers); } // some workarounds on simple messages... if (empty($struct->parts)) { // ...don't trust given content-type if (!empty($headers->ctype)) { $struct->mime_id = '1'; $struct->mimetype = strtolower($headers->ctype); list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype); } // ...and charset (there's a case described in #1488968 where invalid content-type // results in invalid charset in BODYSTRUCTURE) if (!empty($headers->charset) && $headers->charset != $struct->ctype_parameters['charset']) { $struct->charset = $headers->charset; $struct->ctype_parameters['charset'] = $headers->charset; } } $headers->structure = $struct; return $this->icache['message'] = $headers; }
/** * Parse decrypted message body into structure * * @param string Message body * * @return array Message structure */ private function parse_body(&$body) { // Mail_mimeDecode need \r\n end-line, but gpg may return \n $body = preg_replace('/\\r?\\n/', "\r\n", $body); // parse the body into structure $struct = rcube_mime::parse_message($body); return $struct; }
/** * Get attachment body * @see calendar_driver::get_attachment_body() */ public function get_attachment_body($id, $event) { if (!($cal = $this->get_calendar($event['calendar']))) { return false; } // get old revision of event if ($event['rev']) { if (empty($this->bonnie_api)) { return false; } $cid = substr($id, 4); // call Bonnie API and get the raw mime message list($uid, $mailbox, $msguid) = $this->_resolve_event_identity($event); if ($msg_raw = $this->bonnie_api->rawdata('event', $uid, $event['rev'], $mailbox, $msguid)) { // parse the message and find the part with the matching content-id $message = rcube_mime::parse_message($msg_raw); foreach ((array) $message->parts as $part) { if ($part->headers['content-id'] && trim($part->headers['content-id'], '<>') == $cid) { return $part->body; } } } return false; } return $cal->get_attachment_body($id, $event); }
/** * Fetch message headers and body structure from the IMAP server and build * an object structure similar to the one generated by PEAR::Mail_mimeDecode * * @param int $uid Message UID to fetch * @param string $folder Folder to read from * * @return object rcube_message_header Message data */ public function get_message($uid, $folder = null) { if (!strlen($folder)) { $folder = $this->folder; } // Check internal cache if (!empty($this->icache['message'])) { if (($headers = $this->icache['message']) && $headers->uid == $uid) { return $headers; } } $headers = $this->get_message_headers($uid, $folder); // message doesn't exist? if (empty($headers)) { return null; } // structure might be cached if (!empty($headers->structure)) { return $headers; } $this->msg_uid = $uid; if (!$this->check_connection()) { return $headers; } if (empty($headers->bodystructure)) { $headers->bodystructure = $this->conn->getStructure($folder, $uid, true); } $structure = $headers->bodystructure; if (empty($structure)) { return $headers; } // set message charset from message headers if ($headers->charset) { $this->struct_charset = $headers->charset; } else { $this->struct_charset = $this->structure_charset($structure); } $headers->ctype = strtolower($headers->ctype); // Here we can recognize malformed BODYSTRUCTURE and // 1. [@TODO] parse the message in other way to create our own message structure // 2. or just show the raw message body. // Example of structure for malformed MIME message: // ("text" "plain" NIL NIL NIL "7bit" 2154 70 NIL NIL NIL) if ($headers->ctype && !is_array($structure[0]) && $headers->ctype != 'text/plain' && strtolower($structure[0] . '/' . $structure[1]) == 'text/plain') { // we can handle single-part messages, by simple fix in structure (#1486898) if (preg_match('/^(text|application)\\/(.*)/', $headers->ctype, $m)) { $structure[0] = $m[1]; $structure[1] = $m[2]; } else { // Try to parse the message using Mail_mimeDecode package // We need a better solution, Mail_mimeDecode parses message // in memory, which wouldn't work for very big messages, // (it uses up to 10x more memory than the message size) // it's also buggy and not actively developed if ($headers->size && rcube_utils::mem_check($headers->size * 10)) { $raw_msg = $this->get_raw_body($uid); $struct = rcube_mime::parse_message($raw_msg); } else { return $headers; } } } if (empty($struct)) { $struct = $this->structure_part($structure, 0, '', $headers); } // don't trust given content-type if (empty($struct->parts) && !empty($headers->ctype)) { $struct->mime_id = '1'; $struct->mimetype = strtolower($headers->ctype); list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype); } $headers->structure = $struct; return $this->icache['message'] = $headers; }