public function toString($options = array())
{
$eol = $this->getEOL();
$isbase = true;
$oldbaseptr = null;
$parts = $parts_close = array();
if (isset($options['id'])) {
$id = $options['id'];
if (!($part = $this[$id])) {
return $part;
}
unset($options['id']);
$contents = $part->toString($options);
$prev_id = Horde_Mime::mimeIdArithmetic($id, 'up', array('norfc822' => true));
$prev_part = $prev_id == $this->getMimeId() ? $this : $this[$prev_id];
if (!$prev_part) {
return $contents;
}
$boundary = trim($this->getContentTypeParameter('boundary'), '"');
$parts = array($eol . '--' . $boundary . $eol, $contents);
if (!isset($this[Horde_Mime::mimeIdArithmetic($id, 'next')])) {
$parts[] = $eol . '--' . $boundary . '--' . $eol;
}
} else {
if ($isbase = empty($options['_notbase'])) {
$headers = !empty($options['headers']) ? $options['headers'] : false;
if (empty($options['encode'])) {
$options['encode'] = null;
}
if (empty($options['defserver'])) {
$options['defserver'] = null;
}
$options['headers'] = true;
$options['_notbase'] = true;
} else {
$headers = true;
$oldbaseptr =& $options['_baseptr'];
}
$this->_temp['toString'] = '';
$options['_baseptr'] =& $this->_temp['toString'];
/* Any information about a message is embedded in the message
* contents themself. Simply output the contents of the part
* directly and return. */
$ptype = $this->getPrimaryType();
if ($ptype == 'message') {
$parts[] = $this->_contents;
} else {
if (!empty($this->_contents)) {
$encoding = $this->_getTransferEncoding($options['encode']);
switch ($encoding) {
case '8bit':
if (empty($options['_baseptr'])) {
$options['_baseptr'] = '8bit';
}
break;
case 'binary':
$options['_baseptr'] = 'binary';
break;
}
$parts[] = $this->_transferEncode($this->_contents, $encoding);
/* If not using $this->_contents, we can close the stream
* when finished. */
if ($this->_temp['transferEncodeClose']) {
$parts_close[] = end($parts);
}
}
/* Deal with multipart messages. */
if ($ptype == 'multipart') {
if (empty($this->_contents)) {
$parts[] = 'This message is in MIME format.' . $eol;
}
$boundary = trim($this->getContentTypeParameter('boundary'), '"');
/* If base part is multipart/digest, children should not
* have content-type (automatically treated as
* message/rfc822; RFC 2046 [5.1.5]). */
if ($this->getSubType() === 'digest') {
$options['is_digest'] = true;
}
foreach ($this as $part) {
$parts[] = $eol . '--' . $boundary . $eol;
$tmp = $part->toString($options);
if ($part->getEOL() != $eol) {
$tmp = $this->replaceEOL($tmp, $eol, !empty($options['stream']));
}
if (!empty($options['stream'])) {
$parts_close[] = $tmp;
}
$parts[] = $tmp;
}
$parts[] = $eol . '--' . $boundary . '--' . $eol;
}
}
if (is_string($headers)) {
array_unshift($parts, $headers);
} elseif ($headers) {
$hdr_ob = $this->addMimeHeaders(array('encode' => $options['encode'], 'headers' => $headers === true ? null : $headers));
if (!$isbase && !empty($options['is_digest'])) {
unset($hdr_ob['content-type']);
}
if (!empty($this->_temp['toString'])) {
$hdr_ob->addHeader('Content-Transfer-Encoding', $this->_temp['toString']);
}
array_unshift($parts, $hdr_ob->toString(array('canonical' => $eol == self::RFC_EOL, 'charset' => $this->getHeaderCharset(), 'defserver' => $options['defserver'])));
}
}
$newfp = $this->_writeStream($parts);
array_map('fclose', $parts_close);
if (!is_null($oldbaseptr)) {
switch ($this->_temp['toString']) {
case '8bit':
if (empty($oldbaseptr)) {
$oldbaseptr = '8bit';
}
break;
case 'binary':
$oldbaseptr = 'binary';
break;
}
}
if ($isbase && !empty($options['canonical'])) {
return $this->replaceEOL($newfp, self::RFC_EOL, !empty($options['stream']));
}
return empty($options['stream']) ? $this->_readStream($newfp) : $newfp;
}