Skip to content

Commit 2d6a339

Browse files
committed
save dev
got totally drowned in zend/mail, zend/mime, and eventum bugs zendframework/zend-mime#26 zendframework/zend-mail#146
1 parent 7a80010 commit 2d6a339

File tree

4 files changed

+276
-3
lines changed

4 files changed

+276
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Eventum (Issue Tracking System) package.
5+
*
6+
* @copyright (c) Eventum Team
7+
* @license GNU General Public License, version 2 or later (GPL-2+)
8+
*
9+
* For the full copyright and license information,
10+
* please see the COPYING and AUTHORS files
11+
* that were distributed with this source code.
12+
*/
13+
14+
use Eventum\Db\AbstractMigration;
15+
use Eventum\Mail\MailMessage;
16+
use Zend\Mail\Headers;
17+
18+
class EventumFixSupFields extends AbstractMigration
19+
{
20+
/** @var string */
21+
private $email_table;
22+
/** @var string */
23+
private $body_table;
24+
25+
/**
26+
* This would be in init() but it's too early to use adapter.
27+
*
28+
* @see https://github.com/robmorgan/phinx/issues/1095
29+
*/
30+
public function initTables()
31+
{
32+
$this->email_table = $this->quoteColumnName('support_email');
33+
$this->body_table = $this->quoteColumnName('support_email_body');
34+
}
35+
36+
public function up()
37+
{
38+
$this->initTables();
39+
$this->fixTruncatedAddressFields('sup_cc', 'Cc');
40+
$this->fixTruncatedAddressFields('sup_to', 'To');
41+
throw new RuntimeException();
42+
}
43+
44+
public function fixTruncatedAddressFields($field, $header)
45+
{
46+
$st = $this->getTruncatedRecords($field);
47+
foreach ($st as $row) {
48+
$sup_id = $row['sup_id'];
49+
file_put_contents("/tmp/{$row['sup_id']}", $row['body']);
50+
$mail = MailMessage::createFromString($row['body']);
51+
$value = $this->unfold($mail->{$header});
52+
$this->updateFieldValue($sup_id, $field, $value);
53+
}
54+
}
55+
56+
/**
57+
* @see \Zend\Mail\Header\AbstractAddressList::fromString
58+
* @param $fieldValue
59+
* @return mixed
60+
*/
61+
private function unfold($fieldValue)
62+
{
63+
$fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue);
64+
65+
return $fieldValue;
66+
}
67+
68+
private function updateFieldValue($sup_id, $field, $value)
69+
{
70+
$field = $this->quoteTableName($field);
71+
$value = $this->quoteValue($value);
72+
73+
$stmt
74+
= "
75+
UPDATE {$this->email_table}
76+
SET $field=$value
77+
WHERE sup_id=$sup_id AND 1=0
78+
";
79+
$this->query($stmt);
80+
}
81+
82+
/**
83+
* Get sup_id where $field length appears to be truncated
84+
* Thus length is exactly 255 characters.
85+
* This will return only records where support_email_body is not truncated.
86+
*
87+
* @see https://github.com/eventum/eventum/issues/266
88+
*
89+
* @param string $field
90+
* @param int $length
91+
* @return Traversable|array
92+
*/
93+
private function getTruncatedRecords($field, $length = 255)
94+
{
95+
$field = $this->quoteTableName($field);
96+
97+
$stmt
98+
= "
99+
SELECT sup_id, $field field, seb_full_email body
100+
FROM {$this->email_table} e, {$this->body_table} b
101+
WHERE sup_id=seb_sup_id
102+
AND LENGTH($field) = $length
103+
aND sup_id=10357
104+
";
105+
106+
return $this->query($stmt);
107+
}
108+
}

