/**
  * Checks if there has been any significant changes on appointment/meeting item.
  * Significant changes be:
  * 1) startdate has been changed
  * 2) duedate has been changed OR
  * 3) recurrence pattern has been created, modified or removed
  *
  * @param Array oldProps old props before an update
  * @param Number basedate basedate
  * @param Boolean isRecurrenceChanged for change in recurrence pattern.
  * isRecurrenceChanged true means Recurrence pattern has been changed, so clear all attendees response
  */
 function checkSignificantChanges($oldProps, $basedate, $isRecurrenceChanged = false)
 {
     $message = null;
     $attach = null;
     // If basedate is specified then we need to open exception message to clear recipient responses
     if ($basedate) {
         $recurrence = new Recurrence($this->store, $this->message);
         if ($recurrence->isException($basedate)) {
             $attach = $recurrence->getExceptionAttachment($basedate);
             if ($attach) {
                 $message = mapi_attach_openobj($attach, MAPI_MODIFY);
             }
         }
     } else {
         // use normal message or recurring series message
         $message = $this->message;
     }
     if (!$message) {
         return;
     }
     $newProps = mapi_getprops($message, array($this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['updatecounter']));
     // Check whether message is updated or not.
     if (isset($newProps[$this->proptags['updatecounter']]) && $newProps[$this->proptags['updatecounter']] == 0) {
         return;
     }
     if ($newProps[$this->proptags['startdate']] != $oldProps[$this->proptags['startdate']] || $newProps[$this->proptags['duedate']] != $oldProps[$this->proptags['duedate']] || $isRecurrenceChanged) {
         $this->clearRecipientResponse($message);
         mapi_setprops($message, array($this->proptags['owner_critical_change'] => time()));
         mapi_savechanges($message);
         if ($attach) {
             // Also save attachment Object.
             mapi_savechanges($attach);
         }
     }
 }
