1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19: class Horde_Compress_Dbx extends Horde_Compress_Base
20: {
21: 22:
23: public $canDecompress = true;
24:
25: 26: 27: 28: 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: 53: 54: 55:
56: protected $_mails = array();
57:
58: 59: 60: 61: 62:
63: protected $_tmp = array();
64:
65: 66: 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:
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: 89: 90: 91: 92: 93: 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: 104: 105: 106: 107: 108: 109: 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: 144: 145: 146: 147: 148: 149: 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:
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: 227: 228: 229: 230: 231: 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:
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: