Skip to content

Commit 5ac0f0b

Browse files
committed
Merge pull request #1 from bakicdj/master
Make it work with self hosted [wip]
2 parents 57a532c + b0c4aa7 commit 5ac0f0b

File tree

6 files changed

+223
-42
lines changed

6 files changed

+223
-42
lines changed

src/ActiveCollab/EmailReplyExtractor.php

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,67 @@ final class EmailReplyExtractor
1111
const APPLE_MAIL = 'AppleMail';
1212
const GENERIC = 'Generic';
1313
const GOOGLE_MAIL = 'GoogleMail';
14+
const ANDROID_MAIL = 'AndroidMail';
1415
const HOTMAIL = 'Hotmail';
1516
const HUSHMAIL = 'Hushmail';
1617
const IOS = 'iOS';
1718
const OUTLOOK = 'Outlook';
1819
const YAHOO = 'Yahoo';
20+
const APPLE_CLOUD_MAIL = 'AppleCloudMail';
1921

2022
/**
2123
* Parse input file and return reply
2224
*
2325
* @param string $path
2426
* @return string
2527
*/
26-
public static function extractReply($path)
28+
public static function extractReplyEml($path)
2729
{
2830
$parser = new Parser();
2931
$parser->setPath($path);
3032

31-
$extractor = self::getExtractor(self::detectMailer(self::getHeadersRelevantForMailerDetection($parser)), $parser);
33+
$extractor = self::getExtractorEml(self::detectMailer(self::getHeadersRelevantForMailerDetectionEml($parser)), $parser);
3234

33-
return (string) $extractor;
35+
return (string) $extractor->body;
36+
}
37+
38+
/**
39+
* Parse input file and return reply
40+
*
41+
* @param array $headers
42+
* @param string $body
43+
* @return array
44+
*/
45+
public static function extractReply($headers, $body)
46+
{
47+
$mailer = self::detectMailer(self::getHeadersRelevantForMailerDetection($headers));
48+
$extractor = self::getExtractor($mailer, $body);
49+
50+
return [$extractor->body,$mailer];
3451
}
3552

3653
/**
3754
* @param string $mailer
3855
* @param Parser $parser
3956
* @return Extractor
4057
*/
41-
private function getExtractor($mailer, Parser &$parser)
58+
private function getExtractorEml($mailer, Parser &$parser)
59+
{
60+
$class_name = "ActiveCollab\\EmailReplyExtractor\\Extractor\\{$mailer}Extractor";
61+
62+
return new $class_name(null, $parser);
63+
}
64+
65+
/**
66+
* @param string $mailer
67+
* @param string $body
68+
* @return Extractor
69+
*/
70+
private function getExtractor($mailer, $body)
4271
{
4372
$class_name = "ActiveCollab\\EmailReplyExtractor\\Extractor\\{$mailer}Extractor";
4473

45-
return new $class_name($parser);
74+
return new $class_name($body);
4675
}
4776

4877
/**
@@ -64,42 +93,54 @@ public static function detectMailer(array $headers)
6493
return self::APPLE_MAIL;
6594
}
6695
} else if (isset($headers['message-id'])) {
67-
if (strpos($headers['message-id'], '@email.android.com') !== false || strpos($headers['message-id'], '@mail.gmail.com') !== false) {
96+
97+
if (strpos($headers['message-id'], '@mail.gmail.com') !== false) {
6898
return self::GOOGLE_MAIL;
6999
} else if (strpos($headers['message-id'], '@smtp.hushmail.com')) {
70100
return self::HUSHMAIL;
71-
} else if (strpos($headers['message-id'], 'outlook.com')) {
101+
} else if (strpos($headers['message-id'], 'outlook.com') || strpos($headers['message-id'], 'phx.gbl')) {
72102
return self::OUTLOOK;
103+
} else if (strpos($headers['message-id'], 'yahoo.com')) {
104+
return self::YAHOO;
105+
} else if (strpos($headers['message-id'], 'me.com')) {
106+
return self::APPLE_CLOUD_MAIL;
107+
} else if (strpos($headers['message-id'], '@email.android.com') !== false) {
108+
return self::ANDROID_MAIL;
73109
}
74110
} else if (isset($headers['received']) && strpos($headers['received'], 'hotmail.com') !== false) {
75111
return self::HOTMAIL;
76112
} else if (isset($headers['mime-version']) && strpos($headers['mime-version'], 'Apple Message framework') !== false) {
77113
return self::APPLE_MAIL;
78114
}
79-
80115
return self::GENERIC;
81116
}
82117

83118
/**
84119
* @param Parser $parser
85120
* @return array
86121
*/
87-
private static function getHeadersRelevantForMailerDetection(Parser &$parser)
122+
private static function getHeadersRelevantForMailerDetectionEml(Parser &$parser)
88123
{
89-
$headers = [
124+
return self::filterHeaders([
90125
'x-mailer' => $parser->getHeader('x-mailer'),
91126
'message-id' => $parser->getHeader('message-id'),
92127
'Received' => $parser->getHeader('received'),
93128
'Mime-Version' => $parser->getHeader('mime-version'),
94-
];
95-
96-
foreach ($headers as $k => $v) {
97-
if (empty($v)) {
98-
unset($headers[$k]);
99-
}
100-
}
129+
]);
130+
}
101131