Ejemplo n.º 2
0
 /**
  * Reads recurrence information from MAPI
  *
  * @param mixed             $mapimessage
  * @param array             $recurprops
  * @param SyncObject        &$syncMessage       the message
  * @param SyncObject        &$syncRecurrence    the  recurrence message
  * @param array             $tz                 timezone information
  *
  * @access private
  * @return
  */
 private function getRecurrence($mapimessage, $recurprops, &$syncMessage, &$syncRecurrence, $tz)
 {
     if ($syncRecurrence instanceof SyncTaskRecurrence) {
         $recurrence = new TaskRecurrence($this->store, $mapimessage);
     } else {
         $recurrence = new Recurrence($this->store, $mapimessage);
     }
     switch ($recurrence->recur["type"]) {
         case 10:
             // daily
             switch ($recurrence->recur["subtype"]) {
                 default:
                     $syncRecurrence->type = 0;
                     break;
                 case 1:
                     $syncRecurrence->type = 0;
                     $syncRecurrence->dayofweek = 62;
                     // mon-fri
                     $syncRecurrence->interval = 1;
                     break;
             }
             break;
         case 11:
             // weekly
             $syncRecurrence->type = 1;
             break;
         case 12:
             // monthly
             switch ($recurrence->recur["subtype"]) {
                 default:
                     $syncRecurrence->type = 2;
                     break;
                 case 3:
                     $syncRecurrence->type = 3;
                     break;
             }
             break;
         case 13:
             // yearly
             switch ($recurrence->recur["subtype"]) {
                 default:
                     $syncRecurrence->type = 4;
                     break;
                 case 2:
                     $syncRecurrence->type = 5;
                     break;
                 case 3:
                     $syncRecurrence->type = 6;
             }
     }
     // Termination
     switch ($recurrence->recur["term"]) {
         case 0x21:
             $syncRecurrence->until = $recurrence->recur["end"];
             // fixes Mantis #350 : recur-end does not consider timezones - use ClipEnd if available
             if (isset($recurprops[$recurrence->proptags["enddate_recurring"]])) {
                 $syncRecurrence->until = $recurprops[$recurrence->proptags["enddate_recurring"]];
             }
             // add one day (minus 1 sec) to the end time to make sure the last occurrence is covered
             $syncRecurrence->until += 86399;
             break;
         case 0x22:
             $syncRecurrence->occurrences = $recurrence->recur["numoccur"];
             break;
         case 0x23:
             // never ends
             break;
     }
     // Correct 'alldayevent' because outlook fails to set it on recurring items of 24 hours or longer
     if (isset($recurrence->recur["endocc"], $recurrence->recur["startocc"]) && $recurrence->recur["endocc"] - $recurrence->recur["startocc"] >= 1440) {
         $syncMessage->alldayevent = true;
     }
     // Interval is different according to the type/subtype
     switch ($recurrence->recur["type"]) {
         case 10:
             if ($recurrence->recur["subtype"] == 0) {
                 $syncRecurrence->interval = (int) ($recurrence->recur["everyn"] / 1440);
             }
             // minutes
             break;
         case 11:
         case 12:
             $syncRecurrence->interval = $recurrence->recur["everyn"];
             break;
             // months / weeks
         // months / weeks
         case 13:
             $syncRecurrence->interval = (int) ($recurrence->recur["everyn"] / 12);
             break;
             // months
     }
     if (isset($recurrence->recur["weekdays"])) {
         $syncRecurrence->dayofweek = $recurrence->recur["weekdays"];
     }
     // bitmask of days (1 == sunday, 128 == saturday
     if (isset($recurrence->recur["nday"])) {
         $syncRecurrence->weekofmonth = $recurrence->recur["nday"];
     }
     // N'th {DAY} of {X} (0-5)
     if (isset($recurrence->recur["month"])) {
         $syncRecurrence->monthofyear = (int) ($recurrence->recur["month"] / (60 * 24 * 29)) + 1;
     }
     // works ok due to rounding. see also $monthminutes below (1-12)
     if (isset($recurrence->recur["monthday"])) {
         $syncRecurrence->dayofmonth = $recurrence->recur["monthday"];
     }
     // day of month (1-31)
     // All changed exceptions are appointments within the 'exceptions' array. They contain the same items as a normal appointment
     foreach ($recurrence->recur["changed_occurences"] as $change) {
         $exception = new SyncAppointmentException();
         // start, end, basedate, subject, remind_before, reminderset, location, busystatus, alldayevent, label
         if (isset($change["start"])) {
             $exception->starttime = $this->getGMTTimeByTZ($change["start"], $tz);
         }
         if (isset($change["end"])) {
             $exception->endtime = $this->getGMTTimeByTZ($change["end"], $tz);
         }
         if (isset($change["basedate"])) {
             $exception->exceptionstarttime = $this->getGMTTimeByTZ($this->getDayStartOfTimestamp($change["basedate"]) + $recurrence->recur["startocc"] * 60, $tz);
             //open body because getting only property might not work because of memory limit
             $exceptionatt = $recurrence->getExceptionAttachment($change["basedate"]);
             if ($exceptionatt) {
                 $exceptionobj = mapi_attach_openobj($exceptionatt, 0);
                 $this->setMessageBodyForType($exceptionobj, SYNC_BODYPREFERENCE_PLAIN, $exception);
             }
         }
         if (isset($change["subject"])) {
             $exception->subject = w2u($change["subject"]);
         }
         if (isset($change["reminder_before"]) && $change["reminder_before"]) {
             $exception->reminder = $change["remind_before"];
         }
         if (isset($change["location"])) {
             $exception->location = w2u($change["location"]);
         }
         if (isset($change["busystatus"])) {
             $exception->busystatus = $change["busystatus"];
         }
         if (isset($change["alldayevent"])) {
             $exception->alldayevent = $change["alldayevent"];
         }
         // set some data from the original appointment
         if (isset($syncMessage->uid)) {
             $exception->uid = $syncMessage->uid;
         }
         if (isset($syncMessage->organizername)) {
             $exception->organizername = $syncMessage->organizername;
         }
         if (isset($syncMessage->organizeremail)) {
             $exception->organizeremail = $syncMessage->organizeremail;
         }
         if (!isset($syncMessage->exceptions)) {
             $syncMessage->exceptions = array();
         }
         array_push($syncMessage->exceptions, $exception);
     }
     // Deleted appointments contain only the original date (basedate) and a 'deleted' tag
     foreach ($recurrence->recur["deleted_occurences"] as $deleted) {
         $exception = new SyncAppointmentException();
         $exception->exceptionstarttime = $this->getGMTTimeByTZ($this->getDayStartOfTimestamp($deleted) + $recurrence->recur["startocc"] * 60, $tz);
         $exception->deleted = "1";
         if (!isset($syncMessage->exceptions)) {
             $syncMessage->exceptions = array();
         }
         array_push($syncMessage->exceptions, $exception);
     }
     if (isset($syncMessage->complete) && $syncMessage->complete) {
         $syncRecurrence->complete = $syncMessage->complete;
     }
 }
 /**
  * Function returns exception item based on the basedate passed.
  * @param MAPIMessage $recurringMessage Resource of Recurring meeting from calendar
  * @param Unixtime $basedate basedate of exception that needs to be returned.
  * @param MAPIStore $store store that contains the recurring calendar item.
  * @return entryid or MAPIMessage resource of exception item.
  */
 function getExceptionItem($recurringMessage, $basedate, $store = false)
 {
     $occurItem = false;
     $props = mapi_getprops($this->message, array(PR_RCVD_REPRESENTING_NAME, $this->proptags['recurring']));
     // check if the passed item is recurring series
     if ($props[$this->proptags['recurring']] !== false) {
         return false;
     }
     if ($store === false) {
         // If Delegate is processing Meeting Request/Response for Delegator then retrieve Delegator's store and calendar.
         if (isset($props[PR_RCVD_REPRESENTING_NAME])) {
             $delegatorStore = $this->getDelegatorStore($props[PR_RCVD_REPRESENTING_NAME]);
             $store = $delegatorStore['store'];
         } else {
             $store = $this->store;
         }
     }
     $recurr = new Recurrence($store, $recurringMessage);
     $attach = $recurr->getExceptionAttachment($basedate);
     if ($attach) {
         $occurItem = mapi_attach_openobj($attach);
     }
     return $occurItem;
 }
