/**
 * Publishing the FreeBusy information of the default calendar. The 
 * folderentryid argument is used to check if the default calendar 
 * should be updated or not.
 * 
 * @param $store MAPIobject Store object of the store that needs publishing
 * @param $folderentryid binary entryid of the folder that needs to be updated.
 */
function publishFreeBusy($store, $l_rSession, $folderentryid = false)
{
    // Publish updated free/busy information
    // First get default calendar from the root folder
    $rootFolder = mapi_msgstore_openentry($store, null);
    $rootFolderProps = mapi_getprops($rootFolder, array(PR_IPM_APPOINTMENT_ENTRYID));
    // If no folderentryid supplied or if the supplied entryid matches the default calendar.
    if (!$folderentryid || $rootFolderProps[PR_IPM_APPOINTMENT_ENTRYID] == $folderentryid) {
        // Get the calendar and owner entryID
        $calendar = mapi_msgstore_openentry($store, $rootFolderProps[PR_IPM_APPOINTMENT_ENTRYID]);
        $storeProps = mapi_msgstore_getprops($store, array(PR_MAILBOX_OWNER_ENTRYID));
        if (isset($storeProps[PR_MAILBOX_OWNER_ENTRYID])) {
            // Lets share!
            $pub = new FreeBusyPublish($l_rSession, $store, $calendar, $storeProps[PR_MAILBOX_OWNER_ENTRYID]);
            $pub->publishFB(time() - 7 * 24 * 60 * 60, 6 * 30 * 24 * 60 * 60);
            // publish from one week ago, 6 months ahead
        }
    }
}
 /**
  * Function creates meeting item in resource's calendar.
  *@param resource $message MAPI_message which is to create in resource's calendar
  *@param boolean $cancel cancel meeting
  *@param string $prefix prefix for subject of meeting
  */
 function bookResources($message, $cancel, $prefix, $basedate = false)
 {
     if (!$this->enableDirectBooking) {
         return array();
     }
     // Get the properties of the message
     $messageprops = mapi_getprops($message);
     if ($basedate) {
         $recurrItemProps = mapi_getprops($this->message, array($this->proptags['goid'], $this->proptags['goid2'], $this->proptags['timezone_data'], $this->proptags['timezone'], PR_OWNER_APPT_ID));
         $messageprops[$this->proptags['goid']] = $this->setBasedateInGlobalID($recurrItemProps[$this->proptags['goid']], $basedate);
         $messageprops[$this->proptags['goid2']] = $recurrItemProps[$this->proptags['goid2']];
         // Delete properties which are not needed.
         $deleteProps = array($this->proptags['basedate'], PR_DISPLAY_NAME, PR_ATTACHMENT_FLAGS, PR_ATTACHMENT_HIDDEN, PR_ATTACHMENT_LINKID, PR_ATTACH_FLAGS, PR_ATTACH_METHOD);
         foreach ($deleteProps as $propID) {
             if (isset($messageprops[$propID])) {
                 unset($messageprops[$propID]);
             }
         }
         if (isset($messageprops[$this->proptags['recurring']])) {
             $messageprops[$this->proptags['recurring']] = false;
         }
         // Set Outlook properties
         $messageprops[$this->proptags['clipstart']] = $messageprops[$this->proptags['startdate']];
         $messageprops[$this->proptags['clipend']] = $messageprops[$this->proptags['duedate']];
         $messageprops[$this->proptags['timezone_data']] = $recurrItemProps[$this->proptags['timezone_data']];
         $messageprops[$this->proptags['timezone']] = $recurrItemProps[$this->proptags['timezone']];
         $messageprops[$this->proptags['attendee_critical_change']] = time();
         $messageprops[$this->proptags['owner_critical_change']] = time();
     }
     // Get resource recipients
     $getResourcesRestriction = array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_RECIPIENT_TYPE, VALUE => array(PR_RECIPIENT_TYPE => MAPI_BCC)))));
     $recipienttable = mapi_message_getrecipienttable($message);
     $resourceRecipients = mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
     $this->errorSetResource = false;
     $resourceRecipData = array();
     // Put appointment into store resource users
     $i = 0;
     $len = count($resourceRecipients);
     while (!$this->errorSetResource && $i < $len) {
         $request = array(array(PR_DISPLAY_NAME => $resourceRecipients[$i][PR_DISPLAY_NAME]));
         $ab = mapi_openaddressbook($this->session);
         $ret = mapi_ab_resolvename($ab, $request, EMS_AB_ADDRESS_LOOKUP);
         $result = mapi_last_hresult();
         if ($result == NOERROR) {
             $result = $ret[0][PR_ENTRYID];
         }
         $resourceUsername = $ret[0][PR_EMAIL_ADDRESS];
         $resourceABEntryID = $ret[0][PR_ENTRYID];
         // Get StoreEntryID by username
         $user_entryid = mapi_msgstore_createentryid($this->store, $resourceUsername);
         // Open store of the user
         $userStore = mapi_openmsgstore($this->session, $user_entryid);
         // Open root folder
         $userRoot = mapi_msgstore_openentry($userStore, null);
         // Get calendar entryID
         $userRootProps = mapi_getprops($userRoot, array(PR_STORE_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_FREEBUSY_ENTRYIDS));
         // Open Calendar folder   [check hresult==0]
         $accessToFolder = false;
         try {
             $calFolder = mapi_msgstore_openentry($userStore, $userRootProps[PR_IPM_APPOINTMENT_ENTRYID]);
             if ($calFolder) {
                 $calFolderProps = mapi_getProps($calFolder, array(PR_ACCESS));
                 if (($calFolderProps[PR_ACCESS] & MAPI_ACCESS_CREATE_CONTENTS) !== 0) {
                     $accessToFolder = true;
                 }
             }
         } catch (MAPIException $e) {
             $e->setHandled();
             $this->errorSetResource = 1;
             // No access
         }
         if ($accessToFolder) {
             /**
              * Get the LocalFreebusy message that contains the properties that
              * are set to accept or decline resource meeting requests
              */
             // Use PR_FREEBUSY_ENTRYIDS[1] to open folder the LocalFreeBusy msg
             $localFreebusyMsg = mapi_msgstore_openentry($userStore, $userRootProps[PR_FREEBUSY_ENTRYIDS][1]);
             if ($localFreebusyMsg) {
                 $props = mapi_getprops($localFreebusyMsg, array(PR_PROCESS_MEETING_REQUESTS, PR_DECLINE_RECURRING_MEETING_REQUESTS, PR_DECLINE_CONFLICTING_MEETING_REQUESTS));
                 $acceptMeetingRequests = $props[PR_PROCESS_MEETING_REQUESTS] ? 1 : 0;
                 $declineRecurringMeetingRequests = $props[PR_DECLINE_RECURRING_MEETING_REQUESTS] ? 1 : 0;
                 $declineConflictingMeetingRequests = $props[PR_DECLINE_CONFLICTING_MEETING_REQUESTS] ? 1 : 0;
                 if (!$acceptMeetingRequests) {
                     /**
                      * When a resource has not been set to automatically accept meeting requests,
                      * the meeting request has to be sent to him rather than being put directly into
                      * his calendar. No error should be returned.
                      */
                     //$errorSetResource = 2;
                     $this->nonAcceptingResources[] = $resourceRecipients[$i];
                 } else {
                     if ($declineRecurringMeetingRequests && !$cancel) {
                         // Check if appointment is recurring
                         if ($messageprops[$this->proptags['recurring']]) {
                             $this->errorSetResource = 3;
                         }
                     }
                     if ($declineConflictingMeetingRequests && !$cancel) {
                         // Check for conflicting items
                         $conflicting = false;
                         // Open the calendar
                         $calFolder = mapi_msgstore_openentry($userStore, $userRootProps[PR_IPM_APPOINTMENT_ENTRYID]);
                         if ($calFolder) {
                             if ($this->isMeetingConflicting($message, $userStore, $calFolder, $messageprops)) {
                                 $conflicting = true;
                             }
                         } else {
                             $this->errorSetResource = 1;
                             // No access
                         }
                         if ($conflicting) {
                             $this->errorSetResource = 4;
                             // Conflict
                         }
                     }
                 }
             }
         }
         if (!$this->errorSetResource && $accessToFolder) {
             /**
              * First search on GlobalID(0x3)
              * If (recurring and occurrence) If Resource was booked for only this occurrence then Resource should have only this occurrence in Calendar and not whole series.
              * If (normal meeting) then GlobalID(0x3) and CleanGlobalID(0x23) are same, so doesnt matter if search is based on GlobalID.
              */
             $rows = $this->findCalendarItems($messageprops[$this->proptags['goid']], $calFolder);
             /**
              * If no entry is found then
              * 1) Resource doesnt have meeting in Calendar. Seriously!!
              * OR
              * 2) We were looking for occurrence item but Resource has whole series
              */
             if (empty($rows)) {
                 /**
                  * Now search on CleanGlobalID(0x23) WHY???
                  * Because we are looking recurring item
                  *
                  * Possible results of this search
                  * 1) If Resource was booked for more than one occurrences then this search will return all those occurrence because search is perform on CleanGlobalID
                  * 2) If Resource was booked for whole series then it should return series.
                  */
                 $rows = $this->findCalendarItems($messageprops[$this->proptags['goid2']], $calFolder, true);
                 $newResourceMsg = false;
                 if (!empty($rows)) {
                     // Since we are looking for recurring item, open every result and check for 'recurring' property.
                     foreach ($rows as $row) {
                         $ResourceMsg = mapi_msgstore_openentry($userStore, $row);
                         $ResourceMsgProps = mapi_getprops($ResourceMsg, array($this->proptags['recurring']));
                         if (isset($ResourceMsgProps[$this->proptags['recurring']]) && $ResourceMsgProps[$this->proptags['recurring']]) {
                             $newResourceMsg = $ResourceMsg;
                             break;
                         }
                     }
                 }
                 // Still no results found. I giveup, create new message.
                 if (!$newResourceMsg) {
                     $newResourceMsg = mapi_folder_createmessage($calFolder);
                 }
             } else {
                 $newResourceMsg = mapi_msgstore_openentry($userStore, $rows[0]);
             }
             // Prefix the subject if needed
             if ($prefix && isset($messageprops[PR_SUBJECT])) {
                 $messageprops[PR_SUBJECT] = $prefix . $messageprops[PR_SUBJECT];
             }
             // Set status to cancelled if needed
             $messageprops[$this->proptags['busystatus']] = fbBusy;
             // The default status (Busy)
             if ($cancel) {
                 $messageprops[$this->proptags['meetingstatus']] = olMeetingCanceled;
                 // The meeting has been canceled
                 $messageprops[$this->proptags['busystatus']] = fbFree;
                 // Free
             } else {
                 $messageprops[$this->proptags['meetingstatus']] = olMeetingReceived;
                 // The recipient is receiving the request
             }
             $messageprops[$this->proptags['responsestatus']] = olResponseAccepted;
             // The resource autmatically accepts the appointment
             $messageprops[PR_MESSAGE_CLASS] = "IPM.Appointment";
             // Remove the PR_ICON_INDEX as it is not needed in the sent message and it also
             // confuses the Zarafa webaccess
             $messageprops[PR_ICON_INDEX] = null;
             $messageprops[PR_RESPONSE_REQUESTED] = true;
             $addrinfo = $this->getOwnerAddress($this->store);
             if ($addrinfo) {
                 list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $addrinfo;
                 $messageprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
                 $messageprops[PR_SENT_REPRESENTING_NAME] = $ownername;
                 $messageprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
                 $messageprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
                 $messageprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
                 $messageprops[$this->proptags['apptreplyname']] = $ownername;
                 $messageprops[$this->proptags['replytime']] = time();
             }
             if ($basedate && isset($ResourceMsgProps[$this->proptags['recurring']]) && $ResourceMsgProps[$this->proptags['recurring']]) {
                 $recurr = new Recurrence($userStore, $newResourceMsg);
                 // Copy recipients list
                 $reciptable = mapi_message_getrecipienttable($message);
                 $recips = mapi_table_queryallrows($reciptable, $this->recipprops);
                 // add owner to recipient table
                 $this->addOrganizer($messageprops, $recips, true);
                 // Update occurrence
                 if ($recurr->isException($basedate)) {
                     $recurr->modifyException($messageprops, $basedate, $recips);
                 } else {
                     $recurr->createException($messageprops, $basedate, false, $recips);
                 }
             } else {
                 mapi_setprops($newResourceMsg, $messageprops);
                 // Copy attachments
                 $this->replaceAttachments($message, $newResourceMsg);
                 // Copy all recipients too
                 $this->replaceRecipients($message, $newResourceMsg);
                 // Now add organizer also to recipient table
                 $recips = array();
                 $this->addOrganizer($messageprops, $recips);
                 mapi_message_modifyrecipients($newResourceMsg, MODRECIP_ADD, $recips);
             }
             mapi_savechanges($newResourceMsg);
             $resourceRecipData[] = array('store' => $userStore, 'folder' => $calFolder, 'msg' => $newResourceMsg);
             $this->includesResources = true;
         } else {
             /**
              * If no other errors occured and you have no access to the
              * folder of the resource, throw an error=1.
              */
             if (!$this->errorSetResource) {
                 $this->errorSetResource = 1;
             }
             for ($j = 0, $len = count($resourceRecipData); $j < $len; $j++) {
                 // Get the EntryID
                 $props = mapi_message_getprops($resourceRecipData[$j]['msg']);
                 mapi_folder_deletemessages($resourceRecipData[$j]['folder'], array($props[PR_ENTRYID]), DELETE_HARD_DELETE);
             }
             $this->recipientDisplayname = $resourceRecipients[$i][PR_DISPLAY_NAME];
         }
         $i++;
     }
     /**************************************************************
      * Set the BCC-recipients (resources) tackstatus to accepted.
      */
     // Get resource recipients
     $getResourcesRestriction = array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_RECIPIENT_TYPE, VALUE => array(PR_RECIPIENT_TYPE => MAPI_BCC)))));
     $recipienttable = mapi_message_getrecipienttable($message);
     $resourceRecipients = mapi_table_queryallrows($recipienttable, $this->recipprops, $getResourcesRestriction);
     if (!empty($resourceRecipients)) {
         // Set Tracking status of resource recipients to olResponseAccepted (3)
         for ($i = 0, $len = count($resourceRecipients); $i < $len; $i++) {
             $resourceRecipients[$i][PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusAccepted;
             $resourceRecipients[$i][PR_RECIPIENT_TRACKSTATUS_TIME] = time();
         }
         mapi_message_modifyrecipients($message, MODRECIP_MODIFY, $resourceRecipients);
     }
     // Publish updated free/busy information
     if (!$this->errorSetResource) {
         for ($i = 0, $len = count($resourceRecipData); $i < $len; $i++) {
             $storeProps = mapi_msgstore_getprops($resourceRecipData[$i]['store'], array(PR_MAILBOX_OWNER_ENTRYID));
             if (isset($storeProps[PR_MAILBOX_OWNER_ENTRYID])) {
                 $pub = new FreeBusyPublish($this->session, $resourceRecipData[$i]['store'], $resourceRecipData[$i]['folder'], $storeProps[PR_MAILBOX_OWNER_ENTRYID]);
                 $pub->publishFB(time() - 7 * 24 * 60 * 60, 6 * 30 * 24 * 60 * 60);
                 // publish from one week ago, 6 months ahead
             }
         }
     }
     return $resourceRecipData;
 }