<?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
/**
 * ZArchiverOperations
 *
 * @package core
 */
class ZArchiverOperations {
	/**
	* Default constructor
	*/
	function ZArchiverOperations()
	{
	}

	/**
	 * Check whether this message is a stubbed (archived).
	 * @param $store object Message Store object
	 * @param $entryid object Message entryid
	 * @return boolean True when message is stubbed, false when not
	 */
	function isStubbed($store, $entryid)
	{
		$proplist = $GLOBALS["properties"]->getArchiverStubProperties();
		$proplist["message_class"] = PR_MESSAGE_CLASS;
		
		$message = $GLOBALS["operations"]->openMessage($store, $entryid);
		if($message){
			$msgprops = mapi_getprops($message, $proplist);

			if(isset($msgprops[ $proplist["stubbed"] ])){
				if($msgprops[ $proplist["stubbed"] ] == true){
					return true;
				}
			}else{
				if($msgprops[ $proplist["message_class"] ] == "IPM.Zarafa.Stub"){
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Return list of pairs of entryids of stores and messages
	 * @param $store object Message Store object
	 * @param $entryid object Message entryid
	 * @return array|boolean list of pairs of entrids of stores and messages or false if message is corrupt
	 */
	function getArchiveList($store, $entryid)
	{
		$proplist = $GLOBALS["properties"]->getArchiverStubProperties();
		$proplist["source_key"] = PR_SOURCE_KEY;
		$message = $GLOBALS["operations"]->openMessage($store, $entryid);
		if($message){
			$msgprops = mapi_getprops($message, $proplist);

			// Check if properties store_entryids and item_entrids both are missing
			if(!isset($msgprops[ $proplist["store_entryids"] ]) && !isset($msgprops[ $proplist["item_entryids"] ])){
				return Array();
			}

			// Check if any of the properties store_entryids or item_entrids are missing
			if(!isset($msgprops[ $proplist["store_entryids"] ]) || !isset($msgprops[ $proplist["item_entryids"] ])){
				// Message is corrupt
				return false;
			}

			// Check if PR_SOURCE_KEY exists.
			if(isset($msgprops[ $proplist["source_key"] ])){
				// Check if original_source_key exists
				if(isset($msgprops[ $proplist["original_sourcekey"] ])){
					// If the PR_SOURCE_KEY does not match the original_sourcekey message was not copied after archiving.
					if($msgprops[ $proplist["source_key"] ] != $msgprops[ $proplist["original_sourcekey"] ]){
						return Array();
					}
				}else{
					// Message corrupt
					return false;
				}
			}

			$store_entryids = $msgprops[ $proplist["store_entryids"] ];
			$item_entryids = $msgprops[ $proplist["item_entryids"] ];

			// Check if the number
			if(count($store_entryids) == count($item_entryids)){
				$pairlist = Array();
				for($i=0;$i<count($store_entryids);$i++){
					$pairlist[$i] = Array(
						'store' => $store_entryids[$i],
						'item' => $item_entryids[$i]
					);
				}
				return $pairlist;
			}else{
				// Message corrupt
				return false;
			}
		}
	}

	/**
	 * Copy archived properties from archived message to the stub message. Remove the STUBBED 
	 * property and return the attachments.
	 * @param $stubmsg object Message object
	 * @param $archivemsg object Message object
	 */
	function copyPropsToStub($stubmsg, $archivemsg){
		// Restore properties to stub message
		$restoreproplist = $GLOBALS["properties"]->getArchiverRestoreProperties();
		$archiveProps = mapi_getprops($archivemsg, $restoreproplist);
		mapi_setprops($stubmsg, $archiveProps);

		// Remove the STUBBED property from the stub message
		$stubproplist = $GLOBALS["properties"]->getArchiverStubProperties();
		mapi_deleteprops($stubmsg, Array($stubproplist['stubbed']));

		// Delete attachments from stub message
		$attachmentTable = mapi_message_getattachmenttable($stubmsg);
		if($attachmentTable) {
			$attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM));
			foreach($attachments as $props){
				mapi_message_deleteattach($stubmsg, (int) $props[PR_ATTACH_NUM]);
			}
		}

		// Copy attachments from archive message to stub message
		$attachmentTable = mapi_message_getattachmenttable($archivemsg);
		if($attachmentTable) {
			$attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM));
			foreach($attachments as $props){
				$archiveAttach = mapi_message_openattach($archivemsg, (int) $props[PR_ATTACH_NUM]);
				$newStubAttach = mapi_message_createattach($stubmsg);
				mapi_copyto($archiveAttach, array(), array(), $newStubAttach, 0);
				mapi_savechanges($newStubAttach);
			}
		}

		mapi_savechanges($stubmsg);
	}

	/**
	 * Destub an archived message.
	 * @param $store object Message Store object
	 * @param $entryid object Message entryid
	 * @return boolean Returns true if destubbing is successfull, false when it fails.
	 */
	function destub($store, $entryid)
	{
		if($this->isStubbed($store, $entryid)){
			$entryidList = $this->getArchiveList($store, $entryid);
			if($entryidList === false){
				return false;
			}

			if(count($entryidList) > 0){
				$archiveMsg = false;
				for($i=0;$i<count($entryidList)&&!$archiveMsg;$i++){

					/**
					 * It could be that the store entryID is wrapped. With such an entryID the store
					 * cannot be opened.
					 */
					$archiveStore = $GLOBALS["mapisession"]->openMessageStore($entryidList[$i]['store']);
					if($archiveStore){
						$archiveMsg = mapi_msgstore_openentry($archiveStore, $entryidList[0]['item']); 
					}
				}

				if($archiveMsg){
					$stubmsg = $GLOBALS["operations"]->openMessage($store, $entryid);
					$this->copyPropsToStub($stubmsg, $archiveMsg);
					return true;
				}else{
					return false;
				}
			}else{
				return true;
			}
		}
	}

}
?>