Ejemplo n.º 4
0
 /**
  * Get an exception attachment based on its basedate
  */
 function getExceptionAttachment($base_date)
 {
     // Retrieve only embedded messages
     $attach_res = array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_ATTACH_METHOD, VALUE => array(PR_ATTACH_METHOD => 5)))));
     $attachments = mapi_message_getattachmenttable($this->message);
     $attachRows = mapi_table_queryallrows($attachments, array(PR_ATTACH_NUM), $attach_res);
     if (is_array($attachRows)) {
         foreach ($attachRows as $attachRow) {
             $tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]);
             $exception = mapi_attach_openobj($tempattach);
             $data = mapi_message_getprops($exception, array($this->proptags["basedate"]));
             if (isset($data[$this->proptags["basedate"]]) && $this->isSameDay($this->fromGMT($this->tz, $data[$this->proptags["basedate"]]), $base_date)) {
                 return $tempattach;
             }
         }
     }
     return false;
 }
Ejemplo n.º 5
0
function buildEMLAttachment($attach)
{
    $msgembedded = mapi_attach_openobj($attach);
    $msgprops = mapi_getprops($msgembedded, array(PR_MESSAGE_CLASS, PR_CLIENT_SUBMIT_TIME, PR_DISPLAY_TO, PR_SUBJECT, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS));
    $msgembeddedrcpttable = mapi_message_getrecipienttable($msgembedded);
    $msgto = $msgprops[PR_DISPLAY_TO];
    if ($msgembeddedrcpttable) {
        $msgembeddedrecipients = mapi_table_queryrows($msgembeddedrcpttable, array(PR_ADDRTYPE, PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_RECIPIENT_TYPE, PR_RECIPIENT_FLAGS, PR_PROPOSEDNEWTIME, PR_PROPOSENEWTIME_START, PR_PROPOSENEWTIME_END, PR_RECIPIENT_TRACKSTATUS), 0, 99999999);
        foreach ($msgembeddedrecipients as $rcpt) {
            if ($rcpt[PR_DISPLAY_NAME] == $msgprops[PR_DISPLAY_TO]) {
                $msgto = $rcpt[PR_DISPLAY_NAME];
                if (isset($rcpt[PR_EMAIL_ADDRESS]) && $rcpt[PR_EMAIL_ADDRESS] != $msgprops[PR_DISPLAY_TO]) {
                    $msgto .= " <" . $rcpt[PR_EMAIL_ADDRESS] . ">";
                }
                break;
            }
        }
    }
    $msgsubject = $msgprops[PR_SUBJECT];
    $msgfrom = $msgprops[PR_SENT_REPRESENTING_NAME];
    if (isset($msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS]) && $msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] != $msgprops[PR_SENT_REPRESENTING_NAME]) {
        $msgfrom .= " <" . $msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] . ">";
    }
    $msgtime = $msgprops[PR_CLIENT_SUBMIT_TIME];
    $msgembeddedbody = eml_ReadMessage($msgembedded);
    $msgembeddedattachtable = mapi_message_getattachmenttable($msgembedded);
    $msgembeddedattachtablerows = mapi_table_queryallrows($msgembeddedattachtable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD));
    if ($msgembeddedattachtablerows) {
        $boundary = '=_zpush_static';
        $headercontenttype = "multipart/mixed";
        $msgembeddedbody['body'] = "Unfortunately your mobile is not able to handle MIME Messages\n" . "--" . $boundary . "\n" . "Content-Type: " . $msgembeddedbody['content'] . "; charset=utf-8\n" . "Content-Transfer-Encoding: quoted-printable\n\n" . $msgembeddedbody['body'] . "\n";
        foreach ($msgembeddedattachtablerows as $msgembeddedattachtablerow) {
            $msgembeddedattach = mapi_message_openattach($msgembedded, $msgembeddedattachtablerow[PR_ATTACH_NUM]);
            if (!$msgembeddedattach) {
                debugLog("Unable to open attachment number {$attachnum}");
            } else {
                $msgembeddedattachprops = mapi_getprops($msgembeddedattach, array(PR_ATTACH_MIME_TAG, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_DISPLAY_NAME));
                if (isset($msgembeddedattachprops[PR_ATTACH_LONG_FILENAME])) {
                    $attachfilename = w2u($msgembeddedattachprops[PR_ATTACH_LONG_FILENAME]);
                } else {
                    if (isset($msgembeddedattachprops[PR_ATTACH_FILENAME])) {
                        $attachfilename = w2u($msgembeddedattachprops[PR_ATTACH_FILENAME]);
                    } else {
                        if (isset($msgembeddedattachprops[PR_DISPLAY_NAME])) {
                            $attachfilename = w2u($msgembeddedattachprops[PR_DISPLAY_NAME]);
                        } else {
                            $attachfilename = w2u("untitled");
                        }
                    }
                }
                if ($msgembeddedattachtablerow[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG) {
                    $attachfilename .= w2u(".eml");
                }
                $msgembeddedbody['body'] .= "--" . $boundary . "\n" . "Content-Type: " . $msgembeddedattachprops[PR_ATTACH_MIME_TAG] . ";\n" . " name=\"" . $attachfilename . "\"\n" . "Content-Transfer-Encoding: base64\n" . "Content-Disposition: attachment;\n" . " filename=\"" . $attachfilename . "\"\n\n";
                $msgembeddedattachstream = mapi_openpropertytostream($msgembeddedattach, PR_ATTACH_DATA_BIN);
                $msgembeddedattachment = "";
                while (1) {
                    $msgembeddedattachdata = mapi_stream_read($msgembeddedattachstream, 4096);
                    if (byte_strlen($msgembeddedattachdata) == 0) {
                        break;
                    }
                    $msgembeddedattachment .= $msgembeddedattachdata;
                }
                $msgembeddedbody['body'] .= chunk_split(base64_encode($msgembeddedattachment)) . "\n";
                unset($msgembeddedattachment);
            }
        }
        $msgembeddedbody['body'] .= "--" . $boundary . "--\n";
    } else {
        $headercontenttype = $msgembeddedbody['content'] . "; charset=utf-8";
        $boundary = '';
    }
    $msgembeddedheader = "Subject: " . $msgsubject . "\n" . "From: " . $msgfrom . "\n" . "To: " . $msgto . "\n" . "Date: " . gmstrftime("%a, %d %b %Y %T +0000", $msgprops[PR_CLIENT_SUBMIT_TIME]) . "\n" . "MIME-Version: 1.0\n" . "Content-Type: " . $headercontenttype . ";\n" . ($boundary ? " boundary=\"" . $boundary . "\"\n" : "") . "\n";
    $stream = mapi_stream_create();
    mapi_stream_setsize($stream, byte_strlen($msgembeddedheader . $msgembeddedbody['body']));
    mapi_stream_write($stream, $msgembeddedheader . $msgembeddedbody['body']);
    mapi_stream_seek($stream, 0, STREAM_SEEK_SET);
    return $stream;
}
Ejemplo n.º 6
0
 /**
  * Returns the content of the named attachment as stream
  *
  * @param string        $attname
  * @access public
  * @return SyncItemOperationsAttachment
  * @throws StatusException
  */
 public function GetAttachmentData($attname)
 {
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZarafaBackend->GetAttachmentData('%s')", $attname));
     if (!strpos($attname, ":")) {
         throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, attachment requested for non-existing item", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
     }
     list($id, $attachnum) = explode(":", $attname);
     $entryid = hex2bin($id);
     $message = mapi_msgstore_openentry($this->store, $entryid);
     if (!$message) {
         throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, unable to open item for attachment data for id '%s' with: 0x%X", $attname, $id, mapi_last_hresult()), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
     }
     $attach = mapi_message_openattach($message, $attachnum);
     if (!$attach) {
         throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, unable to open attachment number '%s' with: 0x%X", $attname, $attachnum, mapi_last_hresult()), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
     }
     // get necessary attachment props
     $attprops = mapi_getprops($attach, array(PR_ATTACH_MIME_TAG, PR_ATTACH_MIME_TAG_W, PR_ATTACH_METHOD));
     $attachment = new SyncItemOperationsAttachment();
     // check if it's an embedded message and open it in such a case
     if (isset($attprops[PR_ATTACH_METHOD]) && $attprops[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG) {
         $embMessage = mapi_attach_openobj($attach);
         $addrbook = $this->getAddressbook();
         $stream = mapi_inetmapi_imtoinet($this->session, $addrbook, $embMessage, array('use_tnef' => -1));
         // set the default contenttype for this kind of messages
         $attachment->contenttype = "message/rfc822";
     } else {
         $stream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN);
     }
     if (!$stream) {
         throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, unable to open attachment data stream: 0x%X", $attname, mapi_last_hresult()), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
     }
     // put the mapi stream into a wrapper to get a standard stream
     $attachment->data = MapiStreamWrapper::Open($stream);
     if (isset($attprops[PR_ATTACH_MIME_TAG])) {
         $attachment->contenttype = $attprops[PR_ATTACH_MIME_TAG];
     } elseif (isset($attprops[PR_ATTACH_MIME_TAG_W])) {
         $attachment->contenttype = $attprops[PR_ATTACH_MIME_TAG_W];
     }
     //TODO default contenttype
     return $attachment;
 }
Ejemplo n.º 7
0
 /**
  * Get an exception attachment based on its basedate
  */
 function getExceptionAttachment($base_date)
 {
     // Retrieve only exceptions which are stored as embedded messages
     $attach_res = array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_ATTACH_METHOD, VALUE => array(PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG)))));
     $attachments = mapi_message_getattachmenttable($this->message);
     $attachRows = mapi_table_queryallrows($attachments, array(PR_ATTACH_NUM), $attach_res);
     if (is_array($attachRows)) {
         foreach ($attachRows as $attachRow) {
             $tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]);
             $exception = mapi_attach_openobj($tempattach);
             $data = mapi_message_getprops($exception, array($this->proptags["basedate"]));
             if (!isset($data[$this->proptags["basedate"]])) {
                 // if no basedate found then it could be embedded message so ignore it
                 // we need proper restriction to exclude embedded messages aswell
                 continue;
             }
             if ($this->isSameDay($this->fromGMT($this->tz, $data[$this->proptags["basedate"]]), $base_date)) {
                 return $tempattach;
             }
         }
     }
     return false;
 }