Improved TNEFDecoder

This commit is contained in:
the-djmaze 2024-03-10 18:02:38 +01:00
parent d498bf2b53
commit 913ed54668
11 changed files with 406 additions and 550 deletions

View file

@ -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;

View file

@ -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));
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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");

View file

@ -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);
}