/** * Get content of a specific part of this message * * @param string $mime_id Part ID * @param boolean $formatted Enables formatting of text/* parts bodies * @param int $max_bytes Only return/read this number of bytes * @param mixed $mode NULL to return a string, -1 to print body * or file pointer to save the body into * * @return string|bool Part content or operation status */ public function get_part_body($mime_id, $formatted = false, $max_bytes = 0, $mode = null) { if (!($part = $this->mime_parts[$mime_id])) { return; } // allow plugins to modify part body $plugin = $this->app->plugins->exec_hook('message_part_body', array('object' => $this, 'part' => $part)); // only text parts can be formatted $formatted = $formatted && $part->ctype_primary == 'text'; // part body not fetched yet... save in memory if it's small enough if ($part->body === null && is_numeric($mime_id) && $part->size < self::BODY_MAX_SIZE) { $this->storage->set_folder($this->folder); // Warning: body here should be always unformatted $part->body = $this->storage->get_message_part($this->uid, $mime_id, $part, null, null, true, 0, false); } // body stored in message structure (winmail/inline-uuencode) if ($part->body !== null || $part->encoding == 'stream') { $body = $part->body; if ($formatted && $body) { $body = self::format_part_body($body, $part, $this->headers->charset); } if ($max_bytes && strlen($body) > $max_bytes) { $body = substr($body, 0, $max_bytes); } if (is_resource($mode)) { if ($body !== false) { fwrite($mode, $body); rewind($mode); } return $body !== false; } if ($mode === -1) { if ($body !== false) { print $body; } return $body !== false; } return $body; } // get the body from IMAP $this->storage->set_folder($this->folder); $body = $this->storage->get_message_part($this->uid, $mime_id, $part, $mode === -1, is_resource($mode) ? $mode : null, !($mode && $formatted), $max_bytes, $mode && $formatted); if (is_resource($mode)) { rewind($mode); return $body !== false; } if (!$mode && $body && $formatted) { $body = self::format_part_body($body, $part, $this->headers->charset); } return $body; }
/** * Parse message body for UUencoded attachments bodies * * @param rcube_message_part $part Message part to decode * @return array */ function uu_decode(&$part) { // @TODO: messages may be huge, hadle body via file if (!isset($part->body)) { $this->storage->set_folder($this->folder); $part->body = $this->storage->get_message_part($this->uid, $part->mime_id, $part); } $parts = array(); // uuencode regexp $uu_regexp = '/^(begin [0-7]{3,4} ([^\\n]+)\\n)(([\\x21-\\x60]{0,65}\\n){0,2})([\\x21-\\x60]{0,65}|`\\nend)\\s*\\n/sm'; if (preg_match_all($uu_regexp, $part->body, $matches, PREG_SET_ORDER)) { $uu_endstring = "`\nend\n"; // add attachments to the structure foreach ($matches as $pid => $att) { // make sure we're looking at a uuencoded file, and not a false positive $uu_lines = explode("\n", $att[3]); foreach ($uu_lines as $uu_line) { if (strlen($uu_line) == 0) { continue; } $line_len = ord(substr($uu_line, 0, 1)) - 32 & 0x3f; $max_code_len = floor(($line_len + 2) / 3) * 4; $min_code_len = ceil($line_len / 3 * 4); if (strlen($uu_line) - 1 < $min_code_len or strlen($uu_line) - 1 > $max_code_len) { // illegal uuencode, break out of 'foreach $matches' loop break 2; } } $startpos = strpos($part->body, $att[0]) + strlen($att[1]); $endpos = strpos($part->body, $uu_endstring); $filebody = substr($part->body, $startpos, $endpos - $startpos); // remove attachments bodies from the message body $uu_startpos = $startpos - strlen($att[1]); $part->body = substr_replace($part->body, "", $uu_startpos, $endpos + strlen($uu_endstring) - $uu_startpos); $uupart = new rcube_message_part(); $uupart->filename = trim($att[2]); $uupart->encoding = 'stream'; $uupart->body = convert_uudecode($filebody); $uupart->size = strlen($uupart->body); $uupart->mime_id = 'uu.' . $part->mime_id . '.' . $pid; $ctype = rcube_mime::file_content_type($uupart->body, $uupart->filename, 'application/octet-stream', true); $uupart->mimetype = $ctype; list($uupart->ctype_primary, $uupart->ctype_secondary) = explode('/', $ctype); $parts[] = $uupart; unset($matches[$pid]); } // mark body as modified so it will not be cached by rcube_imap_cache $part->body_modified = true; } return $parts; }
/** * Parse message body for UUencoded attachments bodies * * @param rcube_message_part $part Message part to decode * @return array */ function uu_decode(&$part) { // @TODO: messages may be huge, hadle body via file if (!isset($part->body)) { $this->storage->set_folder($this->folder); $part->body = $this->storage->get_message_part($this->uid, $part->mime_id, $part); } $parts = array(); // FIXME: line length is max.65? $uu_regexp = '/begin [0-7]{3,4} ([^\\n]+)\\n/s'; if (preg_match_all($uu_regexp, $part->body, $matches, PREG_SET_ORDER)) { // update message content-type $part->ctype_primary = 'multipart'; $part->ctype_secondary = 'mixed'; $part->mimetype = $part->ctype_primary . '/' . $part->ctype_secondary; $uu_endstring = "`\nend\n"; // add attachments to the structure foreach ($matches as $pid => $att) { $startpos = strpos($part->body, $att[1]) + strlen($att[1]) + 1; // "\n" $endpos = strpos($part->body, $uu_endstring); $filebody = substr($part->body, $startpos, $endpos - $startpos); // remove attachments bodies from the message body $part->body = substr_replace($part->body, "", $startpos, $endpos + strlen($uu_endstring) - $startpos); $uupart = new rcube_message_part(); $uupart->filename = trim($att[1]); $uupart->encoding = 'stream'; $uupart->body = convert_uudecode($filebody); $uupart->size = strlen($uupart->body); $uupart->mime_id = 'uu.' . $part->mime_id . '.' . $pid; $ctype = rcube_mime::content_type($uupart->body, $uupart->filename, 'application/octet-stream', true); $uupart->mimetype = $ctype; list($uupart->ctype_primary, $uupart->ctype_secondary) = explode('/', $ctype); $parts[] = $uupart; unset($matches[$pid]); } // remove attachments bodies from the message body $part->body = preg_replace($uu_regexp, '', $part->body); } return $parts; }