Page MenuHomestyx hydra

No OneTemporary

diff --git a/externals/mimemailparser/MimeMailParser.class.php b/externals/mimemailparser/MimeMailParser.class.php
index 1447ffc4b8..3ce0ee49c7 100644
--- a/externals/mimemailparser/MimeMailParser.class.php
+++ b/externals/mimemailparser/MimeMailParser.class.php
@@ -1,439 +1,459 @@
<?php
require_once('attachment.class.php');
/**
* Fast Mime Mail parser Class using PHP's MailParse Extension
* @author gabe@fijiwebdesign.com
* @url http://www.fijiwebdesign.com/
* @license http://creativecommons.org/licenses/by-sa/3.0/us/
* @version $Id$
*/
class MimeMailParser {
-
+
/**
* PHP MimeParser Resource ID
*/
public $resource;
-
+
/**
* A file pointer to email
*/
public $stream;
-
+
/**
* A text of an email
*/
public $data;
-
+
/**
* Stream Resources for Attachments
*/
public $attachment_streams;
-
+
/**
* Inialize some stuff
- * @return
+ * @return
*/
public function __construct() {
$this->attachment_streams = array();
}
-
+
/**
* Free the held resouces
* @return void
*/
public function __destruct() {
// clear the email file resource
if (is_resource($this->stream)) {
fclose($this->stream);
}
// clear the MailParse resource
if (is_resource($this->resource)) {
mailparse_msg_free($this->resource);
}
// remove attachment resources
foreach($this->attachment_streams as $stream) {
fclose($stream);
}
}
-
+
/**
* Set the file path we use to get the email text
* @return Object MimeMailParser Instance
* @param $mail_path Object
*/
public function setPath($path) {
// should parse message incrementally from file
$this->resource = mailparse_msg_parse_file($path);
$this->stream = fopen($path, 'r');
$this->parse();
return $this;
}
-
+
/**
* Set the Stream resource we use to get the email text
* @return Object MimeMailParser Instance
* @param $stream Resource
*/
public function setStream($stream) {
// streams have to be cached to file first
if (get_resource_type($stream) == 'stream') {
$tmp_fp = tmpfile();
if ($tmp_fp) {
while(!feof($stream)) {
fwrite($tmp_fp, fread($stream, 2028));
}
fseek($tmp_fp, 0);
$this->stream =& $tmp_fp;
} else {
throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.');
return false;
}
fclose($stream);
} else {
$this->stream = $stream;
}
-
+
$this->resource = mailparse_msg_create();
// parses the message incrementally low memory usage but slower
while(!feof($this->stream)) {
mailparse_msg_parse($this->resource, fread($this->stream, 2082));
}
$this->parse();
return $this;
}
-
+
/**
* Set the email text
- * @return Object MimeMailParser Instance
+ * @return Object MimeMailParser Instance
* @param $data String
*/
public function setText($data) {
$this->resource = mailparse_msg_create();
// does not parse incrementally, fast memory hog might explode
mailparse_msg_parse($this->resource, $data);
$this->data = $data;
$this->parse();
return $this;
}
-
+
/**
* Parse the Message into parts
* @return void
* @private
*/
private function parse() {
$structure = mailparse_msg_get_structure($this->resource);
$this->parts = array();
foreach($structure as $part_id) {
$part = mailparse_msg_get_part($this->resource, $part_id);
$this->parts[$part_id] = mailparse_msg_get_part_data($part);
}
}
-
+
/**
* Retrieve the Email Headers
* @return Array
*/
public function getHeaders() {
if (isset($this->parts[1])) {
return $this->getPartHeaders($this->parts[1]);
} else {
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.');
}
return false;
}
/**
* Retrieve the raw Email Headers
* @return string
*/
public function getHeadersRaw() {
if (isset($this->parts[1])) {
return $this->getPartHeaderRaw($this->parts[1]);
} else {
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.');
}
return false;
}
-
+
/**
* Retrieve a specific Email Header
* @return String
* @param $name String Header name
*/
public function getHeader($name) {
if (isset($this->parts[1])) {
$headers = $this->getPartHeaders($this->parts[1]);
if (isset($headers[$name])) {
return $headers[$name];
}
} else {
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.');
}
return false;
}
-
+
/**
* Returns the email message body in the specified format
* @return Mixed String Body or False if not found
* @param $type Object[optional]
*/
public function getMessageBody($type = 'text') {
+
+ // NOTE: This function has been modified for Phabricator. The default
+ // implementation returns the last matching part, which throws away text
+ // for many emails. Instead, we concatenate all matching parts. See
+ // issue 22 for discussion:
+ // http://code.google.com/p/php-mime-mail-parser/issues/detail?id=22
+
$body = false;
$mime_types = array(
'text'=> 'text/plain',
'html'=> 'text/html'
);
if (in_array($type, array_keys($mime_types))) {
foreach($this->parts as $part) {
+ $disposition = $this->getPartContentDisposition($part);
+ if ($disposition == 'attachment') {
+ // text/plain parts with "Content-Disposition: attachment" are
+ // attachments, not part of the text body.
+ continue;
+ }
if ($this->getPartContentType($part) == $mime_types[$type]) {
- $headers = $this->getPartHeaders($part);
- $body = $this->decode($this->getPartBody($part), array_key_exists('content-transfer-encoding', $headers) ?
-$headers['content-transfer-encoding'] : '');
+ $headers = $this->getPartHeaders($part);
+ // Concatenate all the matching parts into the body text. For example,
+ // if a user sends a message with some text, then an image, and then
+ // some more text, the text body of the email gets split over several
+ // attachments.
+ $body .= $this->decode(
+ $this->getPartBody($part),
+ array_key_exists('content-transfer-encoding', $headers)
+ ? $headers['content-transfer-encoding']
+ : '');
}
}
} else {
throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.');
}
return $body;
}
/**
* get the headers for the message body part.
* @return Array
* @param $type Object[optional]
*/
public function getMessageBodyHeaders($type = 'text') {
$headers = false;
$mime_types = array(
'text'=> 'text/plain',
'html'=> 'text/html'
);
if (in_array($type, array_keys($mime_types))) {
foreach($this->parts as $part) {
if ($this->getPartContentType($part) == $mime_types[$type]) {
$headers = $this->getPartHeaders($part);
}
}
} else {
throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.');
}
return $headers;
}
-
+
/**
* Returns the attachments contents in order of appearance
* @return Array
* @param $type Object[optional]
*/
public function getAttachments() {
$attachments = array();
$dispositions = array("attachment","inline");
foreach($this->parts as $part) {
$disposition = $this->getPartContentDisposition($part);
if (in_array($disposition, $dispositions)) {
$attachments[] = new MimeMailParser_attachment(
- $part['disposition-filename'],
- $this->getPartContentType($part),
+ $part['disposition-filename'],
+ $this->getPartContentType($part),
$this->getAttachmentStream($part),
$disposition,
$this->getPartHeaders($part)
);
}
}
return $attachments;
}
-
+
/**
* Return the Headers for a MIME part
* @return Array
* @param $part Array
*/
private function getPartHeaders($part) {
if (isset($part['headers'])) {
return $part['headers'];
}
return false;
}
-
+
/**
* Return a Specific Header for a MIME part
* @return Array
* @param $part Array
* @param $header String Header Name
*/
private function getPartHeader($part, $header) {
if (isset($part['headers'][$header])) {
return $part['headers'][$header];
}
return false;
}
-
+
/**
* Return the ContentType of the MIME part
* @return String
* @param $part Array
*/
private function getPartContentType($part) {
if (isset($part['content-type'])) {
return $part['content-type'];
}
return false;
}
-
+
/**
* Return the Content Disposition
* @return String
* @param $part Array
*/
private function getPartContentDisposition($part) {
if (isset($part['content-disposition'])) {
return $part['content-disposition'];
}
return false;
}
-
+
/**
* Retrieve the raw Header of a MIME part
* @return String
* @param $part Object
*/
private function getPartHeaderRaw(&$part) {
$header = '';
if ($this->stream) {
$header = $this->getPartHeaderFromFile($part);
} else if ($this->data) {
$header = $this->getPartHeaderFromText($part);
} else {
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email parts.');
}
return $header;
}
/**
* Retrieve the Body of a MIME part
* @return String
* @param $part Object
*/
private function getPartBody(&$part) {
$body = '';
if ($this->stream) {
$body = $this->getPartBodyFromFile($part);
} else if ($this->data) {
$body = $this->getPartBodyFromText($part);
} else {
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email parts.');
}
return $body;
}
-
+
/**
* Retrieve the Header from a MIME part from file
* @return String Mime Header Part
* @param $part Array
*/
private function getPartHeaderFromFile(&$part) {
$start = $part['starting-pos'];
$end = $part['starting-pos-body'];
fseek($this->stream, $start, SEEK_SET);
$header = fread($this->stream, $end-$start);
return $header;
}
/**
* Retrieve the Body from a MIME part from file
* @return String Mime Body Part
* @param $part Array
*/
private function getPartBodyFromFile(&$part) {
$start = $part['starting-pos-body'];
$end = $part['ending-pos-body'];
fseek($this->stream, $start, SEEK_SET);
$body = fread($this->stream, $end-$start);
return $body;
}
-
+
/**
* Retrieve the Header from a MIME part from text
* @return String Mime Header Part
* @param $part Array
*/
private function getPartHeaderFromText(&$part) {
$start = $part['starting-pos'];
$end = $part['starting-pos-body'];
$header = substr($this->data, $start, $end-$start);
return $header;
}
/**
* Retrieve the Body from a MIME part from text
* @return String Mime Body Part
* @param $part Array
*/
private function getPartBodyFromText(&$part) {
$start = $part['starting-pos-body'];
$end = $part['ending-pos-body'];
$body = substr($this->data, $start, $end-$start);
return $body;
}
-
+
/**
* Read the attachment Body and save temporary file resource
* @return String Mime Body Part
* @param $part Array
*/
private function getAttachmentStream(&$part) {
- $temp_fp = tmpfile();
+ $temp_fp = tmpfile();
array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = '';
if ($temp_fp) {
if ($this->stream) {
$start = $part['starting-pos-body'];
$end = $part['ending-pos-body'];
fseek($this->stream, $start, SEEK_SET);
$len = $end-$start;
$written = 0;
$write = 2028;
$body = '';
while($written < $len) {
if (($written+$write < $len )) {
$write = $len - $written;
}
$part = fread($this->stream, $write);
fwrite($temp_fp, $this->decode($part, $encoding));
$written += $write;
}
} else if ($this->data) {
$attachment = $this->decode($this->getPartBodyFromText($part), $encoding);
fwrite($temp_fp, $attachment, strlen($attachment));
}
fseek($temp_fp, 0, SEEK_SET);
} else {
throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.');
return false;
}
return $temp_fp;
}
-
+
/**
* Decode the string depending on encoding type.
* @return String the decoded string.
* @param $encodedString The string in its original encoded state.
* @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part.
*/
private function decode($encodedString, $encodingType) {
if (strtolower($encodingType) == 'base64') {
return base64_decode($encodedString);
} else if (strtolower($encodingType) == 'quoted-printable') {
return quoted_printable_decode($encodedString);
} else {
return $encodedString;
}
}
}
?>
diff --git a/scripts/mail/mail_handler.php b/scripts/mail/mail_handler.php
index 6136ef6859..e3225f3623 100755
--- a/scripts/mail/mail_handler.php
+++ b/scripts/mail/mail_handler.php
@@ -1,58 +1,67 @@
#!/usr/bin/php
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
if ($argc > 1) {
$_SERVER['PHABRICATOR_ENV'] = $argv[1];
}
$root = dirname(dirname(dirname(__FILE__)));
require_once $root.'/scripts/__init_script__.php';
require_once $root.'/scripts/__init_env__.php';
require_once $root.'/externals/mimemailparser/MimeMailParser.class.php';
phutil_require_module(
'phabricator',
'applications/metamta/storage/receivedmail');
phutil_require_module(
'phabricator',
'applications/files/storage/file');
$parser = new MimeMailParser();
$parser->setText(file_get_contents('php://stdin'));
$received = new PhabricatorMetaMTAReceivedMail();
$received->setHeaders($parser->getHeaders());
$received->setBodies(array(
'text' => $parser->getMessageBody('text'),
'html' => $parser->getMessageBody('html'),
));
$attachments = array();
foreach ($parser->getAttachments() as $attachment) {
+ if (preg_match('@text/(plain|html)@', $attachment->getContentType()) &&
+ $attachment->getContentDisposition() == 'inline') {
+ // If this is an "inline" attachment with some sort of text content-type,
+ // do not treat it as a file for attachment. MimeMailParser already picked
+ // it up in the getMessageBody() call above. We still want to treat 'inline'
+ // attachments with other content types (e.g., images) as attachments.
+ continue;
+ }
+
$file = PhabricatorFile::newFromFileData(
$attachment->getContent(),
array(
'name' => $attachment->getFilename(),
));
$attachments[] = $file->getPHID();
}
$received->setAttachments($attachments);
$received->save();
$received->processReceivedMail();

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 29, 2:41 PM (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
188797
Default Alt Text
(15 KB)

Event Timeline