src/Mail/Helper/SplitHeaderBody.php

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Eventum (Issue Tracking System) package.
5+
*
6+
* @copyright (c) Eventum Team
7+
* @license GNU General Public License, version 2 or later (GPL-2+)
8+
*
9+
* For the full copyright and license information,
10+
* please see the COPYING and AUTHORS files
11+
* that were distributed with this source code.
12+
*/
13+
14+
namespace Eventum\Mail\Helper;
15+
16+
use Mail_Helper;
17+
18+
class SplitHeaderBody
19+
{
20+
/**
21+
* Split $raw email to headers array and content part.
22+
*
23+
* @param string $raw
24+
* @param array &$headers
25+
* @param string &$content
26+
*/
27+
public static function splitMessage($raw, &$headers, &$content)
28+
{
29+
// this method could be really easy
30+
// if we wouldn't need to handle broken input.
31+
32+
// Handle messages broken by Mail_Helper::rewriteThreadingHeaders()
33+
// which by inserted References: to \r\n separated headers
34+
// used \n separator.
35+
36+
// split by standard headers separator
37+
list($headers, $content) = explode("\r\n\r\n", $raw, 2);
38+
39+
// split by \r\n, but \r may be optional
40+
$headers = preg_split("/\r?\n/", $headers);
41+
// strip any leftover \r
42+
$headers = array_map('trim', $headers);
43+
44+
// now headers is in array form, hard to break that again.
45+
}
46+
47+
private function jurajaokse()
48+
{
49+
// some old emails that were \r separated
50+
// eventum filled as \r\r\nheader\nheader\r\n
51+
// Mail_Helper::rewriteThreadingHeaders()
52+
// corrupted them
53+
54+
// split headers/body by \r\n and join headers back by \n
55+
// this ensures Headers::fromString doesn't assume email headers are \n\n separated
56+
// splitMessage)_
57+
list($headers, $content) = explode("\r\n\r\n", $raw, 2);
58+
59+
$headers = preg_split("/\r?\n/", $headers);
60+
// strip any leftover \r
61+
$headers = array_map('trim', $headers);
62+
// echo json_encode($headersArray);die;
63+
// $headers = join("\n", $headersArray);
64+
// $raw = $headers."\n\n".$content;
65+
66+
/* // try with default \n
67+
// then retry with \r\n
68+
try {
69+
Mime\Decode::splitMessage($raw, $headers, $content, "\n");
70+
} catch (\Zend\Mail\Exception\RuntimeException $e) {
71+
Mime\Decode::splitMessage($raw, $headers, $content, "\r\n");
72+
}*/
73+
74+
/*
75+
// if $raw is "\r" only separated, replace it with "\n"
76+
if (substr_count($headers, "\n") == 0) {
77+
$parts = explode("\r", $raw);
78+
$raw = join("\n", $parts);
79+
}*/
80+
return new CreateFromRaw();
81+
82+
// $message = new self(['root' => true, 'raw' => $raw]);
83+
$message = new self(['root' => true, 'headers' => $headers, 'content' => $content]);
84+
85+
return $message;
86+
}
87+
}

src/Mail/MailMessage.php

