function GetPropIDFromString($store, $mapiprop) { if (is_string($mapiprop)) { $split = explode(":", $mapiprop); if (count($split) != 3) { continue; } if (substr($split[2], 0, 2) == "0x") { $id = hexdec(substr($split[2], 2)); } else { $id = $split[2]; } $named = mapi_getidsfromnames($store, array($id), array(makeguid($split[1]))); $mapiprop = mapi_prop_tag(constant($split[0]), mapi_prop_id($named[0])); } else { return $mapiprop; } return $mapiprop; }
/** * Reads a single mapi prop. * * @param string &$buffer * @param int $size * @param mixed &$read * @param array &$mapiprops * * @access private * @return int */ private function readSingleMapiProp(&$buffer, &$size, &$read, &$mapiprops) { $propTag = 0; $len = 0; $origSize = $size; $isNamedId = 0; $namedProp = 0; $count = 0; $mvProp = 0; $guid = 0; if ($size < 8) { return MAPI_E_NOT_FOUND; } $hresult = $this->readFromTnefStream($buffer, self::DWORD, $propTag); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading a mapi property tag from the stream."); return $hresult; } $size -= 4; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: mapi prop type:" . dechex(mapi_prop_type($propTag))); ZLog::Write(LOGLEVEL_DEBUG, "TNEF: mapi prop tag: 0x" . sprintf("%04x", mapi_prop_id($propTag))); if (mapi_prop_id($propTag) >= 0x8000) { // Named property, first read GUID, then name/id if ($size < 24) { ZLog::Write(LOGLEVEL_WARN, "TNEF: Corrupt guid size for named property:" . dechex($propTag)); return MAPI_E_CORRUPT_DATA; } //strip GUID & name/id $hresult = $this->readBuffer($buffer, 16, $guid); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } $size -= 16; //it is not used and is here only for eventual debugging $readableGuid = unpack("VV/v2v/n4n", $guid); $readableGuid = sprintf("{%08x-%04x-%04x-%04x-%04x%04x%04x}", $readableGuid['V'], $readableGuid['v1'], $readableGuid['v2'], $readableGuid['n1'], $readableGuid['n2'], $readableGuid['n3'], $readableGuid['n4']); ZLog::Write(LOGLEVEL_DEBUG, "TNEF: guid:{$readableGuid}"); $hresult = $this->readFromTnefStream($buffer, self::DWORD, $isNamedId); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property checksum."); return $hresult; } $size -= 4; if ($isNamedId != 0) { // A string name follows //read length of the property $hresult = $this->readFromTnefStream($buffer, self::DWORD, $len); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } //read the name of the property, eg Keywords $hresult = $this->readBuffer($buffer, $len, $namedProp); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; } else { $hresult = $this->readFromTnefStream($buffer, self::DWORD, $namedProp); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading mapi property's length"); return $hresult; } ZLog::Write(LOGLEVEL_DEBUG, "TNEF: named: 0x" . sprintf("%04x", $namedProp)); $size -= 4; } if ($this->store !== false) { $named = mapi_getidsfromnames($this->store, array($namedProp), array(makeguid($readableGuid))); $propTag = mapi_prop_tag(mapi_prop_type($propTag), mapi_prop_id($named[0])); } else { ZLog::Write(LOGLEVEL_WARN, "TNEF: Store not available. It is impossible to get named properties"); } } ZLog::Write(LOGLEVEL_DEBUG, "TNEF: mapi prop tag: 0x" . sprintf("%04x", mapi_prop_id($propTag)) . " " . sprintf("%04x", mapi_prop_type($propTag))); if ($propTag & MV_FLAG) { if ($size < 4) { return MAPI_E_CORRUPT_DATA; } //read the number of properties $hresult = $this->readFromTnefStream($buffer, self::DWORD, $count); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading number of properties for:" . dechex($propTag)); return $hresult; } $size -= 4; } else { $count = 1; } for ($mvProp = 0; $mvProp < $count; $mvProp++) { switch (mapi_prop_type($propTag) & ~MV_FLAG) { case PT_I2: case PT_LONG: $hresult = $this->readBuffer($buffer, 4, $value); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } $value = unpack("V", $value); $value = intval($value[1], 16); if ($propTag & MV_FLAG) { $mapiprops[$propTag][] = $value; } else { $mapiprops[$propTag] = $value; } $size -= 4; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: int or long propvalue:" . $value); break; case PT_R4: if ($propTag & MV_FLAG) { $hresult = $this->readBuffer($buffer, 4, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->readBuffer($buffer, 4, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } $size -= 4; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . $mapiprops[$propTag]); break; case PT_BOOLEAN: $hresult = $this->readBuffer($buffer, 4, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } $size -= 4; //reported by dw2412 //cast to integer as it evaluates to 1 or 0 because //a non empty string evaluates to true :( $mapiprops[$propTag] = (int) bin2hex($mapiprops[$propTag][0]); ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . $mapiprops[$propTag]); break; case PT_SYSTIME: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->readBuffer($buffer, 8, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->readBuffer($buffer, 8, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } //we have to convert the filetime to an unixtime timestamp $filetime = unpack("V2v", $mapiprops[$propTag]); //php on 64-bit systems converts unsigned values differently than on 32 bit systems //we need this "fix" in order to get the same values on both types of systems $filetime['v2'] = substr(sprintf("%08x", $filetime['v2']), -8); $filetime['v1'] = substr(sprintf("%08x", $filetime['v1']), -8); $filetime = hexdec($filetime['v2'] . $filetime['v1']); $filetime = ($filetime - 116444736000000000) / 10000000; $mapiprops[$propTag] = $filetime; // we have to set the start and end times separately because the standard PR_START_DATE and PR_END_DATE aren't enough if ($propTag == PR_START_DATE) { $mapiprops[$this->props["starttime"]] = $mapiprops[$this->props["commonstart"]] = $filetime; } if ($propTag == PR_END_DATE) { $mapiprops[$this->props["endtime"]] = $mapiprops[$this->props["commonend"]] = $filetime; } $size -= 8; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . $mapiprops[$propTag]); break; case PT_DOUBLE: case PT_CURRENCY: case PT_I8: case PT_APPTIME: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->readBuffer($buffer, 8, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->readBuffer($buffer, 8, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } $size -= 8; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . $mapiprops[$propTag]); break; case PT_STRING8: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->readFromTnefStream($buffer, self::DWORD, $len); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } //location fix. it looks like tnef uses this value for location if (mapi_prop_id($propTag) == 0x8342) { $mapiprops[$this->props["location"]] = $mapiprops[$propTag]; unset($mapiprops[$propTag]); } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . $mapiprops[$propTag]); break; case PT_UNICODE: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->readFromTnefStream($buffer, self::DWORD, $len); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } //currently unicode strings are not supported bz mapi_setprops, so we'll use PT_STRING8 $propTag = mapi_prop_tag(PT_STRING8, mapi_prop_id($propTag)); if ($propTag & MV_FLAG) { $hresult = $this->readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } //location fix. it looks like tnef uses this value for location if (mapi_prop_id($propTag) == 0x8342) { $mapiprops[$this->props["location"]] = iconv("UCS-2", "windows-1252", $mapiprops[$propTag]); unset($mapiprops[$propTag]); } //convert from unicode to windows encoding if (isset($mapiprops[$propTag])) { $mapiprops[$propTag] = iconv("UCS-2", "windows-1252", $mapiprops[$propTag]); } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; if (isset($mapiprops[$propTag])) { ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . $mapiprops[$propTag]); } break; case PT_OBJECT: // PST sends PT_OBJECT data. Treat as PT_BINARY // PST sends PT_OBJECT data. Treat as PT_BINARY case PT_BINARY: if ($size < self::BYTE) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->readFromTnefStream($buffer, self::DWORD, $len); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading mapi property's length"); return $hresult; } $size -= 4; if (mapi_prop_type($propTag) == PT_OBJECT) { // IMessage guid [ 0x00020307 C000 0000 0000 0000 00 00 00 46 ] $buffer = substr($buffer, 16); $size -= 16; $len -= 16; } if ($size < $len) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { ZLog::Write(LOGLEVEL_WARN, "TNEF: There was an error reading stream property buffer"); return $hresult; } } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; ZLog::Write(LOGLEVEL_DEBUG, "TNEF: propvalue:" . bin2hex($mapiprops[$propTag])); break; default: return MAPI_E_INVALID_PARAMETER; break; } } return NOERROR; }
* versions of the software. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ define('IID_IStream', makeguid("{0000000c-0000-0000-c000-000000000046}")); define('IID_IMAPITable', makeguid("{00020301-0000-0000-c000-000000000046}")); define('IID_IMessage', makeguid("{00020307-0000-0000-c000-000000000046}")); define('IID_IExchangeExportChanges', makeguid("{a3ea9cc0-d1b2-11cd-80fc-00aa004bba0b}")); define('IID_IExchangeImportContentsChanges', makeguid("{f75abfa0-d0e0-11cd-80fc-00aa004bba0b}")); define('IID_IExchangeImportHierarchyChanges', makeguid("{85a66cf0-d0e0-11cd-80fc-00aa004bba0b}")); define('PSETID_Appointment', makeguid("{00062002-0000-0000-C000-000000000046}")); define('PSETID_Task', makeguid("{00062003-0000-0000-C000-000000000046}")); define('PSETID_Address', makeguid("{00062004-0000-0000-C000-000000000046}")); define('PSETID_Common', makeguid("{00062008-0000-0000-C000-000000000046}")); define('PSETID_Log', makeguid("{0006200A-0000-0000-C000-000000000046}")); define('PSETID_Note', makeguid("{0006200E-0000-0000-C000-000000000046}")); define('PSETID_Meeting', makeguid("{6ED8DA90-450B-101B-98DA-00AA003F1305}")); define('PSETID_Archive', makeguid("{72E98EBC-57D2-4AB5-B0AA-D50A7B531CB9}")); define('PS_MAPI', makeguid("{00020328-0000-0000-C000-000000000046}")); define('PS_PUBLIC_STRINGS', makeguid("{00020329-0000-0000-C000-000000000046}")); define('PS_INTERNET_HEADERS', makeguid("{00020386-0000-0000-c000-000000000046}")); // sk added for Z-Push define('PSETID_AirSync', makeguid("{71035549-0739-4DCB-9163-00F0580DBBDF}"));
<?php define('IID_IStream', makeguid("{0000000c-0000-0000-c000-000000000046}")); define('IID_IMAPITable', makeguid("{00020301-0000-0000-c000-000000000046}")); define('IID_IMessage', makeguid("{00020307-0000-0000-c000-000000000046}")); define('IID_IExchangeExportChanges', makeguid("{a3ea9cc0-d1b2-11cd-80fc-00aa004bba0b}")); define('IID_IExchangeImportContentsChanges', makeguid("{f75abfa0-d0e0-11cd-80fc-00aa004bba0b}")); define('IID_IExchangeImportHierarchyChanges', makeguid("{85a66cf0-d0e0-11cd-80fc-00aa004bba0b}")); define('PSETID_Appointment', makeguid("{00062002-0000-0000-C000-000000000046}")); define('PSETID_Task', makeguid("{00062003-0000-0000-C000-000000000046}")); define('PSETID_Address', makeguid("{00062004-0000-0000-C000-000000000046}")); define('PSETID_Common', makeguid("{00062008-0000-0000-C000-000000000046}")); define('PSETID_Log', makeguid("{0006200A-0000-0000-C000-000000000046}")); define('PSETID_Note', makeguid("{0006200E-0000-0000-C000-000000000046}")); define('PSETID_Meeting', makeguid("{6ED8DA90-450B-101B-98DA-00AA003F1305}")); define('PSETID_Archive', makeguid("{72E98EBC-57D2-4AB5-B0AA-D50A7B531CB9}")); define('PS_MAPI', makeguid("{00020328-0000-0000-C000-000000000046}")); define('PS_PUBLIC_STRINGS', makeguid("{00020329-0000-0000-C000-000000000046}")); define('PS_INTERNET_HEADERS', makeguid("{00020386-0000-0000-c000-000000000046}")); define('MUIDECSAB', makeguid("{50A921AC-D340-48ee-B319-FBA753304425}")); // Zarafa Contact Provider GUIDs define('MUIDZCSAB', makeguid("{30047F72-92E3-DA4F-B86A-E52A7FE46571}"));
function _readSingleMapiProp(&$buffer, &$size, &$read, &$mapiprops) { $propTag = 0; $len = 0; $origSize = $size; $isNamedId = 0; $namedProp = 0; $count = 0; $mvProp = 0; $guid = 0; if ($size < 8) { return MAPI_E_NOT_FOUND; } $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $propTag); if ($hresult !== NOERROR) { debugLog("There was an error reading a mapi property tag from the stream."); return $hresult; } $size -= 4; //debugLog("mapi prop type:".dechex(mapi_prop_type($propTag))); //debugLog("mapi prop tag: 0x".sprintf("%04x", mapi_prop_id($propTag))); if (mapi_prop_id($propTag) >= 0x8000) { // Named property, first read GUID, then name/id if ($size < 24) { debugLog("Corrupt guid size for named property:" . dechex($propTag)); return MAPI_E_CORRUPT_DATA; } //strip GUID & name/id $hresult = $this->_readBuffer($buffer, 16, $guid); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $size -= 16; //it is not used and is here only for eventual debugging $readableGuid = unpack("VV/v2v/n4n", $guid); $readableGuid = sprintf("{%08x-%04x-%04x-%04x-%04x%04x%04x}", $readableGuid['V'], $readableGuid['v1'], $readableGuid['v2'], $readableGuid['n1'], $readableGuid['n2'], $readableGuid['n3'], $readableGuid['n4']); //debugLog("guid:$readableGuid"); $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $isNamedId); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property checksum."); return $hresult; } $size -= 4; if ($isNamedId != 0) { // A string name follows //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } //read the name of the property, eg Keywords $hresult = $this->_readBuffer($buffer, $len, $namedProp); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; } else { $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $namedProp); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } //debugLog("named: 0x".sprintf("%04x", $namedProp)); $size -= 4; } if ($this->_store !== false) { $named = mapi_getidsfromnames($this->_store, array($namedProp), array(makeguid($readableGuid))); $propTag = mapi_prop_tag(mapi_prop_type($propTag), mapi_prop_id($named[0])); } else { debugLog("Store not available. It is impossible to get named properties"); } } //debugLog("mapi prop tag: 0x".sprintf("%04x", mapi_prop_id($propTag))." ".sprintf("%04x", mapi_prop_type($propTag))); if ($propTag & MV_FLAG) { if ($size < 4) { return MAPI_E_CORRUPT_DATA; } //read the number of properties $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $count); if ($hresult !== NOERROR) { debugLog("There was an error reading number of properties for:" . dechex($propTag)); return $hresult; } $size -= 4; } else { $count = 1; } for ($mvProp = 0; $mvProp < $count; $mvProp++) { switch (mapi_prop_type($propTag) & ~MV_FLAG) { case PT_I2: case PT_LONG: $hresult = $this->_readBuffer($buffer, 4, $value); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $value = unpack("V", $value); $value = intval($value[1], 16); if ($propTag & MV_FLAG) { $mapiprops[$propTag][] = $value; } else { $mapiprops[$propTag] = $value; } $size -= 4; //debugLog("int or long propvalue:".$value); break; case PT_R4: if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } $size -= 4; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_BOOLEAN: $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $size -= 4; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_SYSTIME: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } //we have to convert the filetime to an unixtime timestamp $filetime = unpack("V2v", $mapiprops[$propTag]); $filetime = hexdec(sprintf("%08x%08x", $filetime['v2'], $filetime['v1'])); $filetime = ($filetime - 116444736000000000) / 10000000; $mapiprops[$propTag] = $filetime; // we have to set the start and end times separately because the standard PR_START_DATE and PR_END_DATE aren't enough if ($propTag == PR_START_DATE) { $namedStartTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820d"); $mapiprops[$namedStartTime] = $filetime; $namedCommonStart = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8516"); $mapiprops[$namedCommonStart] = $filetime; } if ($propTag == PR_END_DATE) { $namedEndTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820e"); $mapiprops[$namedEndTime] = $filetime; $namedCommonEnd = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8517"); $mapiprops[$namedCommonEnd] = $filetime; } $size -= 8; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_DOUBLE: case PT_CURRENCY: case PT_I8: case PT_APPTIME: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } $size -= 8; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_STRING8: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } //location fix. it looks like tnef uses this value for location if (mapi_prop_id($propTag) == 0x8342) { $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208"); $mapiprops[$namedLocation] = $mapiprops[$propTag]; unset($mapiprops[$propTag]); } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_UNICODE: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } //currently unicode strings are not supported bz mapi_setprops, so we'll use PT_STRING8 $propTag = mapi_prop_tag(PT_STRING8, mapi_prop_id($propTag)); if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } //location fix. it looks like tnef uses this value for location if (mapi_prop_id($propTag) == 0x8342) { $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208"); $mapiprops[$namedLocation] = $mapiprops[$propTag]; unset($mapiprops[$propTag]); $mapiprops[$namedLocation] = iconv("UCS-2", "windows-1252", $mapiprops[$namedLocation]); } //convert from unicode to windows encoding if (isset($mapiprops[$propTag])) { $mapiprops[$propTag] = iconv("UCS-2", "windows-1252", $mapiprops[$propTag]); } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_OBJECT: // PST sends PT_OBJECT data. Treat as PT_BINARY // PST sends PT_OBJECT data. Treat as PT_BINARY case PT_BINARY: if ($size < ZP_BYTE) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if (mapi_prop_type($propTag) == PT_OBJECT) { // TODO: IMessage guid [ 0x00020307 C000 0000 0000 0000 00 00 00 46 ] $buffer = substr($buffer, 16); $size -= 16; $len -= 16; } if ($size < $len) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; //debugLog("propvalue:".bin2hex($mapiprops[$propTag])); break; default: return MAPI_E_INVALID_PARAMETER; break; } } return NOERROR; }
/** * Parses properties from an array of strings. Each "string" may be either an ULONG, which is a direct property ID, * or a string with format "PT_TYPE:{GUID}:StringId" or "PT_TYPE:{GUID}:0xXXXX" for named * properties. * * @returns array of properties */ function getPropIdsFromStrings($store, $mapping) { $props = array(); $ids = array("name" => array(), "id" => array(), "guid" => array(), "type" => array()); // this array stores all the information needed to retrieve a named property $num = 0; // caching $guids = array(); foreach ($mapping as $name => $val) { if (is_string($val)) { $split = explode(":", $val); if (count($split) != 3) { // invalid string, ignore trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE); continue; } if (substr($split[2], 0, 2) == "0x") { $id = hexdec(substr($split[2], 2)); } else { $id = $split[2]; } // have we used this guid before? if (!defined($split[1])) { if (!array_key_exists($split[1], $guids)) { $guids[$split[1]] = makeguid($split[1]); } $guid = $guids[$split[1]]; } else { $guid = constant($split[1]); } // temp store info about named prop, so we have to call mapi_getidsfromnames just one time $ids["name"][$num] = $name; $ids["id"][$num] = $id; $ids["guid"][$num] = $guid; $ids["type"][$num] = $split[0]; $num++; } else { // not a named property $props[$name] = $val; } } if (empty($ids["id"])) { return $props; } // get the ids $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]); foreach ($named as $num => $prop) { $props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop)); } return $props; }
function mapidefs() { define("ZARAFA_SERVICE_GUID", makeguid("{3C253DCA-D227-443C-94FE-425FAB958C19}")); // default store define("ZARAFA_STORE_PUBLIC_GUID", makeguid("{D47F4A09-D3BD-493C-B2FC-3C90BBCB48D4}")); // public store define('RES_PROPERTY', 4); define('RELOP_EQ', 4); define('VALUE', 0); // propval define('RELOP', 1); // compare method define('ULPROPTAG', 6); // property define('MV_FLAG', 0x1000); define('PT_STRING8', 30); /* Null terminated 8-bit character string */ define('PT_TSTRING', PT_STRING8); define('PT_LONG', 3); /* Signed 32-bit value */ define('PT_BINARY', 258); /* Uninterpreted (counted byte array) */ define('PT_MV_LONG', MV_FLAG | PT_LONG); define('DEL_ASSOCIATED', 0x8); define('PT_BOOLEAN', 11); /* 16-bit boolean (non-zero true) */ define('PT_SYSTIME', 64); /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */ define('PT_MV_STRING8', MV_FLAG | PT_STRING8); define('PT_MV_BINARY', MV_FLAG | PT_BINARY); define('PSETID_Address', makeguid("{00062004-0000-0000-C000-000000000046}")); define('PSETID_Common', makeguid("{00062008-0000-0000-C000-000000000046}")); define('PS_PUBLIC_STRINGS', makeguid("{00020329-0000-0000-C000-000000000046}")); define('STORE_UNICODE_OK', 0x40000); // The message store supports properties containing Unicode characters. }