Overview

Packages

  • Compress

Classes

  • Horde_Compress
  • Horde_Compress_Base
  • Horde_Compress_Dbx
  • Horde_Compress_Exception
  • Horde_Compress_Gzip
  • Horde_Compress_Rar
  • Horde_Compress_Tar
  • Horde_Compress_Tnef
  • Horde_Compress_Translation
  • Horde_Compress_Zip
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * This class allows dbx files (e.g. from Outlook Express) to be read.
  4:  *
  5:  * This class is based on code by:
  6:  * Antony Raijekov <dev@strategma.bg>
  7:  * http://uruds.gateway.bg/zeos/
  8:  *
  9:  * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
 10:  *
 11:  * See the enclosed file COPYING for license information (LGPL). If you
 12:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 13:  *
 14:  * @author   Jan Schneider <jan@horde.org>
 15:  * @category Horde
 16:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 17:  * @package  Compress
 18:  */
 19: class Horde_Compress_Dbx extends Horde_Compress_Base
 20: {
 21:     /**
 22:      */
 23:     public $canDecompress = true;
 24: 
 25:     /**
 26:      * TODO
 27:      *
 28:      * @var array
 29:      */
 30:     protected $_flagArray = array(
 31:         0x1 => 'MsgFlags',
 32:         0x2 => 'Sent',
 33:         0x4 => 'position',
 34:         0x7 => 'MessageID',
 35:         0x8 => 'Subject',
 36:         0x9 => 'From_reply',
 37:         0xA => 'References',
 38:         0xB => 'Newsgroup',
 39:         0xD => 'From',
 40:         0xE => 'Reply_To',
 41:         0x12 => 'Received',
 42:         0x13 => 'Receipt',
 43:         0x1A => 'Account',
 44:         0x1B => 'AccountID',
 45:         0x80 => 'Msg',
 46:         0x81 => 'MsgFlags',
 47:         0x84 => 'position',
 48:         0x91 => 'size',
 49:     );
 50: 
 51:     /**
 52:      * TODO
 53:      *
 54:      * @var array
 55:      */
 56:     protected $_mails = array();
 57: 
 58:     /**
 59:      * TODO
 60:      *
 61:      * @var array
 62:      */
 63:     protected $_tmp = array();
 64: 
 65:     /**
 66:      * @return array  List of messages.
 67:      */
 68:     public function decompress($data, array $params = array())
 69:     {
 70:         $this->_mails = $this->_tmp = array();
 71: 
 72:         $position = 0xC4;
 73:         $header_info = unpack('Lposition/LDataLength/nHeaderLength/nFlagCount', substr($data, $position, 12));
 74:         $position += 12;
 75: 
 76:         // Go to the first table offest and process it.
 77:         if ($header_info['position'] > 0) {
 78:             $position = 0x30;
 79:             $buf = unpack('Lposition', substr($data, $position, 4));
 80:             $position = $buf['position'];
 81:             $result = $this->_readIndex($data, $position);
 82:         }
 83: 
 84:         return $this->_mails;
 85:     }
 86: 
 87:     /**
 88:      * Returns a null-terminated string from the specified data.
 89:      *
 90:      * @param string $buf   TODO
 91:      * @param integer $pos  TODO
 92:      *
 93:      * @return string  TODO
 94:      */
 95:     protected function _readString($buf, $pos)
 96:     {
 97:         return ($len = strpos(substr($buf, $pos), chr(0)))
 98:             ? substr($buf, $pos, $len)
 99:             : '';
100:     }
101: 
102:     /**
103:      * TODO
104:      *
105:      * @param string $data       TODO
106:      * @param integer $position  TODO
107:      *
108:      * @return string  TODO
109:      * @throws Horde_Compress_Exception
110:      */
111:     protected function _readMessage($data, $position)
112:     {
113:         $msg = '';
114:         $part = 0;
115: 
116:         if ($position > 0) {
117:             $IndexItemsCount = array_pop(unpack('S', substr($data, 0xC4, 4)));
118:             if ($IndexItemsCount > 0) {
119:                 while ($position < strlen($data)) {
120:                     $part++;
121:                     $s = substr($data, $position, 528);
122:                     if (strlen($s) == 0) {
123:                         break;
124:                     }
125:                     $msg_item = unpack('LFilePos/LUnknown/LItemSize/LNextItem/a512Content', $s);
126:                     if ($msg_item['FilePos'] != $position) {
127:                         throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format"));
128:                     }
129:                     $position += 528;
130:                     $msg .= substr($msg_item['Content'], 0, $msg_item['ItemSize']);
131:                     $position = $msg_item['NextItem'];
132:                     if ($position == 0) {
133:                         break;
134:                     }
135:                 }
136:             }
137:         }
138: 
139:         return $msg;
140:     }
141: 
142:     /**
143:      * TODO
144:      *
145:      * @param string $data       TODO
146:      * @param integer $position  TODO
147:      *
148:      * @return array  TODO
149:      * @throws Horde_Compress_Exception
150:      */
151:     protected function _readMessageInfo($data, $position)
152:     {
153:         $message_info = array();
154:         $msg_header = unpack('Lposition/LDataLength/SHeaderLength/SFlagCount', substr($data, $position, 12));
155:         if ($msg_header['position'] != $position) {
156:             throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format"));
157:         }
158:         $position += 12;
159:         $message_info['HeaderPosition'] = $msg_header['position'];
160:         $flags = $msg_header['FlagCount'] & 0xFF;
161:         $DataSize = $msg_header['DataLength'] - $flags * 4;
162:         $size = 4 * $flags;
163:         $FlagsBuffer = substr($data, $position, $size);
164:         $position += $size;
165:         $size = $DataSize;
166:         $DataBuffer = substr($data, $position, $size);
167:         $position += $size;
168:         $message_info = array();
169: 
170:         /* Process flags */
171:         for ($i = 0; $i < $flags; ++$i) {
172:             $pos = 0;
173:             $f = array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4)));
174: 
175:             $mask = $f & 0xFF;
176:             switch ($mask) {
177:             case 0x1:
178:                 $pos = $pos + ($f >> 8);
179:                 $message_info['MsgFlags'] = array_pop(unpack('C', substr($DataBuffer, $pos++, 1)));
180:                 $message_info['MsgFlags'] += array_pop(unpack('C', substr($DataBuffer, $pos++, 1))) * 256;
181:                 $message_info['MsgFlags'] += array_pop(unpack('C', substr($DataBuffer, $pos, 1))) * 65536;
182:                 break;
183: 
184:             case 0x2:
185:             case 0x4:
186:                 $pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
187:                 $message_info[$this->_flagArray[$mask]] = array_pop(unpack('L', substr($DataBuffer, $pos, 4)));
188:                 break;
189: 
190:             case 0x7:
191:             case 0x8:
192:             case 0x9:
193:             case 0xA:
194:             case 0xB:
195:             case 0xD:
196:             case 0xE:
197:             case 0x13:
198:             case 0x1A:
199:                 $pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
200:                 $message_info[$this->_flagArray[$mask]] = $this->_readString($DataBuffer, $pos);
201:                 break;
202: 
203:             case 0x12:
204:                 $pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
205:                 $message_info['Received'] = array_pop(unpack('L', substr($DataBuffer, $pos, 4)));
206:                 break;
207: 
208:             case 0x1B:
209:                 $pos += array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
210:                 $message_info['AccountID'] = intval($this->_readString($DataBuffer, $pos));
211:                 break;
212: 
213:             case 0x80:
214:             case 0x81:
215:             case 0x84:
216:             case 0x91:
217:                 $message_info[$this->_flagArray[$mask]] = array_pop(unpack('L', substr($FlagsBuffer, $i * 4, 4))) >> 8;
218:                 break;
219:             }
220:         }
221: 
222:         return $message_info;
223:     }
224: 
225:     /**
226:      * TODO
227:      *
228:      * @param string $data       TODO
229:      * @param integer $position  TODO
230:      *
231:      * @throws Horde_Compress_Exception
232:      */
233:     protected function _readIndex($data, $position)
234:     {
235:         $index_header = unpack('LFilePos/LUnknown1/LPrevIndex/LNextIndex/LCount/LUnknown', substr($data, $position, 24));
236:         if ($index_header['FilePos'] != $position) {
237:             throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format"));
238:         }
239: 
240:         // Push it into list of processed items.
241:         $this->_tmp[$position] = true;
242:         if (($index_header['NextIndex'] > 0) &&
243:             empty($this->_tmp[$index_header['NextIndex']])) {
244:             $this->_readIndex($data, $index_header['NextIndex']);
245:         }
246:         if (($index_header['PrevIndex'] > 0) &&
247:             empty($this->_tmp[$index_header['PrevIndex']])) {
248:             $this->_readIndex($data, $index_header['PrevIndex']);
249:         }
250:         $position += 24;
251:         $icount = $index_header['Count'] >> 8;
252:         if ($icount > 0) {
253:             $buf = substr($data, $position, 12 * $icount);
254:             for ($i = 0; $i < $icount; $i++) {
255:                 $hdr_buf = substr($buf, $i * 12, 12);
256:                 $IndexItem = unpack('LHeaderPos/LChildIndex/LUnknown', $hdr_buf);
257:                 if ($IndexItem['HeaderPos'] > 0) {
258:                     $mail['info'] = $this->_readMessageInfo($data, $IndexItem['HeaderPos']);
259:                     $mail['content'] = $this->_readMessage($data, $mail['info']['position']);
260:                     $this->_mails[] = $mail;
261:                 }
262:                 if (($IndexItem['ChildIndex'] > 0) &&
263:                     empty($this->_tmp[$IndexItem['ChildIndex']])) {
264:                     $this->_readIndex($data, $IndexItem['ChildIndex']);
265:                 }
266:             }
267:         }
268:     }
269: 
270: }
271: 
API documentation generated by ApiGen