Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/TNEFDecoder/TNEFAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ class TNEFAttachment
{

var $debug;
var $validateChecksum;
var $mailinfo;
var $files;
var $files_nested;
var $attachments;
var $current_receiver;
var $body;

function __construct($debug = false)
function __construct($debug = false, $validateChecksum = false)
{
$this->debug = $debug;
$this->validateChecksum = $validateChecksum;
$this->files = array();
$this->attachments = array();
$this->mailinfo = new TNEFMailinfo();
Expand Down Expand Up @@ -158,7 +160,13 @@ function tnef_decode_attribute(&$buffer)
$attribute = tnef_geti32($buffer); // attribute if
$length = tnef_geti32($buffer); // length
$value = tnef_getx($length, $buffer); // data
tnef_geti16($buffer); // checksum
$checksumAtt = tnef_geti16($buffer); // checksum
if ($value !== null && $this->validateChecksum) {
$checksum = array_sum(unpack('C*', $value)) & 0xFFFF;
if ($checksum !== $checksumAtt) {
throw new \Exception('Checksums do not match');
}
}

switch($attribute)
{
Expand Down Expand Up @@ -339,7 +347,7 @@ function extract_mapi_attrs(&$buffer)
if ($this->debug)
tnef_log("MAPI Found nested attachment. Processing new one.");
tnef_getx(16, $value); // skip the next 16 bytes (unknown data)
$att = new TNEFAttachment($this->debug);
$att = new TNEFAttachment($this->debug, $this->validateChecksum);
$att->decodeTnef($value);
$this->attachments[] = $att;
if ($this->debug)
Expand Down
109 changes: 44 additions & 65 deletions test/TNEFAttachmentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,14 @@

class TNEFAttachmentTest extends TestCase
{
// /**
// * Test decoding winmail.dat from email attachment encoded in base64
// */
// public function testDecode() {
// $buffer = base64_decode(file_get_contents(dirname(__FILE__) . "/testfiles/base64_attachment.txt"));
// file_put_contents(dirname(__FILE__) . "/testfiles/winmail.dat", $buffer);
//
// $attachment = new TNEFAttachment();
// $attachment->decodeTnef($buffer);
// $files = $attachment->getFiles();
//
// $this->assertEquals(4, count($files));
// $this->assertEquals("image001.jpg", $files[0]->getName());
// $this->assertEquals("image003.jpg", $files[1]->getName());
// $this->assertEquals("image004.jpg", $files[2]->getName());
// $this->assertEquals("image005.jpg", $files[3]->getName());
//
// foreach ($files as $file) {
// $this->assertEquals("image/jpeg", $file->getType());
// }
//
// }
//
// /**
// * Test decoding winmail.dat file from filesystem
// */
// public function testDecode2() {
// $buffer = file_get_contents(dirname(__FILE__) . "/testfiles/winmail2.dat");
//
// $attachment = new TNEFAttachment($buffer);
// $attachment->decodeTnef($buffer);
// $files = $attachment->getFiles();
//
// $this->assertEquals(3, count($files));
// $this->assertEquals("EmbeddedRTF.rtf", $files[0]->getName());
// $this->assertEquals("zappa_av1.jpg", $files[1]->getName());
// $this->assertEquals("bookmark.htm", $files[2]->getName());
// }

/**
* Test decoding winmail.dat file from filesystem
*/
public function testDecode3()
{
$buffer = file_get_contents(dirname(__FILE__) . "/testfiles/two-files.tnef");

$attachment = new TNEFAttachment($buffer);
$attachment = new TNEFAttachment();
$attachment->decodeTnef($buffer);
$files = $attachment->getFiles();

Expand All @@ -62,35 +23,53 @@ public function testDecode3()
$this->assertEquals("README", $files[1]->getName());
}

public function testDecodeAuto() {
$files = scandir ( dirname(__FILE__) . "/testfiles/");
foreach ($files as $file) {
$ext = explode('.', $file);
if (count($ext) == 2 && $ext[1] == "tnef") {
$buffer = file_get_contents(dirname(__FILE__) . "/testfiles/" . $file);
$list = file(dirname(__FILE__) . "/testfiles/" . $ext[0] . '.list', FILE_IGNORE_NEW_LINES + FILE_SKIP_EMPTY_LINES);
$attachment = new TNEFAttachment();
$attachment->decodeTnef($buffer);
$this->assertEquals(count($list), count($attachment->files));
$decodedFiles = array_map(function(TNEFFileBase$file) {return $file->getName();}, $attachment->files);

$withoutRtf = array_filter($list, array($this, "endsWithRtf"));
$withoutRtfdecoded = array_filter($decodedFiles, array($this, "endsWithRtf"));

$rtfs = array_diff($withoutRtf, $list);
$rtfsDecoded = array_diff($withoutRtfdecoded, $decodedFiles);

$this->assertEquals(count($rtfs), count($rtfsDecoded));

sort($withoutRtfdecoded);
sort($withoutRtf);
$this->assertEquals($withoutRtf, $withoutRtfdecoded);
}
/**
* @dataProvider tnefFileProvider
*/
public function testDecodeAuto($tnefFile, $listFile) {
$buffer = file_get_contents($tnefFile);
$attachment = new TNEFAttachment(false, true);

if ($listFile === null) {
$this->expectExceptionMessage('Checksums do not match');
}
$attachment->decodeTnef($buffer);

$list = file($listFile, FILE_IGNORE_NEW_LINES + FILE_SKIP_EMPTY_LINES);
$this->assertEquals(count($list), count($attachment->files));
$decodedFiles = array_map(function(TNEFFileBase$file) {return $file->getName();}, $attachment->files);

$withoutRtf = array_filter($list, array($this, "endsWithRtf"));
$withoutRtfdecoded = array_filter($decodedFiles, array($this, "endsWithRtf"));

$rtfs = array_diff($withoutRtf, $list);
$rtfsDecoded = array_diff($withoutRtfdecoded, $decodedFiles);

$this->assertEquals(count($rtfs), count($rtfsDecoded));

sort($withoutRtfdecoded);
sort($withoutRtf);
$this->assertEquals($withoutRtf, $withoutRtfdecoded);
}

public function tnefFileProvider() {
$tnefFiles = glob(dirname(__FILE__) . "/testfiles/*.tnef");
$result = [];
foreach ($tnefFiles as $tnefFile) {
$pathinfo = pathinfo($tnefFile);
$listFile = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '.list';

$result[] = [
$tnefFile,
file_exists($listFile) ? $listFile : null,
];
}

return $result;
}

private function endsWithRtf($value) {
try{
try {
return explode('.', $value)[1] != 'rtf';
} catch (Throwable $e) {
return false;
Expand Down
Binary file added test/testfiles/invalid-checksum.tnef
Binary file not shown.