/** * Constructor. * * @param mixed $rfc822 The incoming message. Either a string * or a stream resource. * @param boolean $auto_add_headers Automatically add the standard * Message-ID and User-Agent headers? * @since 2.14.0 */ public function __construct($rfc822, $auto_add_headers = true) { if (is_resource($rfc822)) { $stream = new Horde_Stream_Existing(array('stream' => $rfc822)); $stream->rewind(); } else { $stream = new Horde_Stream_Temp(array('max_memory' => self::$memoryLimit)); $stream->add($rfc822, true); } $this->_parseStream($stream); if ($auto_add_headers) { $this->addStandardHeaders(); } }
/** */ protected function _read() { try { if (method_exists($this->_vfs, 'readStream')) { $stream = new Horde_Stream_Existing(array('stream' => $this->_vfs->readStream($this->_vfspath, $this->_id))); $stream->rewind(); } else { $stream = new Horde_Stream_Temp(); $stream->add($this->_vfs->read($this->_vfspath, $this->_id), true); } return $stream; } catch (Horde_Vfs_Exception $e) { throw new IMP_Compose_Exception($e); } }
/** */ protected function _get($keys) { if (!$this->_stream) { return parent::_get($keys); } $out = array(); foreach ($keys as $key) { try { if (method_exists($this->_vfs, 'readStream')) { $data = new Horde_Stream_Existing(array('stream' => $this->_vfs->readStream($this->_params['vfspath'], $key))); $data->rewind(); } else { $data = new Horde_Stream_Temp(); $data->add($this->_vfs->read($this->_params['vfspath'], $key), true); } } catch (Horde_Vfs_Exception $e) { $data = false; } $out[$key] = $data; } return $out; }
/** * Replace the MIME part of the message sent from the client. Headers from * the original message are always used. * * @param Horde_Mime_Part $part The new MIME part. * @since 2.19.0 */ public function replaceMime(Horde_Mime_Part $part) { $mime_stream = $part->toString(array('stream' => true, 'headers' => false)); $mime_stream = new Horde_Stream_Existing(array('stream' => $mime_stream)); // Since we are still using the headers sent from the device, we can // simply zero out the position members etc... $this->_hdr_pos = 0; $this->_stream = $mime_stream; $mime_stream->rewind(); }
/** * Creates a new file in the directory * * @param string $name Name of the file * @param resource|string $data Initial payload * @return null|string */ public function createFile($name, $data = null) { list($app) = explode('/', $this->_path); if (is_resource($data)) { $content = new Horde_Stream_Existing(array('stream' => $data)); $type = Horde_Mime_Magic::analyzeData($content->getString(0, 100), $this->_mimedb); } else { $content = $data; $type = Horde_Mime_Magic::analyzeData($content, $this->_mimedb); } if (!$type) { $type = Horde_Mime_Magic::filenameToMime($name); } try { $this->_registry->callByPackage($app, 'put', array($this->_path . '/' . $name, $content, $type)); } catch (Horde_Exception $e) { throw new DAV\Exception($e->getMessage(), $e->getCode(), $e); } }
/** * Return the full message text. * * @param boolean $stream Return data as a stream? * * @return mixed A string or stream resource. * @throws Horde_ActiveSync_Exception */ public function getFullMsg($stream = false) { // First see if we already have it. if ($stream) { $full = new Horde_Stream_Existing(array('stream' => $this->_data->getFullMsg($stream))); $length = $full->length(); if (!$length) { $full->close(); } } else { $full = $this->_data->getFullMsg(false); $length = strlen($full); } if (!$length) { $query = new Horde_Imap_Client_Fetch_Query(); $query->fullText(array('peek' => true)); try { $fetch_ret = $this->_imap->fetch($this->_mbox, $query, array('ids' => new Horde_Imap_Client_Ids(array($this->uid)))); } catch (Horde_Imap_Exception $e) { throw new Horde_ActiveSync_Exception($e); } $data = $fetch_ret[$this->uid]; $full = $data->getFullMsg($stream); } return $full; }
/** * Encodes the contents of the part as necessary for transport. * * @param resource $fp A stream containing the data to encode. * @param string $encoding The encoding to use. * * @return resource A new file resource with the encoded data. */ protected function _transferEncode($fp, $encoding) { $this->_temp['transferEncodeClose'] = true; switch ($encoding) { case 'base64': /* Base64 Encoding: See RFC 2045, section 6.8 */ return $this->_writeStream($fp, array('filter' => array('convert.base64-encode' => array('line-break-chars' => $this->getEOL(), 'line-length' => 76)))); case 'quoted-printable': // PHP Bug 65776 - Must normalize the EOL characters. stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); $stream = new Horde_Stream_Existing(array('stream' => $fp)); $stream->stream = $this->_writeStream($stream->stream, array('filter' => array('horde_eol' => array('eol' => $stream->getEOL())))); /* Quoted-Printable Encoding: See RFC 2045, section 6.7 */ return $this->_writeStream($fp, array('filter' => array('convert.quoted-printable-encode' => array_filter(array('line-break-chars' => $stream->getEOL(), 'line-length' => 76))))); default: $this->_temp['transferEncodeClose'] = false; return $fp; } }
/** * Encodes the contents of the part as necessary for transport. * * @param resource $fp A stream containing the data to encode. * @param string $encoding The encoding to use. * * @return resource A new file resource with the encoded data. */ protected function _transferEncode($fp, $encoding) { $this->_temp['transferEncodeClose'] = true; switch ($encoding) { case 'base64': /* Base64 Encoding: See RFC 2045, section 6.8 */ return $this->_writeStream($fp, array('filter' => array('convert.base64-encode' => array('line-break-chars' => $this->getEOL(), 'line-length' => 76)))); case 'quoted-printable': $stream = new Horde_Stream_Existing(array('stream' => $fp)); /* Quoted-Printable Encoding: See RFC 2045, section 6.7 */ return $this->_writeStream($fp, array('filter' => array('convert.quoted-printable-encode' => array_filter(array('line-break-chars' => $stream->getEOL(), 'line-length' => 76))))); default: $this->_temp['transferEncodeClose'] = false; return $fp; } }
/** * * @param mixed $path Filename -or- an open PHP stream. * * @return array */ protected function _readData($path) { if (is_resource($path)) { $in = new Horde_Stream_Existing(array('stream' => $path)); $in->rewind(); } else { $in = new Horde_Stream_Existing(array('stream' => @fopen($path, 'rb'))); } $globalOffset = 0; $result = array('Errors' => 0); // if the path was invalid, this error will catch it if (!$in) { $result['Errors'] = 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("The file could not be opened."); return $result; } // First 2 bytes of JPEG are 0xFFD8 $data = bin2hex($in->substring(0, 2)); if ($data == 'ffd8') { $result['ValidJpeg'] = 1; } else { $result['ValidJpeg'] = 0; if (!is_resource($path)) { $in->close(); } return $result; } $result['ValidIPTCData'] = 0; $result['ValidJFIFData'] = 0; $result['ValidEXIFData'] = 0; $result['ValidAPP2Data'] = 0; $result['ValidCOMData'] = 0; // Next 2 bytes are marker tag (0xFFE#) $data = bin2hex($in->substring(0, 2)); $size = bin2hex($in->substring(0, 2)); // Loop through markers till you get to FFE1 (Exif marker) while (!$in->eof() && $data != 'ffe1' && $data != 'ffc0' && $data != 'ffd9') { switch ($data) { case 'ffe0': // JFIF Marker $result['ValidJFIFData'] = 1; $result['JFIF']['Size'] = hexdec($size); if (hexdec($size) - 2 > 0) { $data = $in->substring(0, hexdec($size) - 2); $result['JFIF']['Data'] = $data; } $result['JFIF']['Identifier'] = substr($data, 0, 5); $result['JFIF']['ExtensionCode'] = bin2hex(substr($data, 6, 1)); $globalOffset += hexdec($size) + 2; break; case 'ffed': // IPTC Marker $result['ValidIPTCData'] = 1; $result['IPTC']['Size'] = hexdec($size); if (hexdec($size) - 2 > 0) { $data = $in->substring(0, hexdec($size) - 2); $result['IPTC']['Data'] = $data; } $globalOffset += hexdec($size) + 2; break; case 'ffe2': // EXIF extension Marker $result['ValidAPP2Data'] = 1; $result['APP2']['Size'] = hexdec($size); if (hexdec($size) - 2 > 0) { $data = $in->substring(0, hexdec($size) - 2); $result['APP2']['Data'] = $data; } $globalOffset += hexdec($size) + 2; break; case 'fffe': // COM extension Marker $result['ValidCOMData'] = 1; $result['COM']['Size'] = hexdec($size); if (hexdec($size) - 2 > 0) { $data = $in->substring(0, hexdec($size) - 2); $result['COM']['Data'] = $data; } $globalOffset += hexdec($size) + 2; break; case 'ffe1': $result['ValidEXIFData'] = 1; break; } $data = bin2hex($in->substring(0, 2)); $size = bin2hex($in->substring(0, 2)); } if ($data != 'ffe1') { if (!is_resource($path)) { $in->close(); } return $result; } $result['ValidEXIFData'] = 1; // Size of APP1 $result['APP1Size'] = hexdec($size); // Start of APP1 block starts with 'Exif' header (6 bytes) $header = $in->substring(0, 6); // Then theres a TIFF header with 2 bytes of endieness (II or MM) $header = $in->substring(0, 2); switch ($header) { case 'II': $intel = 1; $result['Endien'] = 'Intel'; break; case 'MM': $intel = 0; $result['Endien'] = 'Motorola'; break; default: // not sure what the default should be, but this seems reasonable $intel = 1; $result['Endien'] = 'Unknown'; break; } // 2 bytes of 0x002a if (bin2hex($in->substring(0, 2)) != '002a') { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = 'Unexpected value.'; return $result; } // Then 4 bytes of offset to IFD0 (usually 8 which includes all 8 bytes // of TIFF header) $offset = bin2hex($in->substring(0, 4)); if ($intel == 1) { $offset = Horde_Image_Exif::intel2Moto($offset); } // Check for extremely large values here if (hexdec($offset) > 100000) { $result['ValidEXIFData'] = 0; if (!is_resource($path)) { $in->close(); } return $result; } if (hexdec($offset) > 8) { $unknown = $in->substring(0, hexdec($offset) - 8); } // add 12 to the offset to account for TIFF header $globalOffset += 12; //=========================================================== // Start of IFD0 $num = bin2hex($in->substring(0, 2)); if ($intel == 1) { $num = Horde_Image_Exif::intel2Moto($num); } $num = hexdec($num); $result['IFD0NumTags'] = $num; // 1000 entries is too much and is probably an error. if ($num < 1000) { for ($i = 0; $i < $num; $i++) { $this->_readEntry($result, $in, $intel, 'IFD0', $globalOffset); } } else { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = 'Illegal size for IFD0'; } // store offset to IFD1 $offset = bin2hex($in->substring(0, 4)); if ($intel == 1) { $offset = Horde_Image_Exif::intel2Moto($offset); } $result['IFD1Offset'] = hexdec($offset); // Check for SubIFD if (!isset($result['IFD0']['ExifOffset']) || $result['IFD0']['ExifOffset'] == 0) { if (!is_resource($path)) { $in->close(); } return $result; } // seek to SubIFD (Value of ExifOffset tag) above. $ExifOffset = $result['IFD0']['ExifOffset']; if (!$in->seek($globalOffset + $ExifOffset, false)) { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find SubIFD"); } //=========================================================== // Start of SubIFD $num = bin2hex($in->substring(0, 2)); if ($intel == 1) { $num = Horde_Image_Exif::intel2Moto($num); } $num = hexdec($num); $result['SubIFDNumTags'] = $num; // 1000 entries is too much and is probably an error. if ($num < 1000) { for ($i = 0; $i < $num; $i++) { $this->_readEntry($result, $in, $intel, 'SubIFD', $globalOffset); } } else { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for SubIFD"); } // Add the 35mm equivalent focal length: // Now properly get this using the FocalLength35mmFilm tag //$result['SubIFD']['FocalLength35mmEquiv'] = get35mmEquivFocalLength($result); // Check for IFD1 if (!isset($result['IFD1Offset']) || $result['IFD1Offset'] == 0) { if (!is_resource($path)) { $in->close(); } return $result; } // seek to IFD1 if (!$in->seek($globalOffset + $result['IFD1Offset'], false)) { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find IFD1"); } //=========================================================== // Start of IFD1 $num = bin2hex($in->substring(0, 2)); if ($intel == 1) { $num = Horde_Image_Exif::intel2Moto($num); } $num = hexdec($num); $result['IFD1NumTags'] = $num; // 1000 entries is too much and is probably an error. if ($num < 1000) { for ($i = 0; $i < $num; $i++) { $this->_readEntry($result, $in, $intel, 'IFD1', $globalOffset); } } else { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for IFD1"); } // include the thumbnail raw data... if ($result['IFD1']['JpegIFOffset'] > 0 && $result['IFD1']['JpegIFByteCount'] > 0) { $cpos = $in->pos(); if ($in->seek($globalOffset + $result['IFD1']['JpegIFOffset'], false)) { $data = $in->substring(0, $result['IFD1']['JpegIFByteCount']); } else { $result['Errors'] = $result['Errors'] + 1; } $result['IFD1']['ThumbnailData'] = $data; } // Check for Interoperability IFD if (!isset($result['SubIFD']['ExifInteroperabilityOffset']) || $result['SubIFD']['ExifInteroperabilityOffset'] == 0) { if (!is_resource($path)) { $in->close(); } return $result; } // Seek to InteroperabilityIFD if (!$in->seek($globalOffset + $result['SubIFD']['ExifInteroperabilityOffset'], false)) { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find InteroperabilityIFD"); } //=========================================================== // Start of InteroperabilityIFD $num = bin2hex($in->substring(0, 2)); if ($intel == 1) { $num = Horde_Image_Exif::intel2Moto($num); } $num = hexdec($num); $result['InteroperabilityIFDNumTags'] = $num; // 1000 entries is too much and is probably an error. if ($num < 1000) { for ($i = 0; $i < $num; $i++) { $this->_readEntry($result, $in, $intel, 'InteroperabilityIFD', $globalOffset); } } else { $result['Errors'] = $result['Errors'] + 1; $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for InteroperabilityIFD"); } if (!is_resource($path)) { $in->close(); } return $result; }