Files
server/usr/share/psa-pear/pear/php/Horde/Compress/Dbx.php
2026-01-07 20:52:11 +01:00

283 lines
8.9 KiB
PHP

<?php
/**
* Copyright 2003-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* This class is based on code by:
* Antony Raijekov <dev@strategma.bg>
* http://uruds.gateway.bg/zeos/
*
* @author Jan Schneider <jan@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
/**
* This class allows dbx files (e.g. from Outlook Express) to be read.
*
* @author Jan Schneider <jan@horde.org>
* @category Horde
* @copyright 2003-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress_Dbx extends Horde_Compress_Base
{
/**
*/
public $canDecompress = true;
/**
* TODO
*
* @var array
*/
protected $_flagArray = array(
0x1 => 'MsgFlags',
0x2 => 'Sent',
0x4 => 'position',
0x7 => 'MessageID',
0x8 => 'Subject',
0x9 => 'From_reply',
0xA => 'References',
0xB => 'Newsgroup',
0xD => 'From',
0xE => 'Reply_To',
0x12 => 'Received',
0x13 => 'Receipt',
0x1A => 'Account',
0x1B => 'AccountID',
0x80 => 'Msg',
0x81 => 'MsgFlags',
0x84 => 'position',
0x91 => 'size',
);
/**
* TODO
*
* @var array
*/
protected $_mails = array();
/**
* TODO
*
* @var array
*/
protected $_tmp = array();
/**
* @return array List of messages.
*/
public function decompress($data, array $params = array())
{
$this->_mails = $this->_tmp = array();
$position = 0xC4;
$header_info = unpack('Lposition/LDataLength/nHeaderLength/nFlagCount', substr($data, $position, 12));
$position += 12;
// Go to the first table offest and process it.
if ($header_info['position'] > 0) {
$position = 0x30;
$buf = unpack('Lposition', substr($data, $position, 4));
$position = $buf['position'];
$this->_readIndex($data, $position);
}
return $this->_mails;
}
/**
* Returns a null-terminated string from the specified data.
*
* @param string $buf TODO
* @param integer $pos TODO
*
* @return string TODO
*/
protected function _readString($buf, $pos)
{
return ($len = strpos(substr($buf, $pos), chr(0)))
? substr($buf, $pos, $len)
: '';
}
/**
* TODO
*
* @param string $data TODO
* @param integer $position TODO
*
* @return string TODO
* @throws Horde_Compress_Exception
*/
protected function _readMessage($data, $position)
{
$msg = '';
$part = 0;
if ($position > 0) {
$IndexItemsCount = array_pop(unpack('S', substr($data, 0xC4, 4)));
if ($IndexItemsCount > 0) {
while ($position < strlen($data)) {
$part++;
$s = substr($data, $position, 528);
if (strlen($s) == 0) {
break;
}
if (version_compare(PHP_VERSION, '5.5', '>=')) {
$msg_item = unpack('LFilePos/LUnknown/LItemSize/LNextItem/Z512Content', $s);
} else {
$msg_item = unpack('LFilePos/LUnknown/LItemSize/LNextItem/a512Content', $s);
}
if ($msg_item['FilePos'] != $position) {
throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format"));
}
$position += 528;
$msg .= substr($msg_item['Content'], 0, $msg_item['ItemSize']);
$position = $msg_item['NextItem'];
if ($position == 0) {
break;
}
}
}
}
return $msg;
}
/**
* TODO
*
* @param string $data TODO
* @param integer $position TODO
*
* @return array TODO
* @throws Horde_Compress_Exception
*/
protected function _readMessageInfo($data, $position)
{
$message_info = array();
$msg_header = unpack('Lposition/LDataLength/SHeaderLength/SFlagCount', substr($data, $position, 12));
if ($msg_header['position'] != $position) {
throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format"));
}
$position += 12;
$message_info['HeaderPosition'] = $msg_header['position'];
$flags = $msg_header['FlagCount'] & 0xFF;
$DataSize = $msg_header['DataLength'] - $flags * 4;
$size = 4 * $flags;
$FlagsBuffer = substr($data, $position, $size);
$position += $size;
$size = $DataSize;
$DataBuffer = substr($data, $position, $size);
$position += $size;
$message_info = array();
/* Process flags */
for ($i = 0; $i < $flags; ++$i) {
$pos = 0;
$f = array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4)));
$mask = $f & 0xFF;
switch ($mask) {
case 0x1:
$pos = $pos + ($f >> 8);
$message_info['MsgFlags'] = array_pop(unpack('C', substr($DataBuffer, $pos++, 1)));
$message_info['MsgFlags'] += array_pop(unpack('C', substr($DataBuffer, $pos++, 1))) * 256;
$message_info['MsgFlags'] += array_pop(unpack('C', substr($DataBuffer, $pos, 1))) * 65536;
break;
case 0x2:
case 0x4:
$pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
$message_info[$this->_flagArray[$mask]] = array_pop(unpack('L', substr($DataBuffer, $pos, 4)));
break;
case 0x7:
case 0x8:
case 0x9:
case 0xA:
case 0xB:
case 0xD:
case 0xE:
case 0x13:
case 0x1A:
$pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
$message_info[$this->_flagArray[$mask]] = $this->_readString($DataBuffer, $pos);
break;
case 0x12:
$pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
$message_info['Received'] = array_pop(unpack('L', substr($DataBuffer, $pos, 4)));
break;
case 0x1B:
$pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
$message_info['AccountID'] = intval($this->_readString($DataBuffer, $pos));
break;
case 0x80:
case 0x81:
case 0x84:
case 0x91:
$message_info[$this->_flagArray[$mask]] = array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
break;
}
}
return $message_info;
}
/**
* TODO
*
* @param string $data TODO
* @param integer $position TODO
*
* @throws Horde_Compress_Exception
*/
protected function _readIndex($data, $position)
{
$index_header = unpack('LFilePos/LUnknown1/LPrevIndex/LNextIndex/LCount/LUnknown', substr($data, $position, 24));
if ($index_header['FilePos'] != $position) {
throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format"));
}
// Push it into list of processed items.
$this->_tmp[$position] = true;
if (($index_header['NextIndex'] > 0) &&
empty($this->_tmp[$index_header['NextIndex']])) {
$this->_readIndex($data, $index_header['NextIndex']);
}
if (($index_header['PrevIndex'] > 0) &&
empty($this->_tmp[$index_header['PrevIndex']])) {
$this->_readIndex($data, $index_header['PrevIndex']);
}
$position += 24;
$icount = $index_header['Count'] >> 8;
if ($icount > 0) {
$buf = substr($data, $position, 12 * $icount);
for ($i = 0; $i < $icount; $i++) {
$hdr_buf = substr($buf, $i * 12, 12);
$IndexItem = unpack('LHeaderPos/LChildIndex/LUnknown', $hdr_buf);
if ($IndexItem['HeaderPos'] > 0) {
$mail['info'] = $this->_readMessageInfo($data, $IndexItem['HeaderPos']);
$mail['content'] = $this->_readMessage($data, $mail['info']['position']);
$this->_mails[] = $mail;
}
if (($IndexItem['ChildIndex'] > 0) &&
empty($this->_tmp[$IndexItem['ChildIndex']])) {
$this->_readIndex($data, $IndexItem['ChildIndex']);
}
}
}
}
}