+39-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use DomainException;
1717
use Eventum\Mail\Helper\MimePart;
1818
use Eventum\Mail\Helper\SanitizeHeaders;
19+
use Eventum\Mail\Helper\SplitHeaderBody;
1920
use InvalidArgumentException;
2021
use LogicException;
2122
use Mime_Helper;
@@ -87,7 +88,42 @@ public static function createNew()
8788
*/
8889
public static function createFromString($raw)
8990
{
90-
$message = new self(['root' => true, 'raw' => $raw]);
91+
// some old emails that were \r separated
92+
// eventum filled as \r\r\nheader\nheader\r\n
93+
// Mail_Helper::rewriteThreadingHeaders()
94+
// corrupted them
95+
96+
// split headers/body by \r\n and join headers back by \n
97+
// this ensures Headers::fromString doesn't assume email headers are \n\n separated
98+
// splitMessage)_
99+
// list($headers, $content) = explode("\r\n\r\n", $raw, 2);
100+
101+
// $headers = preg_split("/\r?\n/", $headers);
102+
// strip any leftover \r
103+
// $headers = array_map('trim', $headers);
104+
// echo json_encode($headersArray);die;
105+
// $headers = join("\n", $headersArray);
106+
// $raw = $headers."\n\n".$content;
107+
108+
/* // try with default \n
109+
// then retry with \r\n
110+
try {
111+
Mime\Decode::splitMessage($raw, $headers, $content, "\n");
112+
} catch (\Zend\Mail\Exception\RuntimeException $e) {
113+
Mime\Decode::splitMessage($raw, $headers, $content, "\r\n");
114+
}*/
115+
116+
/*
117+
// if $raw is "\r" only separated, replace it with "\n"
118+
if (substr_count($headers, "\n") == 0) {
119+
$parts = explode("\r", $raw);
120+
$raw = join("\n", $parts);
121+
}*/
122+
// return new CreateFromRaw();
123+
SplitHeaderBody::splitMessage($raw, $headers, $content);
124+
125+
// $message = new self(['root' => true, 'raw' => $raw]);
126+
$message = new self(['root' => true, 'headers' => $headers, 'content' => $content]);
91127

92128
return $message;
93129
}
@@ -653,8 +689,8 @@ public function removeFromAddressList($header, $address)
653689
public function isSeen()
654690
{
655691
return $this->hasFlag(ZendMailStorage::FLAG_SEEN)
656-
|| $this->hasFlag(ZendMailStorage::FLAG_DELETED)
657-
|| $this->hasFlag(ZendMailStorage::FLAG_ANSWERED);
692+
|| $this->hasFlag(ZendMailStorage::FLAG_DELETED)
693+
|| $this->hasFlag(ZendMailStorage::FLAG_ANSWERED);
658694
}
659695

660696
/**

tests/Mail/MailParseTest.php

+42
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@
1313

1414
namespace Eventum\Test\Mail;
1515

16+
use Eventum\Mail\MailMessage;
1617
use Eventum\Test\TestCase;
18+
use Mail_Helper;
1719
use Mime_Helper;
20+
use Zend\Mail\Header\GenericHeader;
21+
use Zend\Mail\Header\To;
22+
use Zend\Mail\Headers;
1823

1924
/**
2025
* @group mail
@@ -42,4 +47,41 @@ public function testBug684922()
4247
$message_body = $structure->body;
4348
$this->assertEquals('', $message_body);
4449
}
50+
51+
/**
52+
* Test reading email whose headers are \r\n separated
53+
* but body is \n separated. AND it contains \n\n in the email body
54+
*/
55+
public function testReadHeadersSeparator()
56+
{
57+
/* $content = $this->readDataFile('10357_fixed.txt');
58+
59+
$m = MailMessage::createFromString($content);
60+
$headers = $m->getHeadersArray();
61+
list($text_headers, $body) = Mail_Helper::rewriteThreadingHeaders(1, $content, $headers);
62+
63+
file_put_contents('/tmp/broken2.txt', $text_headers);
64+
*/
65+
66+
$content = $this->readDataFile('10357_original.txt');
67+
$mail = MailMessage::createFromString($content);
68+
69+
// $content = $this->readDataFile('10357.txt');
70+
// $mail = MailMessage::createFromString($content);
71+
}
72+
73+
public function testToHeaderNameWithComma()
74+
{
75+
$to = To::fromString('To: "=?iso-8859-1?Q?Wetlesen=2C_Asbj=F8rn?=" <[email protected]>');
76+
echo $to->toString();
77+
$to = To::fromString($to->toString());
78+
echo $to->toString();
79+
}
80+
81+
public function testDogFood()
82+
{
83+
$headers = new Headers();
84+
$headers->addHeader(GenericHeader::fromString('To: "=?iso-8859-1?Q?Wetlesen=2C_Asbj=F8rn?=" <[email protected]>'));
85+
$headers->get('To');
86+
}
4587
}

0 commit comments

Comments
 (0)