102-
return $headers;
132+
/**
133+
* @param array $headers
134+
* @return array
135+
*/
136+
private static function getHeadersRelevantForMailerDetection(array $headers)
137+
{
138+
return self::filterHeaders([
139+
'x-mailer' => $headers['x-mailer'],
140+
'message-id' => $headers['message_id'],
141+
'Received' => $headers['Received'],
142+
'Mime-Version' => $headers['Mime-Version'],
143+
]);
103144
}
104145

105146
/**
@@ -113,4 +154,22 @@ private static function getHeadersRelevantForMailerDetection(Parser &$parser)
113154
public static function strStartsWith($string, $niddle) {
114155
return substr($string, 0, strlen($niddle)) == $niddle;
115156
}
157+
158+
/**
159+
* Return only not empty headers
160+
*
161+
* @param $headers
162+
*
163+
* @return mixed
164+
*/
165+
private static function filterHeaders($headers)
166+
{
167+
foreach ($headers as $k => $v) {
168+
if (empty($v)) {
169+
unset($headers[$k]);
170+
}
171+
}
172+
173+
return $headers;
174+
}
116175
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
namespace ActiveCollab\EmailReplyExtractor\Extractor;
3+
4+
5+
final class AndroidMailExtractor extends Extractor
6+
{
7+
8+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
4+
namespace ActiveCollab\EmailReplyExtractor\Extractor;
5+
6+
7+
class AppleCloudMailExtractor extends Extractor
8+
{
9+
10+
/**
11+
* Find reply separator and remove lines that are after it
12+
*
13+
* @param array $splitters
14+
* @param integer $trim_previous_lines
15+
*/
16+
protected function stripOriginalMessage(array &$splitters, $trim_previous_lines = 0)
17+
{
18+
$stripped = [];
19+
20+
foreach ($this->body as $line) {
21+
if (strpos($line, '--Boundary_') !== false) {
22+
if ($trim_previous_lines == 0) {
23+
$this->body = $stripped;
24+
} else {
25+
$this->body = array_slice($stripped, 0, count($stripped) - $trim_previous_lines);
26+
}
27+
28+
$this->stripEmptyLinesFromTheEnd();
29+
return;
30+
}
31+
$stripped[] = $line;
32+
}
33+
}
34+
35+
/**
36+
* Extract Reply from Apple MAil mail
37+
*/
38+
protected function processLines()
39+
{
40+
$splitters = $this->getOriginalMessageSplitters();
41+
42+
if (!empty($splitters)) {
43+
$this->stripOriginalMessage($splitters);
44+
}
45+
46+
$this->body = implode("\n", $this->body);
47+
if (preg_match('/(.*)(On)(.*) at (.*) wrote\:(.*)/mis', $this->body, $matches, PREG_OFFSET_CAPTURE)) {
48+
$match_index = $matches[2][1];
49+
$this->body = trim(mb_substr($this->body, 0, $match_index));
50+
}
51+
$this->body = explode("\n", $this->body);
52+
53+
$unwanted_text_patterns = $this->getUnwantedTextPatterns();
54+
55+
if (!empty($unwanted_text_patterns)) {
56+
$this->stripUnwantedText($unwanted_text_patterns);
57+
}
58+
59+
$this->stripSignature();
60+
$this->convertPlainTextQuotesToBlockquotes();
61+
}
62+
}

src/ActiveCollab/EmailReplyExtractor/Extractor/Extractor.php

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,45 +14,32 @@ abstract class Extractor
1414
*/
1515
private $parser;
1616

17-
/**
18-
* @param Parser $parser
19-
*/
20-
public function __construct(Parser $parser)
17+
public function __construct($body = null, Parser $parser = null)
2118
{
2219
$this->parser = $parser;
2320

24-
if ($html = $this->parser->getMessageBody('html')) {
25-
$this->body = $this->toPlainText($html);
21+
if($parser instanceof Parser) {
22+
if ($html = $this->parser->getMessageBody('html')) {
23+
$this->body = $this->toPlainText($html);
24+
} else {
25+
$this->body = $this->getParser()->getMessageBody('text');
26+
}
2627
} else {
27-
$this->body = $this->getParser()->getMessageBody('text');
28+
$this->body = $this->toPlainText($body);
2829
}
2930

3031
$this->splitLines();
3132
$this->processLines();
3233
$this->joinLines();
3334
}
3435

35-
/**
36-
* @var string|string[]
37-
*/
38-
protected $body;
39-
40-
/**
41-
* @return string
42-
*/
43-
public function __toString()
44-
{
45-
return $this->body;
46-
}
47-
4836
/**
4937
* Prepare body text for processing
5038
*/
5139
protected function splitLines()
5240
{
53-
$this->body = explode("\n", str_replace([ "\n\r", "\r\n", "\r" ], [ "\n", "\n", "\n" ], $this->body));
41+
$this->body = explode("\n", str_replace(["\n\r", "\r\n", "\r"], ["\n", "\n", "\n"], $this->body));
5442
}
55-
5643
/**
5744
* Process body text
5845
*/
@@ -91,17 +78,38 @@ public function joinLines()
9178
protected function getOriginalMessageSplitters()
9279
{
9380
return [
81+
//'On Thursday, October 15, 2015 12:50 PM, owner (Active Collab) wrote:',
82+
'/On(.*?)wrote\:(.*?)/is',
83+
'- Reply above this line to leave a comment -',
9484
'-- REPLY ABOVE THIS LINE --',
9585
'-- REPLY ABOVE THIS LINE',
9686
'REPLY ABOVE THIS LINE --',
9787
'-- Reply above this line --',
9888
'-----Original Message-----',
9989
'----- Original Message -----',
10090
'-- ODGOVORI ODJE --',
101-
'-------- Original message --------'
91+
'-------- Original message --------',
10292
];
10393
}
10494

95+
/**
96+
* Chack if string is regular expression
97+
*
98+
* @param $str
99+
*
100+
* @return bool
101+
*/
102+
protected function isRegex($str)
103+
{
104+
try {
105+
preg_match($str, 'some str');
106+
} catch (\Exception $e) {
107+
return false;
108+
}
109+
110+
return true;
111+
}
112+
105113
/**
106114
* Find reply separator and remove lines that are after it
107115
*
@@ -113,7 +121,12 @@ protected function stripOriginalMessage(array &$splitters, $trim_previous_lines
113121

114122
foreach ($this->body as $line) {
115123
foreach ($splitters as $splitter) {
116-
if (mb_strpos($line, $splitter) !== false) {
124+
125+
if(!$this->isRegex($splitter)) {
126+
$splitter = '/'.$splitter.'/';
127+
}
128+
129+
if (preg_match($splitter, $line)) {
117130
if ($trim_previous_lines == 0) {
118131
$this->body = $stripped;
119132
} else {
@@ -126,6 +139,7 @@ protected function stripOriginalMessage(array &$splitters, $trim_previous_lines
126139
}
127140
$stripped[] = $line;
128141
}
142+
129143
}
130144

131145
/**

src/ActiveCollab/EmailReplyExtractor/Extractor/OutlookExtractor.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,29 @@
66
*/
77
final class OutlookExtractor extends Extractor
88
{
9+
/**
10+
* @param string $html
11+
*
12+
* @return string
13+
*/
14+
static function toPlainText($html)
15+
{
16+
$html = str_replace('div', 'p', $html);
17+
18+
return parent::toPlainText($html);
19+
}
20+
21+
/**
22+
* Return original message splitters
23+
*
24+
* @todo
25+
* @return array
26+
*/
27+
protected function getOriginalMessageSplitters()
28+
{
29+
return array_merge(parent::getOriginalMessageSplitters(), [
30+
'/\-------------------------/is',
31+
]);
32+
}
33+
934
}

0 commit comments

Comments
 (0)