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

206 lines
6.4 KiB
PHP

<?php
/**
* Horde_Mapi::
*
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @copyright 2009-2017 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package Mapi_Utils
*/
/**
* Utility functions for dealing with Microsoft MAPI structures.
*
* Copyright 2009-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.
*
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @copyright 2009-2017 Horde LLC (http://www.horde.org)
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @package Mapi_Utils
*/
class Horde_Mapi
{
/**
* Determine if the current machine is little endian.
*
* @return boolean True if endianness is little endian, otherwise false.
*/
public static function isLittleEndian()
{
$testint = 0x00FF;
$p = pack('S', $testint);
return ($testint === current(unpack('v', $p)));
}
/**
* Change the byte order of a number. Used to allow big endian machines to
* decode the timezone blobs, which are encoded in little endian order.
*
* @param integer $num The number to reverse.
*
* @return integer The number, in the reverse byte order.
*/
public static function chbo($num)
{
$u = unpack('l', strrev(pack('l', $num)));
return $u[1];
}
/**
* Obtain the UID from a MAPI GOID.
*
* See http://msdn.microsoft.com/en-us/library/hh338153%28v=exchg.80%29.aspx
*
* @param string $goid Base64 encoded Global Object Identifier.
*
* @return string The UID
*/
public static function getUidFromGoid($goid)
{
$goid = base64_decode($goid);
// First, see if it's an Outlook UID or not.
if (substr($goid, 40, 8) == 'vCal-Uid') {
// For vCal UID values:
// Bytes 37 - 40 contain length of data and padding
// Bytes 41 - 48 are == vCal-Uid
// Bytes 53 until next to the last byte (/0) contain the UID.
return trim(substr($goid, 52, strlen($goid) - 1));
} else {
// If it's not a vCal UID, then it is Outlook style UID:
// The entire decoded goid is converted to hex representation with
// bytes 17 - 20 converted to zero
$hex = array();
foreach (str_split($goid) as $chr) {
$hex[] = sprintf('%02X', ord($chr));
}
array_splice($hex, 16, 4, array('00', '00', '00', '00'));
return implode('', $hex);
}
}
/**
* Create a MAPI GOID from a UID
* See http://msdn.microsoft.com/en-us/library/ee157690%28v=exchg.80%29
*
* @param string $uid The UID value to encode.
*
* @return string A Base64 encoded GOID
*/
public static function createGoid($uid, $options = array())
{
// Bytes 1 - 16 MUST be equal to the GOID identifier:
$arrayid = '040000008200E00074C5B7101A82E008';
// Bytes 17 - 20 - Exception replace time (YH YL M D)
$exception = '00000000';
// Bytes 21 - 28 The 8 byte creation time (can be all zeros if not available).
$creationtime = '0000000000000000';
// Bytes 29 - 36 Reserved 8 bytes must be all zeros.
$reserved = '0000000000000000';
// Bytes 37 - 40 - A long value describing the size of the UID data.
$size = strlen($uid);
// Bytes 41 - 52 - MUST BE vCal-Uid 0x01 0x00 0x00 0x00
$vCard = '7643616C2D55696401000000';
// The UID Data:
$hexuid = '';
foreach (str_split($uid) as $chr) {
$hexuid .= sprintf('%02X', ord($chr));
}
// Pack it
$goid = pack('H*H*H*H*VH*H*x', $arrayid, $exception, $creationtime, $reserved, $size, $vCard, $hexuid);
return base64_encode($goid);
}
/**
* Converts a Windows FILETIME value to a unix timestamp.
*
* Adapted from:
* http://stackoverflow.com/questions/610603/help-me-translate-long-value-expressed-in-hex-back-in-to-a-date-time
*
* @param string $ft Binary representation of FILETIME from a pTypDate
* MAPI property.
*
* @return integer The unix timestamp.
* @throws Horde_Mapi_Exception
*/
public static function filetimeToUnixtime($ft)
{
$ft = bin2hex($ft);
$dtval = substr($ft, 0, 16); // clip overlength string
$dtval = str_pad($dtval, 16, '0'); // pad underlength string
$quad = self::_flipEndian($dtval);
try {
$win64_datetime = self::_hexToBcint($quad);
return self::_win64ToUnix($win64_datetime);
} catch (Horde_Mapi_Exception $e) {
return -1;
}
}
// swap little-endian to big-endian
protected static function _flipEndian($str)
{
// make sure #digits is even
if ( strlen($str) & 1 )
$str = '0' . $str;
$t = '';
for ($i = strlen($str)-2; $i >= 0; $i-=2)
$t .= substr($str, $i, 2);
return $t;
}
// convert hex string to BC-int
protected static function _hexToBcint($str)
{
if (!extension_loaded('bcmath')) {
throw new Horde_Mapi_Exception('bcmath extension not loaded.');
}
$hex = array(
'0'=>'0', '1'=>'1', '2'=>'2', '3'=>'3', '4'=>'4',
'5'=>'5', '6'=>'6', '7'=>'7', '8'=>'8', '9'=>'9',
'a'=>'10', 'b'=>'11', 'c'=>'12', 'd'=>'13', 'e'=>'14', 'f'=>'15',
'A'=>'10', 'B'=>'11', 'C'=>'12', 'D'=>'13', 'E'=>'14', 'F'=>'15'
);
$bci = '0';
$len = strlen($str);
for ($i = 0; $i < $len; ++$i) {
$bci = bcmul($bci, '16');
$ch = $str[$i];
if (isset($hex[$ch]))
$bci = bcadd($bci, $hex[$ch]);
}
return $bci;
}
protected static function _win64ToUnix($bci)
{
if (!extension_loaded('bcmath')) {
throw new Horde_Mapi_Exception('bcmath extension not loaded.');
}
// Unix epoch as a Windows file date-time value
$magicnum = '116444735995904000';
$t = bcsub($bci, $magicnum); // Cast to Unix epoch
return bcdiv($t, '10000000', 0); // Convert from ticks to seconds
}
}