<?php
/*
 * Copyright 2005 - 2009  Zarafa B.V.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3, 
 * as published by the Free Software Foundation with the following additional 
 * term according to sec. 7:
 *  
 * According to sec. 7 of the GNU Affero General Public License, version
 * 3, the terms of the AGPL are supplemented with the following terms:
 * 
 * "Zarafa" is a registered trademark of Zarafa B.V. The licensing of
 * the Program under the AGPL does not imply a trademark license.
 * Therefore any rights, title and interest in our trademarks remain
 * entirely with us.
 * 
 * However, if you propagate an unmodified version of the Program you are
 * allowed to use the term "Zarafa" to indicate that you distribute the
 * Program. Furthermore you may use our trademarks where it is necessary
 * to indicate the intended purpose of a product or service provided you
 * use it in accordance with honest practices in industrial or commercial
 * matters.  If you want to propagate modified versions of the Program
 * under the name "Zarafa" or "Zarafa Server", you may only do so if you
 * have a written permission by Zarafa B.V. (to acquire a permission
 * please contact Zarafa at trademark@zarafa.com).
 * 
 * The interactive user interface of the software displays an attribution
 * notice containing the term "Zarafa" and/or the logo of Zarafa.
 * Interactive user interfaces of unmodified and modified versions must
 * display Appropriate Legal Notices according to sec. 5 of the GNU
 * Affero General Public License, version 3, when you propagate
 * unmodified or modified versions of the Program. In accordance with
 * sec. 7 b) of the GNU Affero General Public License, version 3, these
 * Appropriate Legal Notices must retain the logo of Zarafa or display
 * the words "Initial Development by Zarafa" if the display of the logo
 * is not reasonably feasible for technical reasons. The use of the logo
 * of Zarafa in Legal Notices is allowed for unmodified and modified
 * 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/>.
 * 
 */

?>
<?php
	
/**
 * Function to make a MAPIGUID from a php string. 
 * The C++ definition for the GUID is: 
 *  typedef struct _GUID 
 *  { 
 *   unsigned long        Data1; 
 *   unsigned short       Data2; 
 *   unsigned short       Data3; 
 *   unsigned char        Data4[8]; 
 *  } GUID;
 *
 * A GUID is normally represented in the following form: 
 * 	{00062008-0000-0000-C000-000000000046}
 * 
 * @param String GUID
 */
function makeGuid($guid)
{
	// remove the { and } from the string and explode it into an array
	$guidArray = explode('-', substr($guid, 1,strlen($guid)-2));
	
	// convert to hex!
	$data1[0] = intval(substr($guidArray[0], 0, 4),16); // we need to split the unsigned long
	$data1[1] = intval(substr($guidArray[0], 4, 4),16);
	$data2 = intval($guidArray[1], 16);
	$data3 = intval($guidArray[2], 16);
	
	$data4[0] = intval(substr($guidArray[3], 0, 2),16);
	$data4[1] = intval(substr($guidArray[3], 2, 2),16);
	
	for($i=0; $i < 6; $i++)
	{
		$data4[] = intval(substr($guidArray[4], $i*2, 2),16);
	}

	return pack("vvvvCCCCCCCC", $data1[1], $data1[0], $data2, $data3, $data4[0],$data4[1],$data4[2],$data4[3],$data4[4],$data4[5],$data4[6],$data4[7]);
}

/**
 * Function to get a human readable string from a MAPI error code
 *
 *@param int $errcode the MAPI error code, if not given, we use mapi_last_hresult
 *@return string The defined name for the MAPI error code
 */
function get_mapi_error_name($errcode=null)
{
	if ($errcode===null){
		$errcode = mapi_last_hresult();
	}
	
	if ($errcode!=0){
		foreach(get_defined_constants() as $key=>$value){
			if (substr($key,0,7)=="MAPI_E_" || substr($key,0,7)=="MAPI_W_") {
				/**
				 * If PHP encounters a number beyond the bounds of the integer type,
				 * it will be interpreted as a float instead, so when comparing these error codes
				 * we have to manually typecast value to integer, so float will be converted in integer,
				 * but still its out of bound for integer limit so it will be auto adjusted to minus value
				 */
				if ($errcode == (int) $value){
					return $key;
				}
			}
		}
	} else {
		return "NOERROR";
	}

	// error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this)
	$result = unpack("H*",pack("N", $errcode));
	return "0x".$result[1];
}

/**
 * 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 (count($ids["id"])==0){
		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;
}

/**
 * Check wether a call to mapi_getprops returned errors for some properties.
 * mapi_getprops function tries to get values of properties requested but somehow if
 * if a property value can not be fetched then it changes type of property tag as PT_ERROR
 * and returns error for that particular property, probable errors
 * that can be returned as value can be MAPI_E_NOT_FOUND, MAPI_E_NOT_ENOUGH_MEMORY
 * 
 * @param long $property Property to check for error
 * @param Array $propArray An array of properties
 * @return mixed Gives back false when there is no error, if there is, gives the error
 */
function propIsError($property, $propArray)
{
	if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) {
		return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))];
	} else {
		return false;
	}
}

/******** Macro Functions for PR_DISPLAY_TYPE_EX values *********/
/**
 * check addressbook object is a remote mailuser
 */
function DTE_IS_REMOTE_VALID($value) {
	return !!($value & DTE_FLAG_REMOTE_VALID);
}

/**
 * check addressbook object is able to receive permissions
 */
function DTE_IS_ACL_CAPABLE($value) {
	return !!($value & DTE_FLAG_ACL_CAPABLE);
}

function DTE_REMOTE($value) {
	return (($value & DTE_MASK_REMOTE) >> 8);
}

function DTE_LOCAL($value) {
	return ($value & DTE_MASK_LOCAL);
}
?>