source: contrib/z-push/include/z_tnef.php @ 4898

Revision 4898, 27.0 KB checked in by thiagoaos, 13 years ago (diff)

Ticket #2180 - Adicionado código fonte completo do zpush

Line 
1<?php
2/***********************************************
3* File      :   z_tnef.php
4* Project   :   Z-Push
5* Descr     :
6*
7* Created   :   21.06.2008
8*
9* Zarafa Deutschland GmbH, www.zarafaserver.de
10* This file is distributed under GPL v2.
11* Consult LICENSE file for details
12************************************************
13
14 * This is tnef implementation for z-push. It is based on
15 * Zarafa's tnef implementation.
16 *
17 * The ZPush_tnef class does only simple reading of a tnef stream.
18 * Most importantly, we currently only support properties within
19 * the message itself, and do not support recipient tables and
20 * attachment properties within the TNEF data.
21 *
22 * The ZPush_tnef class will accept TNEF streams with data about
23 * recipients and attachments, but the information will be ignored.
24 *
25 * Created on 21.06.2008 by Manfred
26 *
27 * For more information on tnef refer to:
28 * http://msdn.microsoft.com/en-us/library/ms530652(EXCHG.10).aspx
29 * http://msdn.microsoft.com/en-us/library/cc425498(EXCHG.80).aspx
30 *
31 * The mapping between Microsoft Mail IPM classes and those used in
32 * MAPI see: http://msdn2.microsoft.com/en-us/library/ms527360.aspx
33 */
34
35define('TNEF_SIGNATURE',      0x223e9f78);
36define('TNEF_LVL_MESSAGE',    0x01);
37define('TNEF_LVL_ATTACHMENT', 0x02);
38
39
40
41define('ZP_DWORD', 32);
42define('ZP_WORD', 16);
43define('ZP_BYTE', 8);
44
45define('ZP_GUID_SIZE', 256);
46
47class ZPush_tnef{
48
49    //we need a store in order to get the namedpropers
50    function ZPush_tnef($store) {
51        $this->_store = $store;
52    }
53    /*
54    * Function reads tnef stream and puts mapi properties into an array.
55    */
56    function extractProps($tnefstream, &$mapiprops) {
57        $hresult = NOERROR;
58        $signature = 0; //tnef signature - 32 Bit
59        $key = 0; //a nonzero 16-bit unsigned integer
60
61        $type = 0; // 32-bit value
62        $size = 0; // 32-bit value
63        $checksum = 0; //16-bit value
64        $component = 0; //8-bit value - either TNEF_LVL_MESSAGE or TNEF_LVL_ATTACHMENT
65        $buffer = "";
66
67        //mapping between Microsoft Mail IPM classes and those in MAPI
68        $aClassMap = array(
69            "IPM.Microsoft Schedule.MtgReq"        => "IPM.Schedule.Meeting.Request",
70            "IPM.Microsoft Schedule.MtgRespP"    => "IPM.Schedule.Meeting.Resp.Pos",
71            "IPM.Microsoft Schedule.MtgRespN"    => "IPM.Schedule.Meeting.Resp.Neg",
72            "IPM.Microsoft Schedule.MtgRespA"    => "IPM.Schedule.Meeting.Resp.Tent",
73            "IPM.Microsoft Schedule.MtgCncl"    => "IPM.Schedule.Meeting.Canceled",
74            "IPM.Microsoft Mail.Non-Delivery"    => "Report.IPM.Note.NDR",
75            "IPM.Microsoft Mail.Read Receipt"    => "Report.IPM.Note.IPNRN",
76            "IPM.Microsoft Mail.Note"            => "IPM.Note",
77            "IPM.Microsoft Mail.Note"            => "IPM",
78        );
79        //read signature
80        $hresult = $this->_readFromTnefStream($tnefstream, ZP_DWORD, $signature);
81        if ($hresult !== NOERROR) {
82            debugLog("TNEF STREAM:".bin2hex($tnefstream));
83            debugLog("There was an error reading tnef signature");
84            return $hresult;
85        }
86
87        //check signature
88        if ($signature != TNEF_SIGNATURE) {
89            debugLog("Corrupt signature.");
90            return MAPI_E_CORRUPT_DATA;
91        }
92
93        //read key
94        $hresult = $this->_readFromTnefStream($tnefstream, ZP_WORD, $key);
95        if ($hresult !== NOERROR) {
96            debugLog("There was an error reading tnef key.");
97            return $hresult;
98        }
99
100        // File is made of blocks, with each a type and size. Component and Key are ignored.
101        while(1) {
102            //the stream is empty. exit
103            if (strlen($tnefstream) == 0) return NOERROR;
104
105            //read component - it is either TNEF_LVL_MESSAGE or TNEF_LVL_ATTACHMENT
106            $hresult = $this->_readFromTnefStream($tnefstream, ZP_BYTE, $component);
107            if ($hresult !== NOERROR) {
108                $hresult = NOERROR; //EOF -> no error
109                return $hresult;
110                break;
111            }
112
113            //read type
114            $hresult = $this->_readFromTnefStream($tnefstream, ZP_DWORD, $type);
115            if ($hresult !== NOERROR) {
116                debugLog("There was an error reading stream property type");
117                return $hresult;
118            }
119
120            //read size
121            $hresult = $this->_readFromTnefStream($tnefstream, ZP_DWORD, $size);
122            if ($hresult !== NOERROR) {
123                debugLog("There was an error reading stream property size");
124                return $hresult;
125            }
126
127            if ($size == 0) {
128                // do not allocate 0 size data block
129                debugLog("Size is 0. Corrupt data.");
130                return MAPI_E_CORRUPT_DATA;
131            }
132
133            //read buffer
134            $hresult = $this->_readBuffer($tnefstream, $size, $buffer);
135            if ($hresult !== NOERROR) {
136                debugLog("There was an error reading stream property buffer");
137                return $hresult;
138            }
139
140            //read checksum
141            $hresult = $this->_readFromTnefStream($tnefstream, ZP_WORD, $checksum);
142            if ($hresult !== NOERROR) {
143                debugLog("There was an error reading stream property checksum.");
144                return $hresult;
145            }
146
147            // Loop through all the blocks of the TNEF data. We are only interested
148            // in the properties block for now (0x00069003)
149            switch ($type) {
150                case 0x00069003:
151                    $hresult = $this->_readMapiProps($buffer, $size, $mapiprops);
152                    if ($hresult !== NOERROR) {
153                        debugLog("There was an error reading mapi properties' part.");
154                        return $hresult;
155                    }
156                    break;
157                case 0x00078008: // PR_MESSAGE_CLASS
158                    $msMailClass = trim($buffer);
159                    if (array_key_exists($msMailClass, $aClassMap)) {
160                        $messageClass = $aClassMap[$msMailClass];
161                    }
162                    else {
163                        $messageClass = $msMailClass;
164                    }
165                    $mapiprops[PR_MESSAGE_CLASS] = $messageClass;
166                    break;
167                case 0x00050008: // PR_OWNER_APPT_ID
168                    $mapiprops[PR_OWNER_APPT_ID] = $buffer;
169                    break;
170                case 0x00040009: // PR_RESPONSE_REQUESTED
171                    $mapiprops[PR_RESPONSE_REQUESTED] = $buffer;
172                    break;
173
174                // --- TNEF attachemnts ---
175                case 0x00069002:
176                    break;
177                case 0x00018010:        // PR_ATTACH_FILENAME
178                    break;
179                case 0x00068011:        // PR_ATTACH_RENDERING, extra icon information
180                    break;
181                case 0x0006800f:        // PR_ATTACH_DATA_BIN, will be set via OpenProperty() in ECTNEF::Finish()
182                    break;
183                case 0x00069005:        // Attachment property stream
184                    break;
185                default:
186                    // Ignore this block
187                    break;
188            }
189
190        }
191        return NOERROR;
192
193    }
194
195    /*
196    * Reads a given number of bits from stream and converts them from little indian in a "normal" order. The function
197    * also cuts the tnef stream after reading.
198    */
199    function _readFromTnefStream(&$tnefstream, $bits, &$element) {
200        $bytes = $bits / 8;
201
202        $part = substr($tnefstream, 0, $bytes);
203        $packs = array();
204
205        switch ($bits) {
206            case ZP_DWORD:
207                $packs = unpack("V", $part);
208                break;
209            case ZP_WORD:
210                $packs = unpack("v", $part);
211                break;
212            case ZP_BYTE:
213                $packs[1] = ord($part[0]);
214                break;
215            default:
216                $packs = array();
217                break;
218        }
219
220        if (empty($packs) || !isset($packs[1])) return MAPI_E_CORRUPT_DATA;
221
222        $tnefstream = substr($tnefstream, $bytes);
223        $element = $packs[1];
224        return NOERROR;
225    }
226
227    /*
228    * Reads a given number of bits from stream and puts them into $element. The function
229    * also cuts the tnef stream after reading.
230    */
231    function _readBuffer(&$tnefstream, $bytes, &$element) {
232
233        $element = substr($tnefstream, 0, $bytes);
234        $tnefstream = substr($tnefstream, $bytes);
235        return NOERROR;
236
237    }
238
239    /*
240    * Reads mapi props from buffer into an anrray.
241    */
242    function _readMapiProps (&$buffer, $size, &$mapiprops) {
243        $nrprops = 0;
244        //get number of mapi properties
245        $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $nrprops);
246        if ($hresult !== NOERROR) {
247                debugLog("There was an error getting the number of mapi properties in stream.");
248                return $hresult;
249        }
250
251        $size -= 4;
252
253//debugLog("nrprops:$nrprops");
254        //loop through all the properties and add them to our internal list
255        while($nrprops) {
256//debugLog("\tPROP:$nrprops");
257            $hresult = $this->_readSingleMapiProp($buffer, $size, $read, $mapiprops);
258            if ($hresult !== NOERROR) {
259                    debugLog("There was an error reading a mapi property.");
260                    debugLog("result: " . sprintf("%x", $hresult));
261
262                    return $hresult;
263            }
264            $nrprops--;
265        }
266        return NOERROR;
267    }
268
269    /*
270    * Reads a single mapi prop.
271    */
272    function _readSingleMapiProp(&$buffer, &$size, &$read, &$mapiprops) {
273        $propTag = 0;
274        $len = 0;
275        $origSize = $size;
276        $isNamedId = 0;
277        $namedProp = 0;
278        $count = 0;
279        $mvProp = 0;
280        $guid = 0;
281
282        if($size < 8) {
283            return MAPI_E_NOT_FOUND;
284        }
285
286        $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $propTag);
287        if ($hresult !== NOERROR) {
288            debugLog("There was an error reading a mapi property tag from the stream.");
289            return $hresult;
290        }
291        $size -= 4;
292//debugLog("mapi prop type:".dechex(mapi_prop_type($propTag)));
293//debugLog("mapi prop tag: 0x".sprintf("%04x", mapi_prop_id($propTag)));
294        if (mapi_prop_id($propTag) >= 0x8000) {
295        // Named property, first read GUID, then name/id
296            if($size < 24) {
297                debugLog("Corrupt guid size for named property:".dechex($propTag));
298                return MAPI_E_CORRUPT_DATA;
299            }
300            //strip GUID & name/id
301            $hresult = $this->_readBuffer($buffer, 16, $guid);
302            if ($hresult !== NOERROR) {
303                debugLog("There was an error reading stream property buffer");
304                return $hresult;
305            }
306
307            $size -= 16;
308             //it is not used and is here only for eventual debugging
309            $readableGuid = unpack("VV/v2v/n4n", $guid);
310            $readableGuid = sprintf("{%08x-%04x-%04x-%04x-%04x%04x%04x}",$readableGuid['V'], $readableGuid['v1'], $readableGuid['v2'],$readableGuid['n1'],$readableGuid['n2'],$readableGuid['n3'],$readableGuid['n4']);
311//debugLog("guid:$readableGuid");
312            $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $isNamedId);
313            if ($hresult !== NOERROR) {
314                debugLog("There was an error reading stream property checksum.");
315                return $hresult;
316            }
317            $size -= 4;
318
319            if($isNamedId != 0) {
320                // A string name follows
321                //read length of the property
322                $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len);
323                if ($hresult !== NOERROR) {
324                    debugLog("There was an error reading mapi property's length");
325                    return $hresult;
326                }
327                $size -= 4;
328                if ($size < $len) {
329                    return MAPI_E_CORRUPT_DATA;
330                }
331                //read the name of the property, eg Keywords
332                $hresult = $this->_readBuffer($buffer, $len, $namedProp);
333                if ($hresult !== NOERROR) {
334                    debugLog("There was an error reading stream property buffer");
335                    return $hresult;
336                }
337
338                $size -= $len;
339
340                //Re-align
341                $buffer = substr($buffer, ($len & 3 ? 4 - ($len & 3) : 0));
342                $size -= $len & 3 ? 4 - ($len & 3) : 0;
343            }
344            else {
345                $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $namedProp);
346                if ($hresult !== NOERROR) {
347                    debugLog("There was an error reading mapi property's length");
348                    return $hresult;
349                }
350//debugLog("named: 0x".sprintf("%04x", $namedProp));
351                $size -= 4;
352            }
353
354            if ($this->_store !== false) {
355                $named = mapi_getidsfromnames($this->_store, array($namedProp), array(makeguid($readableGuid)));
356
357                $propTag = mapi_prop_tag(mapi_prop_type($propTag), mapi_prop_id($named[0]));
358            }
359            else {
360                debugLog("Store not available. It is impossible to get named properties");
361            }
362        }
363//debugLog("mapi prop tag: 0x".sprintf("%04x", mapi_prop_id($propTag))." ".sprintf("%04x", mapi_prop_type($propTag)));
364        if($propTag & MV_FLAG) {
365            if($size < 4) {
366                return MAPI_E_CORRUPT_DATA;
367            }
368            //read the number of properties
369            $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $count);
370            if ($hresult !== NOERROR) {
371                debugLog("There was an error reading number of properties for:".dechex($propTag));
372                return $hresult;
373            }
374            $size -= 4;
375        }
376        else {
377            $count = 1;
378        }
379
380        for ($mvProp = 0; $mvProp < $count; $mvProp++) {
381            switch(mapi_prop_type($propTag) & ~MV_FLAG ) {
382                case PT_I2:
383                case PT_LONG:
384                    $hresult = $this->_readBuffer($buffer, 4, $value);
385                    if ($hresult !== NOERROR) {
386                        debugLog("There was an error reading stream property buffer");
387                        return $hresult;
388                    }
389                    $value = unpack("V", $value);
390                    $value = intval($value[1], 16);
391
392                    if($propTag & MV_FLAG) {
393                        $mapiprops[$propTag][] = $value;
394                    }
395                    else {
396                        $mapiprops[$propTag] = $value;
397                    }
398                    $size -= 4;
399//debugLog("int or long propvalue:".$value);
400                    break;
401
402                case PT_R4:
403                    if($propTag & MV_FLAG) {
404                        $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag][]);
405
406                        if ($hresult !== NOERROR) {
407                            debugLog("There was an error reading stream property buffer");
408                            return $hresult;
409                        }
410                    }
411                    else {
412                        $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag]);
413                        if ($hresult !== NOERROR) {
414                            debugLog("There was an error reading stream property buffer");
415                            return $hresult;
416                        }
417                    }
418                    $size -= 4;
419//debugLog("propvalue:".$mapiprops[$propTag]);
420                    break;
421
422                case PT_BOOLEAN:
423                    $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag]);
424                        if ($hresult !== NOERROR) {
425                            debugLog("There was an error reading stream property buffer");
426                            return $hresult;
427                        }
428                    $size -= 4;
429                    //reported by dw2412
430                    //cast to integer as it evaluates to 1 or 0 because
431                    //a non empty string evaluates to true :(
432                    $mapiprops[$propTag] = (integer) bin2hex($mapiprops[$propTag]{0});
433//debugLog("propvalue:".$mapiprops[$propTag]);
434                    break;
435
436
437                case PT_SYSTIME:
438                    if($size < 8) {
439                        return MAPI_E_CORRUPT_DATA;
440                    }
441                    if($propTag & MV_FLAG) {
442                        $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag][]);
443                        if ($hresult !== NOERROR) {
444                            debugLog("There was an error reading stream property buffer");
445                            return $hresult;
446                        }
447                    }
448                    else {
449                        $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag]);
450                        if ($hresult !== NOERROR) {
451                            debugLog("There was an error reading stream property buffer");
452                            return $hresult;
453                        }
454                    }
455                    //we have to convert the filetime to an unixtime timestamp
456                    $filetime = unpack("V2v", $mapiprops[$propTag]);
457                    //php on 64-bit systems converts unsigned values differently than on 32 bit systems
458                    //we need this "fix" in order to get the same values on both types of systems
459                    $filetime['v2'] = substr(sprintf("%08x",$filetime['v2']), -8);
460                    $filetime['v1'] = substr(sprintf("%08x",$filetime['v1']), -8);
461
462                    $filetime = hexdec($filetime['v2'].$filetime['v1']);
463                    $filetime = ($filetime - 116444736000000000) / 10000000;
464                    $mapiprops[$propTag] = $filetime;
465                    // we have to set the start and end times separately because the standard PR_START_DATE and PR_END_DATE aren't enough
466                    if ($propTag == PR_START_DATE) {
467                        $namedStartTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820d");
468                        $mapiprops[$namedStartTime] = $filetime;
469                        $namedCommonStart = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8516");
470                        $mapiprops[$namedCommonStart] = $filetime;
471                    }
472                    if ($propTag == PR_END_DATE) {
473                        $namedEndTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820e");
474                        $mapiprops[$namedEndTime] = $filetime;
475                        $namedCommonEnd = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8517");
476                        $mapiprops[$namedCommonEnd] = $filetime;
477                    }
478                    $size -= 8;
479//debugLog("propvalue:".$mapiprops[$propTag]);
480                    break;
481
482                case PT_DOUBLE:
483                case PT_CURRENCY:
484                case PT_I8:
485                case PT_APPTIME:
486                    if($size < 8) {
487                        return MAPI_E_CORRUPT_DATA;
488                    }
489                    if($propTag & MV_FLAG) {
490                        $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag][]);
491                        if ($hresult !== NOERROR) {
492                            debugLog("There was an error reading stream property buffer");
493                            return $hresult;
494                        }
495                    }
496                    else {
497                        $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag]);
498                        if ($hresult !== NOERROR) {
499                            debugLog("There was an error reading stream property buffer");
500                            return $hresult;
501                        }
502                    }
503                    $size -= 8;
504//debugLog("propvalue:".$mapiprops[$propTag]);
505                    break;
506
507                case PT_STRING8:
508                    if($size < 8) {
509                        return MAPI_E_CORRUPT_DATA;
510                    }
511                    // Skip next 4 bytes, it's always '1' (ULONG)
512                    $buffer = substr($buffer, 4);
513                    $size -= 4;
514
515                    //read length of the property
516                    $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len);
517                    if ($hresult !== NOERROR) {
518                        debugLog("There was an error reading mapi property's length");
519                        return $hresult;
520                    }
521                    $size -= 4;
522                    if ($size < $len) {
523                        return MAPI_E_CORRUPT_DATA;
524                    }
525
526                    if ($propTag & MV_FLAG) {
527                        $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]);
528                        if ($hresult !== NOERROR) {
529                            debugLog("There was an error reading stream property buffer");
530                            return $hresult;
531                        }
532                    }
533                    else {
534                        $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]);
535                        if ($hresult !== NOERROR) {
536                            debugLog("There was an error reading stream property buffer");
537                            return $hresult;
538                        }
539                    }
540                    //location fix. it looks like tnef uses this value for location
541                    if (mapi_prop_id($propTag) == 0x8342) {
542                        $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208");
543                        $mapiprops[$namedLocation] = $mapiprops[$propTag];
544                        unset($mapiprops[$propTag]);
545                    }
546
547                    $size -= $len;
548
549                    //Re-align
550                    $buffer = substr($buffer, ($len & 3 ? 4 - ($len & 3) : 0));
551                    $size -= $len & 3 ? 4 - ($len & 3) : 0;
552//debugLog("propvalue:".$mapiprops[$propTag]);
553                    break;
554
555                case PT_UNICODE:
556                    if($size < 8) {
557                        return MAPI_E_CORRUPT_DATA;
558                    }
559                    // Skip next 4 bytes, it's always '1' (ULONG)
560                    $buffer = substr($buffer, 4);
561                    $size -= 4;
562
563                    //read length of the property
564                    $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len);
565                    if ($hresult !== NOERROR) {
566                        debugLog("There was an error reading mapi property's length");
567                        return $hresult;
568                    }
569                    $size -= 4;
570                    if ($size < $len) {
571                        return MAPI_E_CORRUPT_DATA;
572                    }
573                    //currently unicode strings are not supported bz mapi_setprops, so we'll use PT_STRING8
574                    $propTag = mapi_prop_tag(PT_STRING8, mapi_prop_id($propTag));
575
576                    if ($propTag & MV_FLAG) {
577                        $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]);
578                        if ($hresult !== NOERROR) {
579                            debugLog("There was an error reading stream property buffer");
580                            return $hresult;
581                        }
582                    }
583                    else {
584                        $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]);
585                        if ($hresult !== NOERROR) {
586                            debugLog("There was an error reading stream property buffer");
587                            return $hresult;
588                        }
589                    }
590
591                    //location fix. it looks like tnef uses this value for location
592                    if (mapi_prop_id($propTag) == 0x8342) {
593                        $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208");
594                        $mapiprops[$namedLocation] = $mapiprops[$propTag];
595                        unset($mapiprops[$propTag]);
596                        $mapiprops[$namedLocation] = iconv("UCS-2","windows-1252", $mapiprops[$namedLocation]);
597                    }
598
599                    //convert from unicode to windows encoding
600                    if (isset($mapiprops[$propTag])) $mapiprops[$propTag] = iconv("UCS-2","windows-1252", $mapiprops[$propTag]);
601                    $size -= $len;
602
603                    //Re-align
604                    $buffer = substr($buffer, ($len & 3 ? 4 - ($len & 3) : 0));
605                    $size -= $len & 3 ? 4 - ($len & 3) : 0;
606//debugLog("propvalue:".$mapiprops[$propTag]);
607                    break;
608
609                case PT_OBJECT:        // PST sends PT_OBJECT data. Treat as PT_BINARY
610                case PT_BINARY:
611                    if($size < ZP_BYTE) {
612                        return MAPI_E_CORRUPT_DATA;
613                    }
614                    // Skip next 4 bytes, it's always '1' (ULONG)
615                    $buffer = substr($buffer, 4);
616                    $size -= 4;
617
618                    //read length of the property
619                    $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len);
620                    if ($hresult !== NOERROR) {
621                        debugLog("There was an error reading mapi property's length");
622                        return $hresult;
623                    }
624                    $size -= 4;
625
626                    if (mapi_prop_type($propTag) == PT_OBJECT) {
627                        // TODO: IMessage guid [ 0x00020307 C000 0000 0000 0000 00 00 00 46 ]
628                        $buffer = substr($buffer, 16);
629                        $size -= 16;
630                        $len -= 16;
631                    }
632
633                    if ($size < $len) {
634                        return MAPI_E_CORRUPT_DATA;
635                    }
636
637                    if ($propTag & MV_FLAG) {
638                        $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]);
639                        if ($hresult !== NOERROR) {
640                            debugLog("There was an error reading stream property buffer");
641                            return $hresult;
642                        }
643                    }
644                    else {
645                        $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]);
646                        if ($hresult !== NOERROR) {
647                            debugLog("There was an error reading stream property buffer");
648                            return $hresult;
649                        }
650                    }
651
652                    $size -= $len;
653
654                    //Re-align
655                    $buffer = substr($buffer, ($len & 3 ? 4 - ($len & 3) : 0));
656                    $size -= $len & 3 ? 4 - ($len & 3) : 0;
657//debugLog("propvalue:".bin2hex($mapiprops[$propTag]));
658                    break;
659
660                default:
661                    return MAPI_E_INVALID_PARAMETER;
662                    break;
663            }
664        }
665        return NOERROR;
666    }
667}
668?>
Note: See TracBrowser for help on using the repository browser.