<?php
/*
 * Copyright 2005 - 2011  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
/**
 * Spreed Plugin
 */

	require_once(PATH_PLUGIN_DIR . "/spreed/php/inc/class.adhocspreedapi.php");
	require_once(PATH_PLUGIN_DIR . "/spreed/php/inc/class.spreedconference.php");
	/**
	 *
	 * @author S.B. Kok
	 * @version 1.0
	 *
	 * This class is used to communicate with the client side of
	 * the Zarafa WebAccess Spreed plugin. It processes all events
	 * to retrieve mails and contacts, but also processes the start
	 * of the Spreed meeting so everything is configured correctly
	 * using the SpreedConference, SpreedFile, SpreedParticipant, and
	 * SpreedAPI classes.
	 *
	 */
	class SpreedModule extends Module
	{
		/*
		 * The Spreed API should be accessed through the get api method only,
		 * this will make sure an api object is created and returned, which
		 * limits the load in case the client does not need the api for other
		 * calls.
		 */
		private /*SpreedAPI*/ $api;
		private /*boolean*/ $useAdhocApi = true;

		/**
		 * The link to created Spreed SpreedConference object.
		 *
		 * @private
		 * @var null
		 */
		private $conf = null;

		/**
		 * Constructor
		 * @param int $id unique id.
		 * @param array $data list of all actions.
		 */
		public function SpreedModule($id, $data)
		{
			parent::Module($id, $data);

						$this->api = null;
		}

		/**
		 * Get the Spreed API Instance, or create it if this is the first
		 * time this function is being called. This prevents the system
		 * from making unnecessary API calls to the Spreed server if the
		 * api is not used.
		 * @return SpreedConference The instance of the SpreedConference class.
		 */
		private function getApi()
		{
			if($this->api == null){
				if($this->useAdhocApi){
					$this->api = new AdhocSpreedApi();
					$this->api->init();
				} else {
					$this->api = new AuthSpreedApi();
					$this->api->init();
				}
			}
			return $this->api;
		}

		/**
		 * Process the incoming events that were fire by the client.
		 * Depending on the attributes given this will get the mails,
		 * contacts, or even setup the Spreed call.
		 * @return boolean True if everything was processed correctly.
		 */
		public function execute()
		{
			$result = false;

			foreach($this->data as $actionType => $actionData)
			{
				if(isset($actionType)) {
					try {
						switch($actionType)
						{
							case "open":
								$result = $this->open($actionData);
								break;
							case "getMail":
								$result = $this->getMail($actionData);
								break;
							case "getDistList":
								$result = $this->getDistList($actionData);
								break;
							case "save":
								$result = $this->save($actionData);
								break;
							case "clear":
								$result = $this->clear($actionData);
								break;
							default:
								$this->handleUnknownActionType($actionType);
						}

					} catch (MAPIException $e) {
						$this->sendFeedback(false, $this->errorDetailsFromException($e));
					}

				}
			}

			return $result;
		}

		/**
		 * Process the clear event fired at the client, this will remove
		 * all the uploaded file attachments at once if they were already
		 * uploaded to the server.
		 * @param mixed $action The action array with all the attributes set.
		 */
		public function clear($action)
		{
			$this->deleteUploads($action);
		}

		/**
		 * Move all the uploads from the mail to the newly set-up Spreed
		 * meeting. This function is called once the user decided to setup
		 * a Spreed web meeting, while he/she was originally composing a
		 * new email message in the WebAccess mail composer.
		 * @param mixed $action The action attribute array
		 * @return boolean True value if all the attachments were moved
		 * correctly.
		 */
		public function moveUploads($action)
		{
			$attachmentArray = array();

			// Start counting at 0 for the attachments
			$i = 0;

			// Check if there are no files uploaded
			if(!isset($_SESSION["files"])) {
				$_SESSION["files"] = array();
			}

			// Check if no files are uploaded with this dialog_attachments
			if(!isset($_SESSION["files"][$action['to']])) {
				$_SESSION["files"][$action['to']] = array();
			}

			if(isset($_SESSION["files"])) {
				$dialog_attachments = $action['from'];
				if(isset($_SESSION["files"][$dialog_attachments])) {
					// Loop through the uploaded attachments
					foreach ($_SESSION["files"][$dialog_attachments] as $tmpname => $fileinfo){
						// Only add if the file has been uploaded recently.
						// If it is already in a MAPI entry it will automatically be
						// added by the getMail call using a more space-efficient method.
						if (is_file(TMP_PATH."/".$tmpname)) {
							$_SESSION["files"][$action['to']][$tmpname] = $fileinfo;

							$attachmentArray[] = array(
													'attributes' => array('id' => $i++),
													'attach_num' => $i,
													'name' => $fileinfo['name'],
													'size' => $fileinfo['size'],
													'filetype' => $fileinfo['type']
												);
						}
					}
					// If we found recently uploaded files, inform the client
					// about them, so they are shown to the user as well.
					if(count($attachmentArray) >= 1){
						$data = array();
						$data["attributes"] = array("type" => "addAttachments");
						$data["attachments"] = array("attachment" => $attachmentArray);

						array_push($this->responseData["action"], $data);
						$GLOBALS["bus"]->addData($this->responseData);
					}

					// Delete all the files in the $_SESSION["files"][$dialog_attachments].
					unset($_SESSION["files"][$dialog_attachments]);
				}
			}

			return true;
		}

		/**
		 * Setup the spreed conference with all details specified by the
		 * given attribute array. This will use the SpreedConference, SpreedParticipant
		 * SpreedFile, and SpreedAPI classes to setup the Spreed web-meeting on the remote
		 * servers of Spreed.
		 * @param mixed $action The action attributes which contains all the details for
		 * the new spreed meeting.
		 * @return boolean True if the web-meeting is set-up correctly.
		 */
		public function save($action)
		{
			$this->conf = null;
			date_default_timezone_set('UTC');

			$duration = ($action['props']['end_time'] - $action['props']['start_time']) / 60;
			//Collect the data from record
			$action['participants'] = $action['recipients'];
			$action['title']      = $action['props']['subject'];
			$action['description']  = $action['props']['description'];
			$action['timezone']     = $action['props']['timezone'];
			$action['start_time']   = $action['props']['start_time'];
			$action['duration']     = $duration;

			$status = false;

			// Set-up the response data object
			$data = array("title" => $action["title"]);
			$data["attributes"] = array("type" => "spreedCheckin");

			$nrOfParticipants = count($action['participants']);
			if($nrOfParticipants == 0){
				// This check is added on the server side too in case the Javascript failed
				// to check, or if the user is deliberately trying to frustrate the system.
				$data["error"] = dgettext('plugin_spreed', "You need at least one other participant to set-up a Spreed Meeting, select or add another participant to continue") . ".";
			} else if($nrOfParticipants > 2){
				// This check is added on the server side too in case the Javascript failed
				// to check, or if the user is deliberately trying to frustrate the system.
				$data["error"] = dgettext('plugin_spreed', "Too many participants. You are not allowed to add more than two other participants with the free version of Spreed") . ".";
			} else if(array_key_exists($action['timezone'], $GLOBALS['spreed_timezones']) == false){
				// Although we are the ones that set-up the option select list, we may
				// never trust the client input, report the error back to the user.
				$data["error"] = dgettext('plugin_spreed', "The timezone you specified is incorrect, please select another option") . ".";
			} else {
				try {

					$default_lang = substr($GLOBALS["language"]->getSelected(), 0, 2);
					if(!array_key_exists($default_lang, $GLOBALS['spreed_languages'])){
						$default_lang = 'en';
					}

					$api = $this->getApi();
					if(!$this->useAdhocApi){
						$api->deleteAllOpenConferences();
					}
					$creatorNameArray = SpreedParticipant::extractNameArrayFromNameField(($GLOBALS["mapisession"]->getFullName()));
					$creator = new SpreedParticipant($creatorNameArray['firstname'], $creatorNameArray['lastname'], $creatorNameArray['organisation'], strtolower($GLOBALS["mapisession"]->getSMTPAddress()), '', $default_lang, $action['timezone'], true);

					//we should take into consideration timezone offset of the client, no matter
					//what timezone is set in spreed dialog, that's why we get the $timeWithClientOffset value.
					//Substracting instead of adding is needed as js gets offset with the opposite sign we need.
					$timeWithClientOffset=$action['props']['start_time']-($action['props']['client_timezone_offset']*60);
					$date = new DateTime(date('Y-m-d H:i:s',$timeWithClientOffset), new DateTimeZone($action["timezone"]));

					$this->conf = new SpreedConference($action['title'], $action['description'], $date, intval($action['duration']), $action["timezone"], $default_lang, $creator);

					$users = $action['participants'];

					foreach($users as $u) {
						if ($u['object_type']==MAPI_DISTLIST) {
							continue;
						}
						$userName = SpreedParticipant::extractNameArrayFromDisplayName($u['display_name']);

						if(array_key_exists($u['language'], $GLOBALS['spreed_languages']) == false){
							// although we are the ones that set-up the option select list, we may
							// never trust the client input, ignore the error and use English as our default.
							$u['language'] = 'en';
						} else if(array_key_exists($u['timezone'], $GLOBALS['spreed_timezones']) == false){
							// although we are the ones that set-up the option select list, we may
							// never trust the client input, ignore the error and use English as our default.
							$u['timezone'] = $action['timezone'];
						}

						$this->conf->addUser(new SpreedParticipant(
							$userName['firstname'],
							$userName['lastname'],
							$userName['organisation'],
							strtolower($u['smtp_address']), '', $u['language'], $u['timezone'], $u['isModerator'] == 1));
					}

					$this->processUploads($action['attachments']);

					$api->setupSpreedConference($this->conf);

					$data["checkinURL"] = $this->conf->getCreator()->getCheckInURL();

					$this->deleteUploads($action);

					$status = true;
				} catch(SpreedException $e){
					$data["error"] = dgettext('plugin_spreed', "Exception error! ") . $e->getMessage();
					//throw $e;
				}
			}
			if ($data["error"])
			{
				$this->addActionData("error", array('message' => $data["error"]));
			}
			else if ($data["checkinURL"])
			{
				$this->addActionData("update", array("item" => array(
					'id' => $action['id'],
					'props' => array(
						'checkin_url' => $data["checkinURL"]
					)
				)));
			}


			$GLOBALS["bus"]->addData($this->getResponseData());
			$status = true;
			return $status;
		}

		/**
		 * Delete all the uploads of the current upload session.
		 * This will erase all the files that were uploaded in this
		 * session, and it will remove all other references to attachments
		 * that are stored inside messages. It will not, however, delete the
		 * attachments from the original mail messages.
		 * @param mixed $action The action attributes used to determine which
		 * upload session we are in.
		 */
		public function deleteUploads($action)
		{
			if(isset($_SESSION["files"])) {
				$dialog_attachments = array_key_exists('dialog_attachments', $action) ? $action['dialog_attachments'] : '';
				if(isset($_SESSION["files"][$dialog_attachments])) {
					// Loop through the uploaded attachments
					foreach ($_SESSION["files"][$dialog_attachments] as $tmpname => $fileinfo)
					{
						$tmpFile = TMP_PATH."/".$tmpname;
						$tmpDir = $tmpFile ."_dir";
						$destFile = $tmpDir . "/" . basename($fileinfo["name"]);

						if (is_dir($tmpDir)) {
							if (is_file($destFile)) {
								unlink($destFile);
							}
							rmdir($tmpDir);
						}
						if (is_file($tmpFile)) {
							unlink($tmpFile);
						}
					}
					// Delete all the files in the $_SESSION["files"][$dialog_attachments].
					unset($_SESSION["files"][$dialog_attachments]);
				}
			}
		}

		/**
		 * Once the Spreed web meeting is being set-up, this function will make
		 * sure all attachments that have been marked to be uploaded in the web
		 * meeting are available and will be added to the Spreed conference instance
		 * as new SpreedFile instances.
		 * @param mixed $action The action attributes.
		 * @param SpreedConference $conf The Spreed conference instance to add
		 * the files to.
		 */
		public function processUploads($action)
		{
			$dialogAttachments = $action['dialog_attachments'];

			if( isset($action['add']) ) {
				foreach($action['add'] as $attachmentRecord) {

					if( $this->isUploadedFromSpreedDialog($attachmentRecord) ) {
						//just set the dialogAttachment to correct value
						$dialogAttachments = $action['dialog_attachments'];
					} elseif( $this->isCopiedFromDraft($attachmentRecord) ) {
						//just set the dialogAttachment to correct value
						$dialogAttachments = $attachmentRecord['original_attachment_store_id'];
					} else {//Attachment record is copied from stored message
						//copy the files to tmp and add to session with current spreed record attachment store id as key
						$dialogAttachments = $action['dialog_attachments'];
					}

					$this->addAttachmentFilesFromTmpToSpreed($dialogAttachments);

				}
			}

		}

		/**
		 *
		 * @param $dialog_attachments
		 */
		private function addAttachmentFilesFromTmpToSpreed($dialogAttachments) {

				if(isset($_SESSION["files"][$dialogAttachments])) {

					foreach ($_SESSION["files"][$dialogAttachments] as $tmpname => $fileinfo)
					{
							if (is_file(TMP_PATH."/".$tmpname)) {
								$tmpFile = TMP_PATH."/".$tmpname;
								$tmpDir = $tmpFile ."_dir";
								$destFile = $tmpDir . "/" . basename($fileinfo["name"]);

								mkdir($tmpDir);
								rename($tmpFile, $destFile);

								$this->conf->addFile(new SpreedFile($destFile));
							}
					}
				}
		}

		/**
		 * Check if we upload the attachment directly from Spreed Dialog.
		 *
		 * @param $attachmentRecord
		 * @return bool
		 */
		private function isUploadedFromSpreedDialog($attachmentRecord) {
			return  empty($attachmentRecord['original_attachment_store_id']) &&
					empty($attachmentRecord['original_record_entry_id']) &&
					empty($attachmentRecord['original_record_store_entry_id']);
		}

		/**
		 * Check if we copied attachment from newly created email
		 * which was not saved on server(thus parent record has no entryid).
		 *
		 * @param $attachmentRecord
		 * @return bool
		 */
		private function isCopiedFromDraft($attachmentRecord) {
			return  empty($attachmentRecord['original_record_entry_id']) &&
					!empty($attachmentRecord['original_attachment_store_id']) &&
					!empty($attachmentRecord['original_record_store_entry_id']);
		}


//        private function copyAttachmentFromMessageToTmp($storeEntryId, $messageEntryId, $attachmentNumber) {
//
//                // This means the attachment is a message item and is uploaded in sesssion file as mapi message Obj
//                $copyfromStore = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeEntryId));
//                $copyfrom = mapi_msgstore_openentry($copyfromStore , hex2bin($messageEntryId));
//
//                // Get the attachment through MAPI
//                $attachment = mapi_message_openattach($copyfrom, (int) $attachmentNumber);
//
//                // Check if the attachment exists
//                if($attachment){
//                    // Get the props of the attachment
//                    $props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
//
//                    // Open a stream to get the attachment data
//                    $stream = mapi_openpropertytostream($attachment, PR_ATTACH_DATA_BIN);
//                    $stat = mapi_stream_stat($stream);
//
//                    // Open the file handle so we can store the contents of the
//                    // attachment in the file to upload later on.
//                    $fHandle = fopen(TMP_PATH."/".$tmpname, "wb");
//
//                    // Write the attachment chunks to the temporary file
//                    // so we can upload them afterwars.
//                    for($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) {
//                        if (fwrite($fHandle, mapi_stream_read($stream, BLOCK_SIZE)) === FALSE) {
//                            dump("Failed to write to " . TMP_PATH."/".$tmpname);
//                        }
//                    }
//
//                    // Close the write handle
//                    fclose($fHandle);
//
//
//                }
//
//        }

		/**
		 * Retrieve the contact dist list entry from its store which it is located in,
		 * and forward the information to the client so they
		 * can be added to the participant-list.
		 * @param mixed $action The data that holds the contact entry and store ids.
		 * @return boolean True if the action succeeded.
		 **/
		public function getDistList($action)
		{
			$result = false;

			$store = $this->getActionStore($action);

			if($store){
				$message = $GLOBALS["operations"]->openMessage($store, hex2bin($action['entryid']));

				if($message){
					$properties = $GLOBALS["properties"]->getDistListProperties();

					$data = array();
					$data["attributes"] = array("type" => "addParticipants");

					$mailData = $GLOBALS["operations"]->getMessageProps($store, $message, $properties, false);

					// get members
					$messageProps = mapi_getprops($message, array($properties["members"], $properties["oneoff_members"]));
					$members = isset($messageProps[$properties["members"]]) ? $messageProps[$properties["members"]] : array();
					$oneoff_members = isset($messageProps[$properties["oneoff_members"]]) ? $messageProps[$properties["oneoff_members"]] : array();

					// parse oneoff members
					foreach($oneoff_members as $key => $item){
						$oneoff_members[$key] = mapi_parseoneoff($item);
					}

					// Add the sender and all the recipients of this mail to the Spreed Meeting
					$users = array();

					// Start counting from user 0, this includes the sender if it is available
					$i = 0;

					$items = array();
					$count = 0;
					foreach($members as $key => $item){
						$parts = unpack("Vnull/A16guid/Ctype/A*entryid", $item);

						if($parts["guid"] == hex2bin("812b1fa4bea310199d6e00dd010f5402")){
							$item = mapi_parseoneoff($item);
							$item["distlisttype"] = "ONEOFF";
							$item["entryid"] = bin2hex($members[$key]);
							$item["icon_index"] = 512;
							$item["message_class"] = "IPM.DistListItem.OneOffContact";
						} else {
							$item = array();
							$item["name"] = $oneoff_members[$key]["name"];
							$item["type"] = $oneoff_members[$key]["type"];
							$item["address"] = $oneoff_members[$key]["address"];
							$item["entryid"] = array("attributes" => array("type" => "binary"), "_content" => bin2hex($parts["entryid"]));

							// please note that the updated info isn't saved directly, but send to the client, when he submit the distlist again _then_ the dist list is really updated!
							$updated_info = $this->updateItem($store, $oneoff_members[$key], $parts);
							if ($updated_info){
								$item["name"] = $updated_info["name"];
								$item["type"] = $updated_info["type"];
								$item["address"] = $updated_info["email"];
							}
						}

						//$item["name"] = $item["name"];
						//$item["address"] = $item["address"];
						if(strlen($item["name"]) > 0 || strlen($item["address"]) > 0){
							$users[] = array_merge(
											array(
												'attributes' => array('id' => $i++),
												'email' => $item["address"]
											),
											SpreedParticipant::extractNameArrayFromDisplayName($item["name"])
									);
						}
					}

					$data["participants"] = array("user" => $users);

					if(count($users) >= 1){
						array_push($this->responseData["action"], $data);
						$GLOBALS["bus"]->addData($this->responseData);
						$result = true;
					}
				}
			}

			return $result;
		}

		/**
		 * Collect the recipients from provided array of records, by
		 * opening each, retrieving recipients and filtering duplicates and currently logged user.
		 * Also adds the sender to recipients.
		 *
		 * @param mixed $action The data that holds the selectedRecordsData and unique id of request.
		 * @return boolean True if the action succeeded.
		 **/
		public function open($action)
		{
			$result     = false;
			$recipients = array();
			$attachments = array();
			$attachmentsCounter = 0;

			$response   = array(
				'item' => array(
					'props' => array(),
					'id' => $action['id']
				)
			);

			if(isset($action['selectedRecordsData']) && !empty($action['selectedRecordsData']) ) {

				$loggedUserEmailAddress = $GLOBALS["mapisession"]->getEmailAddress();

				$recordsDataCount = sizeof($action['selectedRecordsData']);
				for($i = 0; $i < $recordsDataCount; $i++) {
					$currentStoreEntryId    = $action['selectedRecordsData'][$i]['storeEntryId'];
					$currentMessageEntryId  = $action['selectedRecordsData'][$i]['entryid'];

					$store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($currentStoreEntryId));

					if(is_resource($store)) {
						$mapiMessage = mapi_msgstore_openentry($store, hex2bin($currentMessageEntryId));

						if($mapiMessage) {
							$currentMessageParticipants    = $GLOBALS["operations"]->getRecipientsInfo($store, $mapiMessage);
							$currentMessageAttachments     = $GLOBALS["operations"]->getAttachmentsInfo($store, $mapiMessage);

							//Add sender to recipients
							$senderStructure                = $GLOBALS["operations"]->getSenderAddress($mapiMessage);
							$currentMessageParticipants[]   = $senderStructure;
							//Filter duplicate recipients and logged user
							foreach($currentMessageParticipants as $currentMessageParticipant) {
								if($loggedUserEmailAddress == $currentMessageParticipant['props']['email_address'] || $currentMessageParticipant['props']['object_type']==MAPI_DISTLIST) {
									continue;
								}
								//Each recipient has unique entryid - so we are collecting only unique recipients here
								//filtering duplicates.
								$recipients[$currentMessageParticipant['props']['entryid']] = $currentMessageParticipant;
							}

							foreach($currentMessageAttachments as $currentMessageAttachment) {
								$currentMessageAttachment['props']['original_record_entry_id'] = $currentMessageEntryId;
								$currentMessageAttachment['props']['original_record_store_entry_id'] = $currentStoreEntryId;
								$currentMessageAttachment['props']['original_attach_num'] = $currentMessageAttachment['props']['attach_num'];
								$currentMessageAttachment['props']['attach_num'] = $attachmentsCounter++;

								$attachments[] = $currentMessageAttachment;
							}


						}
					}
				}
				$response['item']['recipients']['item'] = array_values($recipients);
				$response['item']['attachments']['item'] = $attachments;
				$result = true;
			}

			$this->addActionData("item", $response);
			$GLOBALS["bus"]->addData($this->getResponseData());

			return $result;
		}

		/**
		 * Retrieve the mail entry from its store which it is located in,
		 * and forward the contacts of this mail to the client so they
		 * can be added to the participant-list.
		 * @param mixed action The data that holds the mail entry and store ids.
		 * @return boolean True if the action succeeded.
		 **/
		public function getMail($action)
		{
			$result = false;

			$store = $this->getActionStore($action);

			if($store){
				$message = $GLOBALS["operations"]->openMessage($store, hex2bin($action['entryid']));

				if($message){
					$properties = $GLOBALS["properties"]->getMailProperties();

					$data = array();
					$data["attributes"] = array("type" => "addParticipants");

					$mailData = $GLOBALS["operations"]->getMessageProps($store, $message, $properties, false);
					//$data['info'] = $mailData;


					// Add the sender and all the recipients of this mail to the Spreed Meeting
					$users = array();

					// Start counting from user 0, this includes the sender if it is available
					$i = 0;

					// If the sender is available, include it in the participant table
					if(isset($mailData['sender_email_address'])){
						$users[] = array_merge(
										array(
											'attributes' => array('id' => $i++),
											'email' => $mailData['sender_email_address']
										),
										SpreedParticipant::extractNameArrayFromDisplayName($mailData['sender_name'])
									);
					}

					// Loop through the recipients of the mail and add them to the participant table.
					if(isset($mailData['recipients']) && isset($mailData['recipients']['recipient'])){
						foreach($mailData['recipients']['recipient'] as $r){
							$users[] = array_merge(
											array(
												'attributes' => array('id' => $i++),
												'email' => $r['email_address']
											),
											SpreedParticipant::extractNameArrayFromDisplayName($r['display_name'])
									);
						}
					}

					$data["participants"] = array("user" => $users);
					if(count($users) >= 1){
						array_push($this->responseData["action"], $data);
					}
					// Finished loading all the participants


					// Process all the attachments of this email
					$data = array();
					$data["attributes"] = array("type" => "addAttachments");
					$attachmentArray = array();

					// Start counting at 0 for the attachments
					$i = 0;

					// First locate where to to store the attachments in the Session
					$dialog_attachments = $action['dialog_attachments'];

					// Open the message from MAPI
					$copyfromStore = $GLOBALS["mapisession"]->openMessageStore(hex2bin($action['store']));
					$copyfrom = mapi_msgstore_openentry($copyfromStore ,  hex2bin($action['entryid']));

					// Open the attachment table if it is available
					$attachmentTable = mapi_message_getattachmenttable($copyfrom);
					if($attachmentTable) {
						// Query the attachment table for all attachments and their related
						// number, size, filename, etc.
						$attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD));

						// Loop through the attachments
						foreach($attachments as $attach_props){
							if ($attach_props[PR_ATTACH_METHOD] == 5)
								continue;

							// Set the default filename to ERROR, in case we could not extract the
							// filename correctly this will be shown to the user.
							$filename = "ERROR";

							// Try to obtain the real filename from the MAPI record
							if(isset($attach_props[PR_ATTACH_LONG_FILENAME])) {
								$filename = $attach_props[PR_ATTACH_LONG_FILENAME];
							} else if(isset($attach_props[PR_ATTACH_FILENAME])) {
								$filename = $attach_props[PR_ATTACH_FILENAME];
							} else if(isset($attach_props[PR_DISPLAY_NAME])) {
								$filename = $attach_props[PR_DISPLAY_NAME];
							}

							// Create a temporary file location based on the filename
							$tmpname = tempnam(TMP_PATH, stripslashes($filename));

							// Set the default Content Type
							$contentType = "application/octet-stream";

							// Set the content type based on the filename
							$contentType = getMIMEType($filename);

							if($contentType == "message/rfc822") {
								/**
								* check content type that is send by browser because content type for
								* eml attachments will be message/rfc822, but this content type is used
								* for message-in-message embedded objects, so we have to send it as
								* application/octet-stream.
								*/
								$contentType = "application/octet-stream";
							}

							// Check if there are no files uploaded
							if(!isset($_SESSION["files"])) {
								$_SESSION["files"] = array();
							}

							// Check if no files are uploaded with this dialog_attachments
							if(!isset($_SESSION["files"][$dialog_attachments])) {
								$_SESSION["files"][$dialog_attachments] = array();
							}

							// Strip path details
							$tmpname = basename($tmpname);

							// Add file information to the session
							$_SESSION["files"][$dialog_attachments][$tmpname] = Array(
								"name"       => stripslashes($filename),
								"size"       => $attach_props[PR_ATTACH_SIZE],
								"origatnum"  => $attach_props[PR_ATTACH_NUM],
								"type"       => $contentType,
								"storeid"    => $action['store'],
								"entryid"    => $action['entryid'],
								"sourcetype" => 'default'
							);

							// Make a new attachment object that will make the attachment
							// visible on the client side.
							// FIXME Fix the following if you ever want to store the meeting on the MAPI server:
							//       at the moment the attach_num value is set to the length of the array of files,
							//       however, the number should be changed to the number that we got from MAPI if
							//       we store it on the MAPI server.
							$attachmentArray[] = array(
													'attributes' => array('id' => $i++),
													'attach_num' => count($_SESSION["files"][$dialog_attachments]),
													'name' => stripslashes($filename),
													'size' => $attach_props[PR_ATTACH_SIZE],
													'filetype' => $contentType
												);

						}
						$data["attachments"] = array("attachment" => $attachmentArray);
						if(count($attachmentArray) >= 1){
							array_push($this->responseData["action"], $data);
						}
					}

					if(count($attachmentArray) >= 1 || count($users) >= 1){
						$GLOBALS["bus"]->addData($this->responseData);
						$result = true;
					}
				}
			}

			return $result;
		}

	}
?>
