mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 15:45:55 +08:00
Improved TNEFDecoder
This commit is contained in:
parent
d498bf2b53
commit
913ed54668
|
@ -531,6 +531,10 @@ trait Messages
|
|||
if (\in_array($oFile->type, ['application/rtf', 'text/rtf'])) {
|
||||
$rtf = new \SnappyMail\Rtf\Document($oFile->content);
|
||||
$oMessage->setHtml($rtf->toHTML());
|
||||
} else {
|
||||
// List as attachment?
|
||||
$oMapiAttachment = new \MailSo\Mail\Attachment($sFolder, $iUid, BodyStructure);
|
||||
$oMessage->Attachments->append($oMapiAttachment);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace TNEFDecoder;
|
||||
|
||||
require 'functions.php';
|
||||
require 'constants.php';
|
||||
|
||||
/**
|
||||
|
@ -19,128 +18,107 @@ require 'constants.php';
|
|||
*
|
||||
*/
|
||||
|
||||
function tnef_log($string)
|
||||
{
|
||||
echo $string . "\n";
|
||||
// \error_log($string . "\n", 3, '/tmp/squirrelmail_tnef_decoder.log');
|
||||
// \SnappyMail\Log::debug('TNEF', $string);
|
||||
}
|
||||
|
||||
class TNEFAttachment
|
||||
{
|
||||
|
||||
var $validateChecksum;
|
||||
var $mailinfo;
|
||||
var $files;
|
||||
var $files_nested;
|
||||
var $attachments;
|
||||
var $current_receiver;
|
||||
var $body;
|
||||
public bool $debug;
|
||||
public bool $validateChecksum;
|
||||
public TNEFMailinfo $mailinfo;
|
||||
public array
|
||||
$files = [],
|
||||
$attachments = [],
|
||||
$body = [];
|
||||
public ?array $files_nested = null;
|
||||
public ?TNEFFile $current_receiver = null;
|
||||
|
||||
function __construct($validateChecksum = false)
|
||||
public function __construct(bool $debug = false, bool $validateChecksum = false)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
$this->validateChecksum = $validateChecksum;
|
||||
$this->files = array();
|
||||
$this->attachments = array();
|
||||
$this->mailinfo = new TNEFMailinfo();
|
||||
$this->body = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TNEFFileBase[]
|
||||
*/
|
||||
function &getFiles()
|
||||
* @return TNEFFileBase[]
|
||||
*/
|
||||
public function &getFiles(): array
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TNEFFileBase[]
|
||||
*/
|
||||
function &getFilesNested()
|
||||
* @return TNEFFileBase[]
|
||||
*/
|
||||
public function &getFilesNested(): array
|
||||
{
|
||||
if (!$this->files_nested)
|
||||
{
|
||||
if (null === $this->files_nested) {
|
||||
$this->files_nested = array();
|
||||
|
||||
$num_attach = count($this->attachments);
|
||||
if ($num_attach > 0)
|
||||
{
|
||||
for ($cnt = 0; $cnt < $num_attach; $cnt++)
|
||||
{
|
||||
$this->addFiles($this->files_nested, $this->files);
|
||||
$this->addFiles($this->files_nested, $this->attachments[$cnt]->getFilesNested());
|
||||
}
|
||||
$this->addFilesNested($this->files);
|
||||
foreach ($this->attachments as $attachment) {
|
||||
$this->addFilesNested($attachment->getFilesNested());
|
||||
}
|
||||
else
|
||||
$this->addFiles($this->files_nested, $this->files);
|
||||
}
|
||||
|
||||
return $this->files_nested;
|
||||
}
|
||||
|
||||
function addFiles(&$add_to, &$add)
|
||||
private function addFilesNested(array &$add): void
|
||||
{
|
||||
global $tnef_minimum_rtf_size_to_decode;
|
||||
$num_files = count($add);
|
||||
for ($cnt = 0; $cnt < $num_files; $cnt++)
|
||||
if ((strtolower(get_class($add[$cnt])) != "tneffilertf") || ($add[$cnt]->getSize() > $tnef_minimum_rtf_size_to_decode))
|
||||
$add_to[] = &$add[$cnt];
|
||||
foreach ($add as $file) {
|
||||
$this->files_nested[] = &$file;
|
||||
}
|
||||
}
|
||||
|
||||
function addFilesCond(&$add_to, &$add)
|
||||
{
|
||||
global $tnef_minimum_rtf_size_to_decode;
|
||||
$num_files = count($add);
|
||||
for ($cnt = 0; $cnt < $num_files; $cnt++)
|
||||
if ((strtolower(get_class($add[$cnt])) == "tneffilertf") && ($add[$cnt]->getSize() > $tnef_minimum_rtf_size_to_decode))
|
||||
$add_to[] = &$add[$cnt];
|
||||
}
|
||||
|
||||
function getAttachments()
|
||||
public function getAttachments(): array
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TNEFMailinfo
|
||||
*/
|
||||
function getMailinfo()
|
||||
public function getMailinfo(): TNEFMailinfo
|
||||
{
|
||||
return $this->mailinfo;
|
||||
}
|
||||
|
||||
function getBodyElements()
|
||||
public function getBodyElements(): array
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
function decodeTnef($data)
|
||||
public function decodeTnef($data): void
|
||||
{
|
||||
$buffer = new TNEFBuffer($data);
|
||||
|
||||
$tnef_signature = tnef_geti32($buffer);
|
||||
if ($tnef_signature == TNEF_SIGNATURE) {
|
||||
$tnef_key = tnef_geti16($buffer);
|
||||
tnef_log(sprintf("Signature: 0x%08x\nKey: 0x%04x\n", $tnef_signature, $tnef_key));
|
||||
$tnef_signature = $buffer->geti32();
|
||||
if (TNEF_SIGNATURE == $tnef_signature) {
|
||||
$tnef_key = $buffer->geti16();
|
||||
$this->debug && tnef_log(\sprintf("Signature: 0x%08x\nKey: 0x%04x\n", $tnef_signature, $tnef_key));
|
||||
|
||||
while ($buffer->getRemainingBytes() > 0) {
|
||||
$lvl_type = tnef_geti8($buffer);
|
||||
$lvl_type = $buffer->geti8();
|
||||
|
||||
switch ($lvl_type) {
|
||||
case TNEF_LVL_MESSAGE:
|
||||
$this->tnef_decode_attribute($buffer);
|
||||
break;
|
||||
|
||||
case TNEF_LVL_ATTACHMENT:
|
||||
$this->tnef_decode_attribute($buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
$len = $buffer->getRemainingBytes();
|
||||
if ($len > 0)
|
||||
tnef_log("Invalid file format! Unknown Level $lvl_type. Rest=$len");
|
||||
if ($this->debug) {
|
||||
$len = $buffer->getRemainingBytes();
|
||||
if ($len)
|
||||
tnef_log("Invalid file format! Unknown Level {$lvl_type}. Rest={$len}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tnef_log("Invalid file format! Wrong signature.");
|
||||
} else {
|
||||
throw new \RuntimeException("TNEF: Invalid file format! Wrong signature.");
|
||||
}
|
||||
|
||||
// propagate parent message's code page to child files if given
|
||||
|
@ -151,43 +129,42 @@ class TNEFAttachment
|
|||
$this->files[$i]->setMessageCodePage($code_page);
|
||||
}
|
||||
|
||||
function tnef_decode_attribute(TNEFBuffer $buffer)
|
||||
private function tnef_decode_attribute(TNEFBuffer $buffer)
|
||||
{
|
||||
$attribute = tnef_geti32($buffer); // attribute if
|
||||
$length = tnef_geti32($buffer); // length
|
||||
$value = tnef_getx($length, $buffer); // data
|
||||
$checksumAtt = tnef_geti16($buffer); // checksum
|
||||
$attribute = $buffer->geti32(); // attribute if
|
||||
$length = $buffer->geti32(); // length
|
||||
$value = $buffer->getBytes($length); // data
|
||||
$checksumAtt = $buffer->geti16(); // checksum
|
||||
if ($value !== null && $this->validateChecksum) {
|
||||
$checksum = array_sum(unpack('C*', $value)) & 0xFFFF;
|
||||
$checksum = \array_sum(\unpack('C*', $value)) & 0xFFFF;
|
||||
if ($checksum !== $checksumAtt) {
|
||||
throw new \Exception('Checksums do not match');
|
||||
}
|
||||
}
|
||||
|
||||
switch($attribute)
|
||||
switch ($attribute)
|
||||
{
|
||||
case TNEF_ARENDDATA: // marks start of new attachment
|
||||
tnef_log("Creating new File for Attachment");
|
||||
$this->current_receiver = new TNEFFile();
|
||||
case TNEF_ARENDDATA: // marks start of new attachment
|
||||
$this->debug && tnef_log("Creating new File for Attachment");
|
||||
$this->current_receiver = new TNEFFile($this->debug);
|
||||
$this->files[] = $this->current_receiver;
|
||||
break;
|
||||
|
||||
case TNEF_AMAPIATTRS:
|
||||
tnef_log("mapi attrs");
|
||||
$this->debug && tnef_log("mapi attrs");
|
||||
$this->extract_mapi_attrs(new TNEFBuffer($value));
|
||||
break;
|
||||
|
||||
case TNEF_AMAPIPROPS:
|
||||
tnef_log("mapi props");
|
||||
$this->debug && tnef_log("mapi props");
|
||||
$this->extract_mapi_attrs(new TNEFBuffer($value));
|
||||
break;
|
||||
|
||||
case TNEF_AMCLASS:
|
||||
$value = substr($value, 0, $length - 1);
|
||||
if ($value == 'IPM.Contact')
|
||||
{
|
||||
tnef_log("Creating vCard Attachment");
|
||||
$this->current_receiver = new TNEFvCard();
|
||||
if ($value == 'IPM.Contact') {
|
||||
$this->debug && tnef_log("Creating vCard Attachment");
|
||||
$this->current_receiver = new TNEFvCard($this->debug);
|
||||
$this->files[] = $this->current_receiver;
|
||||
}
|
||||
break;
|
||||
|
@ -200,83 +177,79 @@ class TNEFAttachment
|
|||
}
|
||||
}
|
||||
|
||||
function extract_mapi_attrs(TNEFBuffer $buffer)
|
||||
private function extract_mapi_attrs(TNEFBuffer $buffer): void
|
||||
{
|
||||
|
||||
$number = tnef_geti32($buffer); // number of attributes
|
||||
$number = $buffer->geti32(); // number of attributes
|
||||
$props = 0;
|
||||
$ended = 0;
|
||||
|
||||
while (($buffer->getRemainingBytes() > 0) && ($props < $number) && (!$ended))
|
||||
{
|
||||
$props++;
|
||||
while (($buffer->getRemainingBytes() > 0) && ($props++ < $number) && !$ended) {
|
||||
$value = '';
|
||||
unset($named_id);
|
||||
$length = 0;
|
||||
$have_multivalue = 0;
|
||||
$have_multivalue = false;
|
||||
$num_multivalues = 1;
|
||||
$attr_type = tnef_geti16($buffer);
|
||||
$attr_name = tnef_geti16($buffer);
|
||||
$attr_type = $buffer->geti16();
|
||||
$attr_name = $buffer->geti16();
|
||||
|
||||
if (($attr_type & TNEF_MAPI_MV_FLAG) != 0)
|
||||
{
|
||||
tnef_log("Multivalue Attribute found.");
|
||||
$have_multivalue = 1;
|
||||
if (($attr_type & TNEF_MAPI_MV_FLAG) != 0) {
|
||||
$this->debug && tnef_log("Multivalue Attribute found.");
|
||||
$have_multivalue = true;
|
||||
$attr_type = $attr_type & ~TNEF_MAPI_MV_FLAG;
|
||||
}
|
||||
|
||||
if (($attr_name >= 0x8000) && ($attr_name < 0xFFFE)) // Named Attribute
|
||||
{
|
||||
$guid = tnef_getx(16, $buffer);
|
||||
$named_type = tnef_geti32($buffer);
|
||||
// Named Attribute
|
||||
if (($attr_name >= 0x8000) && ($attr_name < 0xFFFE)) {
|
||||
$guid = $buffer->getBytes(16);
|
||||
$named_type = $buffer->geti32();
|
||||
switch ($named_type)
|
||||
{
|
||||
case TNEF_MAPI_NAMED_TYPE_ID:
|
||||
$named_id = tnef_geti32($buffer);
|
||||
$attr_name = $named_id;
|
||||
tnef_log(sprintf("Named Id='0x%04x'", $named_id));
|
||||
break;
|
||||
$named_id = $buffer->geti32();
|
||||
$attr_name = $named_id;
|
||||
$this->debug && tnef_log(sprintf("Named Id='0x%04x'", $named_id));
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_NAMED_TYPE_STRING:
|
||||
$attr_name = 0x9999; // dummy to identify strings
|
||||
$idlen = tnef_geti32($buffer);
|
||||
tnef_log("idlen=$idlen");
|
||||
$buflen = $idlen + ((4 - ($idlen % 4)) % 4); // pad to next 4 byte boundary
|
||||
tnef_log("buflen=$buflen");
|
||||
$named_id = substr(tnef_getx($buflen, $buffer), 0, $idlen ); // read and truncate to length
|
||||
tnef_log("Named Id='$named_id'");
|
||||
break;
|
||||
$attr_name = 0x9999; // dummy to identify strings
|
||||
$idlen = $buffer->geti32();
|
||||
$this->debug && tnef_log("idlen={$idlen}");
|
||||
$buflen = $idlen + ((4 - ($idlen % 4)) % 4); // pad to next 4 byte boundary
|
||||
$this->debug && tnef_log("buflen={$buflen}");
|
||||
$named_id = substr($buffer->getBytes($buflen), 0, $idlen ); // read and truncate to length
|
||||
$this->debug && tnef_log("Named Id='{$named_id}'");
|
||||
break;
|
||||
|
||||
default:
|
||||
tnef_log(sprintf("Unknown Named Type 0x%04x found", $named_type));
|
||||
break;
|
||||
$this->debug && tnef_log(\sprintf("Unknown Named Type 0x%04x found", $named_type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($have_multivalue)
|
||||
{
|
||||
$num_multivalues = tnef_geti32($buffer);
|
||||
tnef_log("Number of multivalues=$num_multivalues");
|
||||
if ($have_multivalue) {
|
||||
$num_multivalues = $buffer->geti32();
|
||||
$this->debug && tnef_log("Number of multivalues={$num_multivalues}");
|
||||
}
|
||||
|
||||
switch($attr_type)
|
||||
switch ($attr_type)
|
||||
{
|
||||
case TNEF_MAPI_NULL:
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_SHORT:
|
||||
$value = tnef_geti16($buffer);
|
||||
$value = $buffer->geti16();
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_INT:
|
||||
case TNEF_MAPI_BOOLEAN:
|
||||
for ($cnt = 0; $cnt < $num_multivalues; $cnt++)
|
||||
$value = tnef_geti32($buffer);
|
||||
$value = $buffer->geti32();
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_FLOAT:
|
||||
case TNEF_MAPI_ERROR:
|
||||
$value = tnef_getx(4, $buffer);
|
||||
$value = $buffer->getBytes(4);
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_DOUBLE:
|
||||
|
@ -284,59 +257,53 @@ class TNEFAttachment
|
|||
case TNEF_MAPI_CURRENCY:
|
||||
case TNEF_MAPI_INT8BYTE:
|
||||
case TNEF_MAPI_SYSTIME:
|
||||
$value = tnef_getx(8, $buffer);
|
||||
$value = $buffer->getBytes(8);
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_CLSID:
|
||||
tnef_log("What is a MAPI CLSID ????");
|
||||
$this->debug && tnef_log("What is a MAPI CLSID ????");
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_STRING:
|
||||
case TNEF_MAPI_UNICODE_STRING:
|
||||
case TNEF_MAPI_BINARY:
|
||||
case TNEF_MAPI_OBJECT:
|
||||
if ($have_multivalue)
|
||||
$num_vals = $num_multivalues;
|
||||
else
|
||||
$num_vals = tnef_geti32($buffer);
|
||||
$num_vals = $have_multivalue ? $num_multivalues : $buffer->geti32();
|
||||
|
||||
if ($num_vals > 20) // A Sanity check.
|
||||
{
|
||||
$ended = 1;
|
||||
tnef_log("Number of entries in String Attributes=$num_vals. Aborting Mapi parsing.");
|
||||
}
|
||||
else
|
||||
{
|
||||
for ($cnt = 0; $cnt < $num_vals; $cnt++)
|
||||
{
|
||||
$length = tnef_geti32($buffer);
|
||||
$buflen = $length + ((4 - ($length % 4)) % 4); // pad to next 4 byte boundary
|
||||
if ($attr_type == TNEF_MAPI_STRING)
|
||||
$length -= 1;
|
||||
$value = substr(tnef_getx($buflen, $buffer), 0, $length); // read and truncate to length
|
||||
}
|
||||
if ($num_vals > 20) {
|
||||
// A Sanity check.
|
||||
$ended = 1;
|
||||
$this->debug && tnef_log("Number of entries in String Attributes={$num_vals}. Aborting Mapi parsing.");
|
||||
} else {
|
||||
for ($cnt = 0; $cnt < $num_vals; ++$cnt) {
|
||||
$length = $buffer->geti32();
|
||||
$buflen = $length + ((4 - ($length % 4)) % 4); // pad to next 4 byte boundary
|
||||
if ($attr_type == TNEF_MAPI_STRING)
|
||||
$length -= 1;
|
||||
$value = \substr($buffer->getBytes($buflen), 0, $length); // read and truncate to length
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
tnef_log("Unknown mapi attribute! $attr_type");
|
||||
$this->debug && tnef_log("Unknown mapi attribute! {$attr_type}");
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($attr_name)
|
||||
{
|
||||
case TNEF_MAPI_ATTACH_DATA:
|
||||
tnef_log("MAPI Found nested attachment. Processing new one.");
|
||||
$this->debug && tnef_log("MAPI Found nested attachment. Processing new one.");
|
||||
$value = substr($value, 16); // skip the next 16 bytes (unknown data)
|
||||
$att = new TNEFAttachment($this->validateChecksum);
|
||||
$att = new TNEFAttachment($this->debug, $this->validateChecksum);
|
||||
$att->decodeTnef($value);
|
||||
$this->attachments[] = $att;
|
||||
tnef_log("MAPI Finished nested attachment. Continuing old one.");
|
||||
$this->debug && tnef_log("MAPI Finished nested attachment. Continuing old one.");
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_RTF_COMPRESSED:
|
||||
tnef_log("MAPI Found Compressed RTF Attachment.");
|
||||
$this->files[] = new TNEFFileRTF($value);
|
||||
$this->debug && tnef_log("MAPI Found Compressed RTF Attachment.");
|
||||
$this->files[] = new TNEFFileRTF($this->debug, $value);
|
||||
break;
|
||||
case TNEF_MAPI_BODY:
|
||||
case TNEF_MAPI_BODY_HTML:
|
||||
|
@ -349,23 +316,18 @@ class TNEFAttachment
|
|||
$this->body[] = $result;
|
||||
break;
|
||||
default:
|
||||
$this->mailinfo->receiveMapiAttribute($attr_type, $attr_name, $value, $length, ($attr_type == TNEF_MAPI_UNICODE_STRING));
|
||||
$this->mailinfo->receiveMapiAttribute($attr_type, $attr_name, $value, $length);
|
||||
if ($this->current_receiver)
|
||||
$this->current_receiver->receiveMapiAttribute($attr_type, $attr_name, $value, $length, ($attr_type == TNEF_MAPI_UNICODE_STRING));
|
||||
$this->current_receiver->receiveMapiAttribute($attr_type, $attr_name, $value, $length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($ended)
|
||||
{
|
||||
if ($this->debug && $ended) {
|
||||
$len = $buffer->getRemainingBytes();
|
||||
for ($cnt = 0; $cnt < $len; $cnt++)
|
||||
{
|
||||
$ord = tnef_geti8($buffer);
|
||||
if ($ord == 0)
|
||||
$char = "";
|
||||
else
|
||||
$char = chr($ord);
|
||||
tnef_log(sprintf("Char Nr. %6d = 0x%02x = '%s'", $cnt, $ord, $char));
|
||||
for ($cnt = 0; $cnt < $len; ++$cnt) {
|
||||
$ord = $buffer->geti8();
|
||||
$char = $ord ? \chr($ord) : '';
|
||||
tnef_log(\sprintf("Char Nr. %6d = 0x%02x = '%s'", $cnt, $ord, $char));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,14 @@ namespace TNEFDecoder;
|
|||
class TNEFBuffer
|
||||
{
|
||||
private string $data;
|
||||
private int $offset;
|
||||
private int $offset = 0;
|
||||
|
||||
function __construct(string $data)
|
||||
public function __construct(string $data)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
function getBytes(int $numBytes): ?string
|
||||
public function getBytes(int $numBytes): ?string
|
||||
{
|
||||
if ($this->getRemainingBytes() < $numBytes) {
|
||||
$this->offset = \strlen($this->data);
|
||||
|
@ -38,11 +37,30 @@ class TNEFBuffer
|
|||
return \substr($this->data, $this->offset - $numBytes, $numBytes);
|
||||
}
|
||||
|
||||
function getRemainingBytes(): int
|
||||
public function getRemainingBytes(): int
|
||||
{
|
||||
return \strlen($this->data) - $this->offset;
|
||||
}
|
||||
|
||||
public function geti8(): ?int
|
||||
{
|
||||
$bytes = $this->getBytes(1);
|
||||
return (null === $bytes) ? null : \ord($bytes[0]);
|
||||
}
|
||||
|
||||
public function geti16(): ?int
|
||||
{
|
||||
$bytes = $this->getBytes(2);
|
||||
return (null === $bytes) ? null : \ord($bytes[0]) + (\ord($bytes[1]) << 8);
|
||||
}
|
||||
|
||||
public function geti32(): ?int
|
||||
{
|
||||
$bytes = $this->getBytes(4);
|
||||
return (null === $bytes) ? null
|
||||
: \ord($bytes[0])
|
||||
+ (\ord($bytes[1]) << 8)
|
||||
+ (\ord($bytes[2]) << 16)
|
||||
+ (\ord($bytes[3]) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,31 +14,24 @@
|
|||
*
|
||||
*/
|
||||
|
||||
class TNEFDate
|
||||
class TNEFDate extends \DateTime
|
||||
{
|
||||
|
||||
private ?int $year;
|
||||
private ?int $month;
|
||||
private ?int $day;
|
||||
private ?int $hour;
|
||||
private ?int $minute;
|
||||
private ?int $second;
|
||||
public function __construct(string $datetime = "now", ?\DateTimeZone $timezone = null)
|
||||
{
|
||||
parent::__construct($datetime, new \DateTimeZone('UTC'));
|
||||
}
|
||||
|
||||
public function setTnefBuffer(TNEFBuffer $buffer)
|
||||
{
|
||||
$this->year = tnef_geti16($buffer);
|
||||
$this->month = tnef_geti16($buffer);
|
||||
$this->day = tnef_geti16($buffer);
|
||||
$this->hour = tnef_geti16($buffer);
|
||||
$this->minute = tnef_geti16($buffer);
|
||||
$this->second = tnef_geti16($buffer);
|
||||
$this->setDate(
|
||||
$buffer->geti16(), // year
|
||||
$buffer->geti16(), // month
|
||||
$buffer->geti16() // day
|
||||
);
|
||||
$this->setTime(
|
||||
$buffer->geti16(), // hour
|
||||
$buffer->geti16(), // minute
|
||||
$buffer->geti16() // second
|
||||
);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return \sprintf("%04d-%02d-%02d %02d:%02d:%02d",
|
||||
$this->year, $this->month, $this->day,
|
||||
$this->hour, $this->minute, $this->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?php namespace TNEFDecoder;
|
||||
<?php
|
||||
|
||||
namespace TNEFDecoder;
|
||||
|
||||
/**
|
||||
* SquirrelMail TNEF Decoder Plugin
|
||||
|
@ -17,14 +19,14 @@
|
|||
class TNEFFile extends TNEFFileBase
|
||||
{
|
||||
|
||||
var $metafile;
|
||||
public string $metafile;
|
||||
|
||||
function getMetafile()
|
||||
public function getMetafile()
|
||||
{
|
||||
return $this->metafile;
|
||||
}
|
||||
|
||||
function receiveTnefAttribute($attribute, $value, $length)
|
||||
public function receiveTnefAttribute(int $attribute, string $value, int $length): void
|
||||
{
|
||||
switch ($attribute)
|
||||
{
|
||||
|
@ -34,18 +36,18 @@ class TNEFFile extends TNEFFileBase
|
|||
case TNEF_AFILENAME:
|
||||
// strip path
|
||||
//
|
||||
if (($pos = strrpos($value, '/')) !== FALSE)
|
||||
$this->name = substr($value, $pos + 1);
|
||||
if (($pos = \strrpos($value, '/')) !== FALSE)
|
||||
$this->name = \substr($value, $pos + 1);
|
||||
else
|
||||
$this->name = $value;
|
||||
|
||||
// Strip trailing null bytes if present
|
||||
$this->name = trim($this->name);
|
||||
$this->name = \trim($this->name);
|
||||
break;
|
||||
// code page
|
||||
//
|
||||
case TNEF_AOEMCODEPAGE:
|
||||
$this->code_page = tnef_geti16(new TNEFBuffer($value));
|
||||
$this->code_page = (new TNEFBuffer($value))->geti16();
|
||||
break;
|
||||
|
||||
// the attachment itself
|
||||
|
@ -71,7 +73,7 @@ class TNEFFile extends TNEFFileBase
|
|||
}
|
||||
}
|
||||
|
||||
function receiveMapiAttribute($attr_type, $attr_name, $value, $length, $is_unicode=FALSE)
|
||||
public function receiveMapiAttribute(int $attr_type, int $attr_name, string $value, int $length): void
|
||||
{
|
||||
switch ($attr_name)
|
||||
{
|
||||
|
@ -81,26 +83,26 @@ class TNEFFile extends TNEFFileBase
|
|||
case TNEF_MAPI_ATTACH_LONG_FILENAME:
|
||||
// strip path
|
||||
//
|
||||
if (($pos = strrpos($value, '/')) !== FALSE)
|
||||
$this->name = substr($value, $pos + 1);
|
||||
if (($pos = \strrpos($value, '/')) !== FALSE)
|
||||
$this->name = \substr($value, $pos + 1);
|
||||
else
|
||||
$this->name = $value;
|
||||
|
||||
if ($is_unicode) $this->name_is_unicode = TRUE;
|
||||
$this->name_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
// Is this ever set, and what is format?
|
||||
//
|
||||
case TNEF_MAPI_ATTACH_MIME_TAG:
|
||||
$type0 = $type1 = '';
|
||||
$mime_type = explode('/', $value, 2);
|
||||
$mime_type = \explode('/', $value, 2);
|
||||
if (!empty($mime_type[0]))
|
||||
$type0 = $mime_type[0];
|
||||
if (!empty($mime_type[1]))
|
||||
$type1 = $mime_type[1];
|
||||
$this->type = "$type0/$type1";
|
||||
if ($is_unicode) {
|
||||
$this->type = substr(mb_convert_encoding($this->type, "UTF-8" , "UTF-16LE"), 0, -1);
|
||||
$this->type = "{$type0}/{$type1}";
|
||||
if (TNEF_MAPI_UNICODE_STRING === $attr_type) {
|
||||
$this->type = \substr(\mb_convert_encoding($this->type, "UTF-8" , "UTF-16LE"), 0, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?php namespace TNEFDecoder;
|
||||
<?php
|
||||
|
||||
namespace TNEFDecoder;
|
||||
|
||||
/**
|
||||
* SquirrelMail TNEF Decoder Plugin
|
||||
|
@ -17,36 +19,64 @@
|
|||
class TNEFFileBase
|
||||
{
|
||||
public bool $name_is_unicode = FALSE;
|
||||
public string $name = 'Untitled';
|
||||
public string $code_page = '';
|
||||
public string $message_code_page = ''; // parent message's code page (the whole TNEF file)
|
||||
public string $type = 'application/octet-stream';
|
||||
public string $content = '';
|
||||
var $created;
|
||||
var $modified;
|
||||
public string
|
||||
$name = 'Untitled',
|
||||
$code_page = '',
|
||||
$message_code_page = '', // parent message's code page (the whole TNEF file)
|
||||
$type = 'application/octet-stream',
|
||||
$content = '';
|
||||
public ?TNEFDate
|
||||
$created = null,
|
||||
$modified = null;
|
||||
public bool $debug;
|
||||
|
||||
function setMessageCodePage(string $code_page)
|
||||
public function __construct(bool $debug)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
public function setMessageCodePage(string $code_page): void
|
||||
{
|
||||
$this->message_code_page = $code_page;
|
||||
}
|
||||
|
||||
function getCodePage()
|
||||
public function getCodePage(): string
|
||||
{
|
||||
return empty($this->code_page)
|
||||
? $this->message_code_page
|
||||
: $this->code_page;
|
||||
}
|
||||
|
||||
function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
if ($this->name_is_unicode) {
|
||||
return \substr(\mb_convert_encoding($this->name, "UTF-8" , "UTF-16LE"), 0, -1);
|
||||
}
|
||||
return $this->name;
|
||||
return $this->name_is_unicode
|
||||
? \substr(\mb_convert_encoding($this->name, "UTF-8" , "UTF-16LE"), 0, -1)
|
||||
: $this->name;
|
||||
}
|
||||
|
||||
function getSize()
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getSize(): int
|
||||
{
|
||||
return \strlen($this->content);
|
||||
}
|
||||
|
||||
public function getCreated(): ?TNEFDate
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
public function getModified(): ?TNEFDate
|
||||
{
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,34 +15,33 @@
|
|||
*/
|
||||
class TNEFFileRTF extends TNEFFileBase
|
||||
{
|
||||
var $size;
|
||||
public string $name = 'EmbeddedRTF.rtf';
|
||||
public string $type = 'application/rtf';
|
||||
protected int $size = 0;
|
||||
const MAX_DICT_SIZE = 4096;
|
||||
const INIT_DICT_SIZE = 207;
|
||||
|
||||
function __construct($data)
|
||||
public function __construct($debug, $data)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->type = "application/rtf";
|
||||
$this->name = "EmbeddedRTF.rtf";
|
||||
|
||||
parent::__construct($debug);
|
||||
$this->decode_crtf(new TNEFBuffer($data));
|
||||
}
|
||||
|
||||
function getSize()
|
||||
public function getSize(): int
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
function decode_crtf(TNEFBuffer $buffer)
|
||||
public function decode_crtf(TNEFBuffer $buffer)
|
||||
{
|
||||
$size_compressed = tnef_geti32($buffer);
|
||||
$this->size = tnef_geti32($buffer);
|
||||
$magic = tnef_geti32($buffer);
|
||||
$crc32 = tnef_geti32($buffer);
|
||||
$size_compressed = $buffer->geti32();
|
||||
$this->size = $buffer->geti32();
|
||||
$magic = $buffer->geti32();
|
||||
$crc32 = $buffer->geti32();
|
||||
|
||||
tnef_log("CRTF: size comp=$size_compressed, size=$this->size");
|
||||
$this->debug && tnef_log("CRTF: size comp={$size_compressed}, size={$this->size}");
|
||||
|
||||
$data = tnef_getx($buffer->getRemainingBytes(), $buffer);
|
||||
$data = $buffer->getBytes($buffer->getRemainingBytes());
|
||||
|
||||
switch ($magic) {
|
||||
case CRTF_COMPRESSED:
|
||||
|
@ -54,33 +53,33 @@ class TNEFFileRTF extends TNEFFileBase
|
|||
break;
|
||||
|
||||
default:
|
||||
tnef_log("Unknown Compressed RTF Format");
|
||||
$this->debug && tnef_log("Unknown Compressed RTF Format");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function uncompress($data)
|
||||
public function uncompress($data)
|
||||
{
|
||||
$preload = "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx";
|
||||
$length_preload = strlen($preload);
|
||||
$length_preload = \strlen($preload);
|
||||
$init_dict = [];
|
||||
for ($cnt = 0; $cnt < $length_preload; $cnt++) {
|
||||
for ($cnt = 0; $cnt < $length_preload; ++$cnt) {
|
||||
$init_dict[$cnt] = $preload[$cnt];
|
||||
}
|
||||
$init_dict = array_merge($init_dict, array_fill(count($init_dict), self::MAX_DICT_SIZE - $length_preload, ' '));
|
||||
$init_dict = \array_merge($init_dict, \array_fill(\count($init_dict), self::MAX_DICT_SIZE - $length_preload, ' '));
|
||||
$write_offset = self::INIT_DICT_SIZE;
|
||||
$this->content = '';
|
||||
$end = false;
|
||||
$in = 0;
|
||||
$l = strlen($data);
|
||||
$l = \strlen($data);
|
||||
while (!$end) {
|
||||
if ($in >= $l) {
|
||||
break;
|
||||
}
|
||||
$control = strrev(str_pad(decbin(ord($data[$in++])), 8, 0, STR_PAD_LEFT));
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
$control = \strrev(\str_pad(\decbin(\ord($data[$in++])), 8, 0, STR_PAD_LEFT));
|
||||
for ($i = 0; $i < 8; ++$i) {
|
||||
if ($control[$i] == '1') {
|
||||
$token = unpack("n", $data[$in++] . $data[$in++])[1];
|
||||
$token = \unpack("n", $data[$in++] . $data[$in++])[1];
|
||||
$offset = ($token >> 4) & 0b111111111111;
|
||||
$length = $token & 0b1111;
|
||||
if ($write_offset == $offset) {
|
||||
|
@ -88,12 +87,12 @@ class TNEFFileRTF extends TNEFFileBase
|
|||
break;
|
||||
}
|
||||
$actual_length = $length + 2;
|
||||
for ($step = 0; $step < $actual_length; $step++) {
|
||||
for ($step = 0; $step < $actual_length; ++$step) {
|
||||
$read_offset = ($offset + $step) % self::MAX_DICT_SIZE;
|
||||
$char = $init_dict[$read_offset];
|
||||
$this->content .= $char;
|
||||
$init_dict[$write_offset] = $char;
|
||||
$write_offset = ($write_offset + 1) % self::MAX_DICT_SIZE;
|
||||
$init_dict[$write_offset] = $char;
|
||||
$write_offset = ($write_offset + 1) % self::MAX_DICT_SIZE;
|
||||
}
|
||||
} else {
|
||||
if ($in >= $l) {
|
||||
|
|
|
@ -17,91 +17,89 @@
|
|||
class TNEFMailinfo
|
||||
{
|
||||
|
||||
var $subject;
|
||||
var $topic;
|
||||
var $topic_is_unicode = FALSE;
|
||||
var $from;
|
||||
var $from_is_unicode = FALSE;
|
||||
var $from_name;
|
||||
var $from_name_is_unicode = FALSE;
|
||||
var $date_sent;
|
||||
var $code_page = '';
|
||||
public string
|
||||
$subject = '',
|
||||
$topic = '',
|
||||
$from = '',
|
||||
$from_name = '',
|
||||
$code_page = '';
|
||||
public ?TNEFDate $date_sent = null;
|
||||
public bool
|
||||
$topic_is_unicode = FALSE,
|
||||
$from_is_unicode = FALSE,
|
||||
$from_name_is_unicode = FALSE;
|
||||
|
||||
|
||||
function getTopic()
|
||||
public function getTopic(): string
|
||||
{
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
function getSubject()
|
||||
public function getSubject(): string
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
function getFrom()
|
||||
public function getFrom(): string
|
||||
{
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
function getCodePage()
|
||||
public function getCodePage(): string
|
||||
{
|
||||
return $this->code_page;
|
||||
}
|
||||
|
||||
function getFromName()
|
||||
public function getFromName(): string
|
||||
{
|
||||
return $this->from_name;
|
||||
}
|
||||
|
||||
function getDateSent()
|
||||
public function getDateSent(): TNEFDate
|
||||
{
|
||||
return $this->date_sent;
|
||||
}
|
||||
|
||||
function receiveTnefAttribute($attribute, $value, $length)
|
||||
public function receiveTnefAttribute(int $attribute, string $value, int $length): void
|
||||
{
|
||||
$value = new TNEFBuffer($value);
|
||||
|
||||
switch($attribute)
|
||||
switch ($attribute)
|
||||
{
|
||||
case TNEF_AOEMCODEPAGE:
|
||||
$this->code_page = tnef_geti16($value);
|
||||
$this->code_page = $value->geti16();
|
||||
break;
|
||||
|
||||
case TNEF_ASUBJECT:
|
||||
$this->subject = tnef_getx($length - 1, $value);
|
||||
$this->subject = $value->getBytes($length - 1);
|
||||
break;
|
||||
|
||||
case TNEF_ADATERECEIVED:
|
||||
if (!$this->date_sent)
|
||||
{
|
||||
$this->date_sent = new TNEFDate();
|
||||
$this->date_sent->setTnefBuffer($value);
|
||||
if ($this->date_sent) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TNEF_ADATESENT:
|
||||
$this->date_sent = new TNEFDate();
|
||||
$this->date_sent->setTnefBuffer($value);
|
||||
}
|
||||
}
|
||||
|
||||
function receiveMapiAttribute($attr_type, $attr_name, $value, $length, $is_unicode=FALSE)
|
||||
public function receiveMapiAttribute(int $attr_type, int $attr_name, string $value, int $length): void
|
||||
{
|
||||
switch($attr_name)
|
||||
switch ($attr_name)
|
||||
{
|
||||
case TNEF_MAPI_CONVERSATION_TOPIC:
|
||||
$this->topic = $value;
|
||||
if ($is_unicode) $this->topic_is_unicode = TRUE;
|
||||
$this->topic_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_SENT_REP_EMAIL_ADDR:
|
||||
$this->from = $value;
|
||||
if ($is_unicode) $this->from_is_unicode = TRUE;
|
||||
$this->from_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_SENT_REP_NAME:
|
||||
$this->from_name = $value;
|
||||
if ($is_unicode) $this->from_name_is_unicode = TRUE;
|
||||
$this->from_name_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,285 +18,232 @@ namespace TNEFDecoder;
|
|||
|
||||
class TNEFvCard extends TNEFFileBase
|
||||
{
|
||||
|
||||
public bool $name_is_unicode = FALSE;
|
||||
public string $name = 'Untitled';
|
||||
public string $code_page = '';
|
||||
public string $message_code_page = ''; // parent message's code page (the whole TNEF file)
|
||||
public string $type = 'text/x-vcard';
|
||||
public string $content = '';
|
||||
var $metafile;
|
||||
var $surname;
|
||||
var $surname_is_unicode = FALSE;
|
||||
var $given_name;
|
||||
var $given_name_is_unicode = FALSE;
|
||||
var $middle_name;
|
||||
var $middle_name_is_unicode = FALSE;
|
||||
var $nickname;
|
||||
var $nickname_is_unicode = FALSE;
|
||||
var $company;
|
||||
var $company_is_unicode = FALSE;
|
||||
var $homepages;
|
||||
var $addresses;
|
||||
var $emails;
|
||||
var $telefones;
|
||||
|
||||
public bool
|
||||
$surname_is_unicode = FALSE,
|
||||
$given_name_is_unicode = FALSE,
|
||||
$middle_name_is_unicode = FALSE,
|
||||
$nickname_is_unicode = FALSE,
|
||||
$company_is_unicode = FALSE;
|
||||
public string
|
||||
$surname,
|
||||
$given_name,
|
||||
$middle_name,
|
||||
$nickname,
|
||||
$company,
|
||||
$metafile;
|
||||
public array
|
||||
$homepages = [],
|
||||
$addresses = [],
|
||||
$emails = [],
|
||||
$telefones = [];
|
||||
|
||||
private static
|
||||
$address_mapping = array (
|
||||
TNEF_MAPI_LOCALTY => array ("Address", ADDRESS_CITY),
|
||||
TNEF_MAPI_COUNTRY => array ("Address", ADDRESS_COUNTRY),
|
||||
TNEF_MAPI_POSTAL_CODE => array ("Address", ADDRESS_ZIP),
|
||||
TNEF_MAPI_STATE_OR_PROVINCE => array ("Address", ADDRESS_STATE),
|
||||
TNEF_MAPI_STREET_ADDRESS => array ("Address", ADDRESS_STREET),
|
||||
TNEF_MAPI_POST_OFFICE_BOX => array ("Address", ADDRESS_PO_BOX),
|
||||
TNEF_MAPI_HOME_ADDR_CITY => array ("Home Address", ADDRESS_CITY),
|
||||
TNEF_MAPI_HOME_ADDR_COUNTRY => array ("Home Address", ADDRESS_COUNTRY),
|
||||
TNEF_MAPI_HOME_ADDR_ZIP => array ("Home Address", ADDRESS_ZIP),
|
||||
TNEF_MAPI_HOME_ADDR_STATE => array ("Home Address", ADDRESS_STATE),
|
||||
TNEF_MAPI_HOME_ADDR_STREET => array ("Home Address", ADDRESS_STREET),
|
||||
TNEF_MAPI_HOME_ADDR_PO_BOX => array ("Home Address", ADDRESS_PO_BOX),
|
||||
TNEF_MAPI_OTHER_ADDR_CITY => array ("Other Address", ADDRESS_CITY),
|
||||
TNEF_MAPI_OTHER_ADDR_COUNTRY => array ("Other Address", ADDRESS_COUNTRY),
|
||||
TNEF_MAPI_OTHER_ADDR_ZIP => array ("Other Address", ADDRESS_ZIP),
|
||||
TNEF_MAPI_OTHER_ADDR_STATE => array ("Other Address", ADDRESS_STATE),
|
||||
TNEF_MAPI_OTHER_ADDR_STREET => array ("Other Address", ADDRESS_STREET),
|
||||
TNEF_MAPI_OTHER_ADDR_PO_BOX => array ("Other Address", ADDRESS_PO_BOX),
|
||||
TNEF_MAPI_LOCALTY => array ("Address", ADDRESS_CITY),
|
||||
TNEF_MAPI_COUNTRY => array ("Address", ADDRESS_COUNTRY),
|
||||
TNEF_MAPI_POSTAL_CODE => array ("Address", ADDRESS_ZIP),
|
||||
TNEF_MAPI_STATE_OR_PROVINCE => array ("Address", ADDRESS_STATE),
|
||||
TNEF_MAPI_STREET_ADDRESS => array ("Address", ADDRESS_STREET),
|
||||
TNEF_MAPI_POST_OFFICE_BOX => array ("Address", ADDRESS_PO_BOX),
|
||||
TNEF_MAPI_HOME_ADDR_CITY => array ("Home Address", ADDRESS_CITY),
|
||||
TNEF_MAPI_HOME_ADDR_COUNTRY => array ("Home Address", ADDRESS_COUNTRY),
|
||||
TNEF_MAPI_HOME_ADDR_ZIP => array ("Home Address", ADDRESS_ZIP),
|
||||
TNEF_MAPI_HOME_ADDR_STATE => array ("Home Address", ADDRESS_STATE),
|
||||
TNEF_MAPI_HOME_ADDR_STREET => array ("Home Address", ADDRESS_STREET),
|
||||
TNEF_MAPI_HOME_ADDR_PO_BOX => array ("Home Address", ADDRESS_PO_BOX),
|
||||
TNEF_MAPI_OTHER_ADDR_CITY => array ("Other Address", ADDRESS_CITY),
|
||||
TNEF_MAPI_OTHER_ADDR_COUNTRY => array ("Other Address", ADDRESS_COUNTRY),
|
||||
TNEF_MAPI_OTHER_ADDR_ZIP => array ("Other Address", ADDRESS_ZIP),
|
||||
TNEF_MAPI_OTHER_ADDR_STATE => array ("Other Address", ADDRESS_STATE),
|
||||
TNEF_MAPI_OTHER_ADDR_STREET => array ("Other Address", ADDRESS_STREET),
|
||||
TNEF_MAPI_OTHER_ADDR_PO_BOX => array ("Other Address", ADDRESS_PO_BOX),
|
||||
),
|
||||
$email_mapping = array (
|
||||
TNEF_MAPI_EMAIL1_DISPLAY => array ("Email 1", EMAIL_DISPLAY),
|
||||
TNEF_MAPI_EMAIL1_TRANSPORT => array ("Email 1", EMAIL_TRANSPORT),
|
||||
TNEF_MAPI_EMAIL1_EMAIL => array ("Email 1", EMAIL_EMAIL),
|
||||
TNEF_MAPI_EMAIL1_EMAIL2 => array ("Email 1", EMAIL_EMAIL2),
|
||||
TNEF_MAPI_EMAIL2_DISPLAY => array ("Email 2", EMAIL_DISPLAY),
|
||||
TNEF_MAPI_EMAIL2_TRANSPORT => array ("Email 2", EMAIL_TRANSPORT),
|
||||
TNEF_MAPI_EMAIL2_EMAIL => array ("Email 2", EMAIL_EMAIL),
|
||||
TNEF_MAPI_EMAIL2_EMAIL2 => array ("Email 2", EMAIL_EMAIL2),
|
||||
TNEF_MAPI_EMAIL3_DISPLAY => array ("Email 3", EMAIL_DISPLAY),
|
||||
TNEF_MAPI_EMAIL3_TRANSPORT => array ("Email 3", EMAIL_TRANSPORT),
|
||||
TNEF_MAPI_EMAIL3_EMAIL => array ("Email 3", EMAIL_EMAIL),
|
||||
TNEF_MAPI_EMAIL3_EMAIL2 => array ("Email 3", EMAIL_EMAIL2),
|
||||
TNEF_MAPI_EMAIL1_DISPLAY => array ("Email 1", EMAIL_DISPLAY),
|
||||
TNEF_MAPI_EMAIL1_TRANSPORT => array ("Email 1", EMAIL_TRANSPORT),
|
||||
TNEF_MAPI_EMAIL1_EMAIL => array ("Email 1", EMAIL_EMAIL),
|
||||
TNEF_MAPI_EMAIL1_EMAIL2 => array ("Email 1", EMAIL_EMAIL2),
|
||||
TNEF_MAPI_EMAIL2_DISPLAY => array ("Email 2", EMAIL_DISPLAY),
|
||||
TNEF_MAPI_EMAIL2_TRANSPORT => array ("Email 2", EMAIL_TRANSPORT),
|
||||
TNEF_MAPI_EMAIL2_EMAIL => array ("Email 2", EMAIL_EMAIL),
|
||||
TNEF_MAPI_EMAIL2_EMAIL2 => array ("Email 2", EMAIL_EMAIL2),
|
||||
TNEF_MAPI_EMAIL3_DISPLAY => array ("Email 3", EMAIL_DISPLAY),
|
||||
TNEF_MAPI_EMAIL3_TRANSPORT => array ("Email 3", EMAIL_TRANSPORT),
|
||||
TNEF_MAPI_EMAIL3_EMAIL => array ("Email 3", EMAIL_EMAIL),
|
||||
TNEF_MAPI_EMAIL3_EMAIL2 => array ("Email 3", EMAIL_EMAIL2),
|
||||
),
|
||||
$homepage_mapping = array (
|
||||
TNEF_MAPI_PERSONAL_HOME_PAGE => "Personal Homepage",
|
||||
TNEF_MAPI_BUSINESS_HOME_PAGE => "Business Homepage",
|
||||
TNEF_MAPI_OTHER_HOME_PAGE => "Other Homepage",
|
||||
TNEF_MAPI_PERSONAL_HOME_PAGE => "Personal Homepage",
|
||||
TNEF_MAPI_BUSINESS_HOME_PAGE => "Business Homepage",
|
||||
TNEF_MAPI_OTHER_HOME_PAGE => "Other Homepage",
|
||||
),
|
||||
$telefone_mapping = array (
|
||||
TNEF_MAPI_PRIMARY_TEL_NUMBER => "Primary Telefone",
|
||||
TNEF_MAPI_HOME_TEL_NUMBER => "Home Telefone",
|
||||
TNEF_MAPI_HOME2_TEL_NUMBER => "Home2 Telefone",
|
||||
TNEF_MAPI_BUSINESS_TEL_NUMBER => "Business Telefone",
|
||||
TNEF_MAPI_BUSINESS2_TEL_NUMBER => "Business2 Telefone",
|
||||
TNEF_MAPI_MOBILE_TEL_NUMBER => "Mobile Telefone",
|
||||
TNEF_MAPI_RADIO_TEL_NUMBER => "Radio Telefone",
|
||||
TNEF_MAPI_CAR_TEL_NUMBER => "Car Telefone",
|
||||
TNEF_MAPI_OTHER_TEL_NUMBER => "Other Telefone",
|
||||
TNEF_MAPI_PAGER_TEL_NUMBER => "Pager Telefone",
|
||||
TNEF_MAPI_PRIMARY_FAX_NUMBER => "Primary Fax",
|
||||
TNEF_MAPI_BUSINESS_FAX_NUMBER => "Business Fax",
|
||||
TNEF_MAPI_HOME_FAX_NUMBER => "Home Fax",
|
||||
TNEF_MAPI_PRIMARY_TEL_NUMBER => "Primary Telefone",
|
||||
TNEF_MAPI_HOME_TEL_NUMBER => "Home Telefone",
|
||||
TNEF_MAPI_HOME2_TEL_NUMBER => "Home2 Telefone",
|
||||
TNEF_MAPI_BUSINESS_TEL_NUMBER => "Business Telefone",
|
||||
TNEF_MAPI_BUSINESS2_TEL_NUMBER => "Business2 Telefone",
|
||||
TNEF_MAPI_MOBILE_TEL_NUMBER => "Mobile Telefone",
|
||||
TNEF_MAPI_RADIO_TEL_NUMBER => "Radio Telefone",
|
||||
TNEF_MAPI_CAR_TEL_NUMBER => "Car Telefone",
|
||||
TNEF_MAPI_OTHER_TEL_NUMBER => "Other Telefone",
|
||||
TNEF_MAPI_PAGER_TEL_NUMBER => "Pager Telefone",
|
||||
TNEF_MAPI_PRIMARY_FAX_NUMBER => "Primary Fax",
|
||||
TNEF_MAPI_BUSINESS_FAX_NUMBER => "Business Fax",
|
||||
TNEF_MAPI_HOME_FAX_NUMBER => "Home Fax",
|
||||
);
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->telefones = array();
|
||||
$this->homepages = array();
|
||||
$this->emails = array();
|
||||
$this->addresses = array();
|
||||
}
|
||||
|
||||
function getSurname()
|
||||
public function getSurname(): string
|
||||
{
|
||||
return $this->surname;
|
||||
}
|
||||
|
||||
function getGivenName()
|
||||
public function getGivenName(): string
|
||||
{
|
||||
return $this->given_name;
|
||||
}
|
||||
|
||||
function getMiddleName()
|
||||
public function getMiddleName(): string
|
||||
{
|
||||
return $this->middle_name;
|
||||
}
|
||||
|
||||
function getNickname()
|
||||
public function getNickname(): string
|
||||
{
|
||||
return $this->nickname;
|
||||
}
|
||||
|
||||
function getCompany()
|
||||
public function getCompany(): string
|
||||
{
|
||||
return $this->company;
|
||||
}
|
||||
|
||||
function getAddresses()
|
||||
public function getAddresses(): array
|
||||
{
|
||||
return $this->addresses;
|
||||
}
|
||||
|
||||
function getMetafile()
|
||||
public function getMetafile()
|
||||
{
|
||||
return $this->metafile;
|
||||
}
|
||||
|
||||
function getTelefones()
|
||||
public function getTelefones(): array
|
||||
{
|
||||
return $this->telefones;
|
||||
}
|
||||
|
||||
function getHomepages()
|
||||
public function getHomepages(): array
|
||||
{
|
||||
return $this->homepages;
|
||||
}
|
||||
|
||||
function getEmails()
|
||||
public function getEmails(): array
|
||||
{
|
||||
return $this->emails;
|
||||
}
|
||||
|
||||
function receiveTnefAttribute($attribute, $value, $length)
|
||||
public function receiveTnefAttribute(int $attribute, string $value, int $length): void
|
||||
{
|
||||
switch ($attribute)
|
||||
{
|
||||
|
||||
// code page
|
||||
//
|
||||
case TNEF_AOEMCODEPAGE:
|
||||
$this->code_page = tnef_geti16(new TNEFBuffer($value));
|
||||
$this->code_page = (new TNEFBuffer($value))->geti16();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function receiveMapiAttribute($attr_type, $attr_name, $value, $length, $is_unicode=FALSE)
|
||||
public function receiveMapiAttribute(int $attr_type, int $attr_name, string $value, int $length)
|
||||
{
|
||||
switch($attr_name)
|
||||
switch ($attr_name)
|
||||
{
|
||||
case TNEF_MAPI_DISPLAY_NAME:
|
||||
$this->name = $value;
|
||||
|
||||
if ($is_unicode) $this->name_is_unicode = TRUE;
|
||||
|
||||
$this->name_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_SURNAME:
|
||||
$this->surname = $value;
|
||||
|
||||
if ($is_unicode) $this->surname_is_unicode = TRUE;
|
||||
|
||||
$this->surname_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_GIVEN_NAME:
|
||||
$this->given_name = $value;
|
||||
|
||||
if ($is_unicode) $this->given_name_is_unicode = TRUE;
|
||||
|
||||
$this->given_name_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_MIDDLE_NAME:
|
||||
$this->middle_name = $value;
|
||||
|
||||
if ($is_unicode) $this->middle_name_is_unicode = TRUE;
|
||||
|
||||
$this->middle_name_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_NICKNAME:
|
||||
$this->nickname = $value;
|
||||
|
||||
if ($is_unicode) $this->nickname_is_unicode = TRUE;
|
||||
|
||||
$this->nickname_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
case TNEF_MAPI_COMPANY_NAME:
|
||||
$this->company = $value;
|
||||
|
||||
if ($is_unicode) $this->company_is_unicode = TRUE;
|
||||
|
||||
$this->company_is_unicode = TNEF_MAPI_UNICODE_STRING === $attr_type;
|
||||
break;
|
||||
|
||||
default:
|
||||
$rc = $this->evaluateTelefoneAttribute($attr_type, $attr_name, $value, $length);
|
||||
if (!$rc)
|
||||
$rc = $this->evaluateEmailAttribute($attr_type, $attr_name, $value, $length);
|
||||
if (!$rc)
|
||||
$rc = $this->evaluateAddressAttribute($attr_type, $attr_name, $value, $length);
|
||||
if (!$rc)
|
||||
$rc = $this->evaluateHomepageAttribute($attr_type, $attr_name, $value, $length);
|
||||
$this->evaluateTelefoneAttribute($attr_type, $attr_name, $value, $length)
|
||||
|| $this->evaluateEmailAttribute($attr_type, $attr_name, $value, $length)
|
||||
|| $this->evaluateAddressAttribute($attr_type, $attr_name, $value, $length)
|
||||
|| $this->evaluateHomepageAttribute($attr_type, $attr_name, $value, $length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateTelefoneAttribute($attr_type, $attr_name, $value, $length)
|
||||
private function evaluateTelefoneAttribute(int $attr_type, int $attr_name, string $value, int $length): bool
|
||||
{
|
||||
$rc = 0;
|
||||
|
||||
if ($length > 0)
|
||||
{
|
||||
if (array_key_exists($attr_name, static::$telefone_mapping))
|
||||
{
|
||||
$telefone_key = static::$telefone_mapping[$attr_name];
|
||||
$this->telefones[$telefone_key] = $value;
|
||||
$rc = 1;
|
||||
tnef_log("Setting telefone '$telefone_key' to value '$value'");
|
||||
}
|
||||
if ($length && \array_key_exists($attr_name, static::$telefone_mapping)) {
|
||||
$telefone_key = static::$telefone_mapping[$attr_name];
|
||||
$this->telefones[$telefone_key] = $value;
|
||||
$this->debug && tnef_log("Setting telefone '{$telefone_key}' to value '{$value}'");
|
||||
return true;
|
||||
}
|
||||
|
||||
return $rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
function evaluateEmailAttribute($attr_type, $attr_name, $value, $length)
|
||||
private function evaluateEmailAttribute(int $attr_type, int $attr_name, string $value, int $length): bool
|
||||
{
|
||||
$rc = 0;
|
||||
|
||||
if ($length > 0)
|
||||
{
|
||||
if (array_key_exists($attr_name, static::$email_mapping))
|
||||
{
|
||||
$email_key = static::$email_mapping[$attr_name];
|
||||
if (!array_key_exists($email_key[0], $this->emails))
|
||||
$this->emails[$email_key[0]] = array ( EMAIL_DISPLAY => "", EMAIL_TRANSPORT => "", EMAIL_EMAIL => "", EMAIL_EMAIL2 => "");
|
||||
$this->emails[$email_key[0]][$email_key[1]] = $value;
|
||||
}
|
||||
if ($length && \array_key_exists($attr_name, static::$email_mapping)) {
|
||||
$email_key = static::$email_mapping[$attr_name];
|
||||
if (!\array_key_exists($email_key[0], $this->emails))
|
||||
$this->emails[$email_key[0]] = array(EMAIL_DISPLAY => "", EMAIL_TRANSPORT => "", EMAIL_EMAIL => "", EMAIL_EMAIL2 => "");
|
||||
$this->emails[$email_key[0]][$email_key[1]] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return $rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
function evaluateAddressAttribute($attr_type, $attr_name, $value, $length)
|
||||
private function evaluateAddressAttribute(int $attr_type, int $attr_name, string $value, int $length): bool
|
||||
{
|
||||
$rc = 0;
|
||||
|
||||
if ($length > 0)
|
||||
{
|
||||
if (array_key_exists($attr_name, static::$address_mapping))
|
||||
{
|
||||
$address_key = static::$address_mapping[$attr_name];
|
||||
if (!array_key_exists($address_key[0], $this->addresses))
|
||||
$this->addresses[$address_key[0]] = array ( );
|
||||
$this->addresses[$address_key[0]][$address_key[1]] = $value;
|
||||
}
|
||||
if ($length && \array_key_exists($attr_name, static::$address_mapping)) {
|
||||
$address_key = static::$address_mapping[$attr_name];
|
||||
if (!\array_key_exists($address_key[0], $this->addresses))
|
||||
$this->addresses[$address_key[0]] = array();
|
||||
$this->addresses[$address_key[0]][$address_key[1]] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return $rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
function evaluateHomepageAttribute($attr_type, $attr_name, $value, $length)
|
||||
private function evaluateHomepageAttribute(int $attr_type, int $attr_name, string $value, int $length): bool
|
||||
{
|
||||
$rc = 0;
|
||||
|
||||
if ($length > 0)
|
||||
{
|
||||
if (array_key_exists($attr_name, static::$homepage_mapping))
|
||||
{
|
||||
$homepage_key = static::$homepage_mapping[$attr_name];
|
||||
$this->homepages[$homepage_key] = $value;
|
||||
$rc = 1;
|
||||
tnef_log("Setting homepage '$homepage_key' to value '$value'");
|
||||
}
|
||||
if ($length && \array_key_exists($attr_name, static::$homepage_mapping)) {
|
||||
$homepage_key = static::$homepage_mapping[$attr_name];
|
||||
$this->homepages[$homepage_key] = $value;
|
||||
$this->debug && tnef_log("Setting homepage '{$homepage_key}' to value '{$value}'");
|
||||
return true;
|
||||
}
|
||||
|
||||
return $rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -194,7 +194,6 @@ define ("EMAIL_DISPLAY", 1);
|
|||
define ("EMAIL_TRANSPORT", 2);
|
||||
define ("EMAIL_EMAIL", 3);
|
||||
define ("EMAIL_EMAIL2", 4);
|
||||
|
||||
define ("ADDRESS_STREET", "Street");
|
||||
define ("ADDRESS_ZIP", "Zip");
|
||||
define ("ADDRESS_CITY", "City");
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
<?php namespace TNEFDecoder;
|
||||
|
||||
/**
|
||||
* SquirrelMail TNEF Decoder Plugin
|
||||
*
|
||||
* Copyright (c) 2010- Paul Lesniewski <paul@squirrelmail.org>
|
||||
* Copyright (c) 2003 Bernd Wiegmann <bernd@wib-software.de>
|
||||
* Copyright (c) 2002 Graham Norburys <gnorbury@bondcar.com>
|
||||
*
|
||||
* Licensed under the GNU GPL. For full terms see the file COPYING.
|
||||
*
|
||||
* @package plugins
|
||||
* @subpackage tnef_decoder
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Debugging output --> to a file (/tmp/squirrelmail_tnef_decoder.log)
|
||||
*
|
||||
* Note this assumes a world-writable /tmp directory
|
||||
*
|
||||
* @param string $string The text to be logged
|
||||
*
|
||||
* @return boolean TRUE on success, FALSE when a problem occurred
|
||||
*
|
||||
*/
|
||||
function tnef_log($string)
|
||||
{
|
||||
\SnappyMail\Log::debug('TNEF', $string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TNEF decoding helper function
|
||||
*
|
||||
*/
|
||||
function tnef_getx($size, TNEFBuffer $buf)
|
||||
{
|
||||
return $buf->getBytes($size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TNEF decoding helper function
|
||||
*
|
||||
*/
|
||||
function tnef_geti8(TNEFBuffer $buf)
|
||||
{
|
||||
$bytes = $buf->getBytes(1, $buf);
|
||||
if ($bytes === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ord($bytes[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TNEF decoding helper function
|
||||
*
|
||||
*/
|
||||
function tnef_geti16(TNEFBuffer $buf): ?int
|
||||
{
|
||||
$bytes = $buf->getBytes(2, $buf);
|
||||
if ($bytes === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ord($bytes[0])
|
||||
+ (ord($bytes[1]) << 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TNEF decoding helper function
|
||||
*
|
||||
*/
|
||||
function tnef_geti32(TNEFBuffer $buf): ?int
|
||||
{
|
||||
$bytes = $buf->getBytes(4, $buf);
|
||||
if ($bytes === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ord($bytes[0])
|
||||
+ (ord($bytes[1]) << 8)
|
||||
+ (ord($bytes[2]) << 16)
|
||||
+ (ord($bytes[3]) << 24);
|
||||
}
|
Loading…
Reference in a new issue