/** * Pack timezone info for Sync * * @param array $tz * * @access private * @return string */ private function getSyncBlobFromTZ($tz) { // set the correct TZ name (done using the Bias) if (!isset($tz["tzname"]) || !$tz["tzname"] || !isset($tz["tznamedst"]) || !$tz["tznamedst"]) { $tz = TimezoneUtil::FillTZNames($tz); } $packed = pack("la64vvvvvvvv" . "la64vvvvvvvv" . "l", $tz["bias"], $tz["tzname"], 0, $tz["dstendmonth"], $tz["dstendday"], $tz["dstendweek"], $tz["dstendhour"], $tz["dstendminute"], $tz["dstendsecond"], $tz["dstendmillis"], $tz["stdbias"], $tz["tznamedst"], 0, $tz["dststartmonth"], $tz["dststartday"], $tz["dststartweek"], $tz["dststarthour"], $tz["dststartminute"], $tz["dststartsecond"], $tz["dststartmillis"], $tz["dstbias"]); return $packed; }
/** * Converts a text/calendar part into SyncMeetingRequest * This is called on received messages, it's not called for events generated from the mobile * * @access private * @param $part MIME part * @param $output SyncMail object * @param $is_sent_folder boolean */ function parse_meeting_calendar($part, &$output, $is_sent_folder) { $ical = new iCalComponent(); $ical->ParseFrom($part->body); ZLog::Write(LOGLEVEL_WBXML, sprintf("BackendIMAP->parse_meeting_calendar(): %s", $part->body)); // Get UID $uid = false; $props = $ical->GetPropertiesByPath("VEVENT/UID"); if (count($props) > 0) { $uid = $props[0]->Value(); } $method = false; $props = $ical->GetPropertiesByPath("VCALENDAR/METHOD"); if (count($props) > 0) { $method = strtolower($props[0]->Value()); ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar(): Using method from vcalendar object: %s", $method)); } else { if (isset($part->ctype_parameters["method"])) { $method = strtolower($part->ctype_parameters["method"]); ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar(): Using method from mime part object: %s", $method)); } } if ($method === false) { ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - No method header, please report it to the developers")); $output->messageclass = "IPM.Appointment"; } else { switch ($method) { case "cancel": $output->messageclass = "IPM.Schedule.Meeting.Canceled"; $output->meetingrequest->disallownewtimeproposal = 1; ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Event canceled, removing calendar object"); delete_calendar_dav($uid); break; case "counter": ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Counter received"); $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent"; $output->meetingrequest->disallownewtimeproposal = 0; break; case "reply": ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Reply received"); $props = $ical->GetPropertiesByPath('VEVENT/ATTENDEE'); for ($i = 0; $i < count($props); $i++) { $mailto = $props[$i]->Value(); $props_params = $props[$i]->Parameters(); $status = strtolower($props_params["PARTSTAT"]); if (!$is_sent_folder) { // Only evaluate received replies, not sent $res = update_calendar_attendee($uid, $mailto, $status); } else { $res = true; } if ($res) { // Only set messageclass for replies changing my calendar object switch ($status) { case "accepted": $output->messageclass = "IPM.Schedule.Meeting.Resp.Pos"; ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> accepted"); break; case "needs-action": $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent"; ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> needs-action"); break; case "tentative": $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent"; ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> tentative"); break; case "declined": $output->messageclass = "IPM.Schedule.Meeting.Resp.Neg"; ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> declined"); break; default: ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - Unknown reply status <%s>, please report it to the developers", $status)); $output->messageclass = "IPM.Appointment"; break; } } } $output->meetingrequest->disallownewtimeproposal = 1; break; case "request": $output->messageclass = "IPM.Schedule.Meeting.Request"; $output->meetingrequest->disallownewtimeproposal = 0; ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): New request"); // New meeting, we don't create it now, because we need to confirm it first, but if we don't create it we won't see it in the calendar break; default: ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - Unknown method <%s>, please report it to the developers", strtolower($part->headers["method"]))); $output->messageclass = "IPM.Appointment"; $output->meetingrequest->disallownewtimeproposal = 0; break; } } $props = $ical->GetPropertiesByPath('VEVENT/DTSTAMP'); if (count($props) == 1) { $output->meetingrequest->dtstamp = Utils::MakeUTCDate($props[0]->Value()); } $props = $ical->GetPropertiesByPath('VEVENT/UID'); if (count($props) == 1) { $output->meetingrequest->globalobjid = $props[0]->Value(); } $props = $ical->GetPropertiesByPath('VEVENT/DTSTART'); if (count($props) == 1) { $output->meetingrequest->starttime = Utils::MakeUTCDate($props[0]->Value()); if (strlen($props[0]->Value()) == 8) { $output->meetingrequest->alldayevent = 1; } } $props = $ical->GetPropertiesByPath('VEVENT/DTEND'); if (count($props) == 1) { $output->meetingrequest->endtime = Utils::MakeUTCDate($props[0]->Value()); if (strlen($props[0]->Value()) == 8) { $output->meetingrequest->alldayevent = 1; } } $props = $ical->GetPropertiesByPath('VEVENT/ORGANIZER'); if (count($props) == 1) { $output->meetingrequest->organizer = str_ireplace("MAILTO:", "", $props[0]->Value()); } $props = $ical->GetPropertiesByPath('VEVENT/LOCATION'); if (count($props) == 1) { $output->meetingrequest->location = $props[0]->Value(); } $props = $ical->GetPropertiesByPath('VEVENT/CLASS'); if (count($props) == 1) { switch ($props[0]->Value()) { case "PUBLIC": $output->meetingrequest->sensitivity = "0"; break; case "PRIVATE": $output->meetingrequest->sensitivity = "2"; break; case "CONFIDENTIAL": $output->meetingrequest->sensitivity = "3"; break; default: ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar() - No sensitivity class. Using 2")); $output->meetingrequest->sensitivity = "2"; break; } } // Get $tz from first timezone $props = $ical->GetPropertiesByPath("VTIMEZONE/TZID"); if (count($props) > 0) { // TimeZones shouldn't have dots $tzname = str_replace(".", "", $props[0]->Value()); $tz = TimezoneUtil::GetFullTZFromTZName($tzname); } else { $tz = TimezoneUtil::GetFullTZ(); } $output->meetingrequest->timezone = base64_encode(TimezoneUtil::GetSyncBlobFromTZ($tz)); // Fixed values $output->meetingrequest->instancetype = 0; $output->meetingrequest->responserequested = 1; $output->meetingrequest->busystatus = 2; // TODO: reminder $output->meetingrequest->reminder = ""; }
/** * Reads an email object from MAPI * * @param mixed $mapimessage * @param ContentParameters $contentparameters * * @access private * @return SyncEmail */ private function getEmail($mapimessage, $contentparameters) { $message = new SyncMail(); $this->getPropsFromMAPI($message, $mapimessage, MAPIMapping::GetEmailMapping()); $emailproperties = MAPIMapping::GetEmailProperties(); $messageprops = $this->getProps($mapimessage, $emailproperties); if (isset($messageprops[PR_SOURCE_KEY])) { $sourcekey = $messageprops[PR_SOURCE_KEY]; } else { return false; } //set the body according to contentparameters and supported AS version $this->setMessageBody($mapimessage, $contentparameters, $message); $fromname = $fromaddr = ""; if (isset($messageprops[$emailproperties["representingname"]])) { // remove encapsulating double quotes from the representingname $fromname = preg_replace('/^\\"(.*)\\"$/', "\${1}", $messageprops[$emailproperties["representingname"]]); } if (isset($messageprops[$emailproperties["representingentryid"]])) { $fromaddr = $this->getSMTPAddressFromEntryID($messageprops[$emailproperties["representingentryid"]]); } if ($fromname == $fromaddr) { $fromname = ""; } if ($fromname) { $from = "\"" . w2u($fromname) . "\" <" . w2u($fromaddr) . ">"; } else { //START CHANGED dw2412 HTC shows "error" if sender name is unknown $from = "\"" . w2u($fromaddr) . "\" <" . w2u($fromaddr) . ">"; } //END CHANGED dw2412 HTC shows "error" if sender name is unknown $message->from = $from; // process Meeting Requests if (isset($message->messageclass) && strpos($message->messageclass, "IPM.Schedule.Meeting") === 0) { $message->meetingrequest = new SyncMeetingRequest(); $this->getPropsFromMAPI($message->meetingrequest, $mapimessage, MAPIMapping::GetMeetingRequestMapping()); $meetingrequestproperties = MAPIMapping::GetMeetingRequestProperties(); $props = $this->getProps($mapimessage, $meetingrequestproperties); // Get the GOID if (isset($props[$meetingrequestproperties["goidtag"]])) { $message->meetingrequest->globalobjid = base64_encode($props[$meetingrequestproperties["goidtag"]]); } // Set Timezone if (isset($props[$meetingrequestproperties["timezonetag"]])) { $tz = $this->getTZFromMAPIBlob($props[$meetingrequestproperties["timezonetag"]]); } else { $tz = $this->getGMTTZ(); } $message->meetingrequest->timezone = base64_encode(TimezoneUtil::GetSyncBlobFromTZ($tz)); // send basedate if exception if (isset($props[$meetingrequestproperties["recReplTime"]]) || isset($props[$meetingrequestproperties["lidIsException"]]) && $props[$meetingrequestproperties["lidIsException"]] == true) { if (isset($props[$meetingrequestproperties["recReplTime"]])) { $basedate = $props[$meetingrequestproperties["recReplTime"]]; $message->meetingrequest->recurrenceid = $this->getGMTTimeByTZ($basedate, $this->getGMTTZ()); } else { if (!isset($props[$meetingrequestproperties["goidtag"]]) || !isset($props[$meetingrequestproperties["recurStartTime"]]) || !isset($props[$meetingrequestproperties["timezonetag"]])) { ZLog::Write(LOGLEVEL_WARN, "Missing property to set correct basedate for exception"); } else { $basedate = Utils::ExtractBaseDate($props[$meetingrequestproperties["goidtag"]], $props[$meetingrequestproperties["recurStartTime"]]); $message->meetingrequest->recurrenceid = $this->getGMTTimeByTZ($basedate, $tz); } } } // Organizer is the sender if (strpos($message->messageclass, "IPM.Schedule.Meeting.Resp") === 0) { $message->meetingrequest->organizer = $message->to; } else { $message->meetingrequest->organizer = $message->from; } // Process recurrence if (isset($props[$meetingrequestproperties["isrecurringtag"]]) && $props[$meetingrequestproperties["isrecurringtag"]]) { $myrec = new SyncMeetingRequestRecurrence(); // get recurrence -> put $message->meetingrequest as message so the 'alldayevent' is set correctly $this->getRecurrence($mapimessage, $props, $message->meetingrequest, $myrec, $tz); $message->meetingrequest->recurrences = array($myrec); } // Force the 'alldayevent' in the object at all times. (non-existent == 0) if (!isset($message->meetingrequest->alldayevent) || $message->meetingrequest->alldayevent == "") { $message->meetingrequest->alldayevent = 0; } // Instancetype // 0 = single appointment // 1 = master recurring appointment // 2 = single instance of recurring appointment // 3 = exception of recurring appointment $message->meetingrequest->instancetype = 0; if (isset($props[$meetingrequestproperties["isrecurringtag"]]) && $props[$meetingrequestproperties["isrecurringtag"]] == 1) { $message->meetingrequest->instancetype = 1; } else { if ((!isset($props[$meetingrequestproperties["isrecurringtag"]]) || $props[$meetingrequestproperties["isrecurringtag"]] == 0) && isset($message->meetingrequest->recurrenceid)) { if (isset($props[$meetingrequestproperties["appSeqNr"]]) && $props[$meetingrequestproperties["appSeqNr"]] == 0) { $message->meetingrequest->instancetype = 2; } else { $message->meetingrequest->instancetype = 3; } } } // Disable reminder if it is off if (!isset($props[$meetingrequestproperties["reminderset"]]) || $props[$meetingrequestproperties["reminderset"]] == false) { $message->meetingrequest->reminder = ""; } else { ///set the default reminder time to seconds if ($props[$meetingrequestproperties["remindertime"]] == 0x5ae980e1) { $message->meetingrequest->reminder = 900; } else { $message->meetingrequest->reminder = $props[$meetingrequestproperties["remindertime"]] * 60; } } // Set sensitivity to 0 if missing if (!isset($message->meetingrequest->sensitivity)) { $message->meetingrequest->sensitivity = 0; } // If the user is working from a location other than the office the busystatus should be interpreted as free. if (isset($message->meetingrequest->busystatus) && $message->meetingrequest->busystatus == fbWorkingElsewhere) { $message->meetingrequest->busystatus = fbFree; } // If the busystatus has the value of -1, we should be interpreted as tentative (1) / ZP-581 if (isset($message->meetingrequest->busystatus) && $message->meetingrequest->busystatus == -1) { $message->meetingrequest->busystatus = fbTentative; } // if a meeting request response hasn't been processed yet, // do it so that the attendee status is updated on the mobile if (!isset($messageprops[$emailproperties["processed"]])) { // check if we are not sending the MR so we can process it - ZP-581 $cuser = ZPush::GetBackend()->GetUserDetails(ZPush::GetBackend()->GetCurrentUsername()); if (isset($cuser["emailaddress"]) && $cuser["emailaddress"] != $fromaddr) { $req = new Meetingrequest($this->store, $mapimessage, $this->session); if ($req->isMeetingRequestResponse()) { $req->processMeetingRequestResponse(); } if ($req->isMeetingCancellation()) { $req->processMeetingCancellation(); } } } $message->contentclass = DEFAULT_CALENDAR_CONTENTCLASS; } // Add attachments $attachtable = mapi_message_getattachmenttable($mapimessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); $entryid = bin2hex($messageprops[$emailproperties["entryid"]]); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { if (Request::GetProtocolVersion() >= 12.0) { $attach = new SyncBaseAttachment(); } else { $attach = new SyncAttachment(); } $mapiattach = mapi_message_openattach($mapimessage, $row[PR_ATTACH_NUM]); $attachprops = mapi_getprops($mapiattach, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_CONTENT_ID_W, PR_ATTACH_MIME_TAG, PR_ATTACH_MIME_TAG_W, PR_ATTACH_METHOD, PR_DISPLAY_NAME, PR_DISPLAY_NAME_W, PR_ATTACH_SIZE)); if (isset($attachprops[PR_ATTACH_MIME_TAG]) && strpos(strtolower($attachprops[PR_ATTACH_MIME_TAG]), 'signed') !== false || isset($attachprops[PR_ATTACH_MIME_TAG_W]) && strpos(strtolower($attachprops[PR_ATTACH_MIME_TAG_W]), 'signed') !== false) { continue; } // the displayname is handled equaly for all AS versions $attach->displayname = w2u(isset($attachprops[PR_ATTACH_LONG_FILENAME]) ? $attachprops[PR_ATTACH_LONG_FILENAME] : (isset($attachprops[PR_ATTACH_FILENAME]) ? $attachprops[PR_ATTACH_FILENAME] : (isset($attachprops[PR_DISPLAY_NAME]) ? $attachprops[PR_DISPLAY_NAME] : "attachment.bin"))); // fix attachment name in case of inline images if ($attach->displayname == "inline.txt" && (isset($attachprops[PR_ATTACH_MIME_TAG]) || $attachprops[PR_ATTACH_MIME_TAG_W])) { $mimetype = isset($attachprops[PR_ATTACH_MIME_TAG]) ? $attachprops[PR_ATTACH_MIME_TAG] : $attachprops[PR_ATTACH_MIME_TAG_W]; $mime = explode("/", $mimetype); if (count($mime) == 2 && $mime[0] == "image") { $attach->displayname = "inline." . $mime[1]; } } // set AS version specific parameters if (Request::GetProtocolVersion() >= 12.0) { $attach->filereference = $entryid . ":" . $row[PR_ATTACH_NUM]; $attach->method = isset($attachprops[PR_ATTACH_METHOD]) ? $attachprops[PR_ATTACH_METHOD] : ATTACH_BY_VALUE; // if displayname does not have the eml extension for embedde messages, android and WP devices won't open it if ($attach->method == ATTACH_EMBEDDED_MSG) { if (strtolower(substr($attach->displayname, -4)) != '.eml') { $attach->displayname .= '.eml'; } } $attach->estimatedDataSize = $attachprops[PR_ATTACH_SIZE]; if (isset($attachprops[PR_ATTACH_CONTENT_ID]) && $attachprops[PR_ATTACH_CONTENT_ID]) { $attach->contentid = $attachprops[PR_ATTACH_CONTENT_ID]; } if (!isset($attach->contentid) && isset($attachprops[PR_ATTACH_CONTENT_ID_W]) && $attachprops[PR_ATTACH_CONTENT_ID_W]) { $attach->contentid = $attachprops[PR_ATTACH_CONTENT_ID_W]; } if (isset($attachprops[PR_ATTACHMENT_HIDDEN]) && $attachprops[PR_ATTACHMENT_HIDDEN]) { $attach->isinline = 1; } if (!isset($message->asattachments)) { $message->asattachments = array(); } array_push($message->asattachments, $attach); } else { $attach->attsize = $attachprops[PR_ATTACH_SIZE]; $attach->attname = $entryid . ":" . $row[PR_ATTACH_NUM]; if (!isset($message->attachments)) { $message->attachments = array(); } array_push($message->attachments, $attach); } } } // Get To/Cc as SMTP addresses (this is different from displayto and displaycc because we are putting // in the SMTP addresses as well, while displayto and displaycc could just contain the display names $message->to = array(); $message->cc = array(); $reciptable = mapi_message_getrecipienttable($mapimessage); $rows = mapi_table_queryallrows($reciptable, array(PR_RECIPIENT_TYPE, PR_DISPLAY_NAME, PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_ENTRYID)); foreach ($rows as $row) { $address = ""; $fulladdr = ""; $addrtype = isset($row[PR_ADDRTYPE]) ? $row[PR_ADDRTYPE] : ""; if (isset($row[PR_SMTP_ADDRESS])) { $address = $row[PR_SMTP_ADDRESS]; } elseif ($addrtype == "SMTP" && isset($row[PR_EMAIL_ADDRESS])) { $address = $row[PR_EMAIL_ADDRESS]; } elseif ($addrtype == "ZARAFA" && isset($row[PR_ENTRYID])) { $address = $this->getSMTPAddressFromEntryID($row[PR_ENTRYID]); } $name = isset($row[PR_DISPLAY_NAME]) ? $row[PR_DISPLAY_NAME] : ""; if ($name == "" || $name == $address) { $fulladdr = w2u($address); } else { if (substr($name, 0, 1) != '"' && substr($name, -1) != '"') { $fulladdr = "\"" . w2u($name) . "\" <" . w2u($address) . ">"; } else { $fulladdr = w2u($name) . "<" . w2u($address) . ">"; } } if ($row[PR_RECIPIENT_TYPE] == MAPI_TO) { array_push($message->to, $fulladdr); } else { if ($row[PR_RECIPIENT_TYPE] == MAPI_CC) { array_push($message->cc, $fulladdr); } } } if (is_array($message->to) && !empty($message->to)) { $message->to = implode(", ", $message->to); } if (is_array($message->cc) && !empty($message->cc)) { $message->cc = implode(", ", $message->cc); } // without importance some mobiles assume "0" (low) - Mantis #439 if (!isset($message->importance)) { $message->importance = IMPORTANCE_NORMAL; } //TODO contentclass and nativebodytype and internetcpid if (!isset($message->internetcpid)) { $message->internetcpid = defined('STORE_INTERNET_CPID') ? constant('STORE_INTERNET_CPID') : INTERNET_CPID_WINDOWS1252; } $this->setFlag($mapimessage, $message); if (!isset($message->contentclass)) { $message->contentclass = DEFAULT_EMAIL_CONTENTCLASS; } if (!isset($message->nativebodytype)) { $message->nativebodytype = $this->getNativeBodyType($messageprops); } // reply, reply to all, forward flags if (isset($message->lastverbexecuted) && $message->lastverbexecuted) { $message->lastverbexecuted = Utils::GetLastVerbExecuted($message->lastverbexecuted); } return $message; }
/** * Converts a text/calendar part into SyncMeetingRequest * * @access private * @param $part MIME part * @param $output SyncMail object */ private function parseMeetingCalendar($part, &$output) { $ical = new iCalComponent(); $ical->ParseFrom($part->body); if (isset($part->ctype_parameters["method"])) { switch (strtolower($part->ctype_parameters["method"])) { case "cancel": $output->messageclass = "IPM.Schedule.Meeting.Canceled"; break; case "counter": $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent"; break; case "reply": $props = $ical->GetPropertiesByPath('!VTIMEZONE/ATTENDEE'); if (count($props) == 1) { $props_params = $props[0]->Parameters(); if (isset($props_params["PARTSTAT"])) { switch (strtolower($props_params["PARTSTAT"])) { case "accepted": $output->messageclass = "IPM.Schedule.Meeting.Resp.Pos"; break; case "needs-action": case "tentative": $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent"; break; case "declined": $output->messageclass = "IPM.Schedule.Meeting.Resp.Neg"; break; default: ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - Unknown reply status %s", strtolower($props_params["PARTSTAT"]))); $output->messageclass = "IPM.Appointment"; break; } } else { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - No reply status found")); $output->messageclass = "IPM.Appointment"; } } else { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - There are not attendees")); $output->messageclass = "IPM.Appointment"; } break; case "request": $output->messageclass = "IPM.Schedule.Meeting.Request"; break; default: ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - Unknown method %s", strtolower($part->headers["method"]))); $output->messageclass = "IPM.Appointment"; break; } } else { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - No method header")); $output->messageclass = "IPM.Appointment"; } $props = $ical->GetPropertiesByPath('VEVENT/DTSTAMP'); if (count($props) == 1) { $output->meetingrequest->dtstamp = Utils::MakeUTCDate($props[0]->Value()); } $props = $ical->GetPropertiesByPath('VEVENT/UID'); if (count($props) == 1) { $output->meetingrequest->globalobjid = $props[0]->Value(); } $props = $ical->GetPropertiesByPath('VEVENT/DTSTART'); if (count($props) == 1) { $output->meetingrequest->starttime = Utils::MakeUTCDate($props[0]->Value()); if (strlen($props[0]->Value()) == 8) { $output->meetingrequest->alldayevent = 1; } } $props = $ical->GetPropertiesByPath('VEVENT/DTEND'); if (count($props) == 1) { $output->meetingrequest->endtime = Utils::MakeUTCDate($props[0]->Value()); if (strlen($props[0]->Value()) == 8) { $output->meetingrequest->alldayevent = 1; } } $props = $ical->GetPropertiesByPath('VEVENT/ORGANIZER'); if (count($props) == 1) { $output->meetingrequest->organizer = str_ireplace("MAILTO:", "", $props[0]->Value()); } $props = $ical->GetPropertiesByPath('VEVENT/LOCATION'); if (count($props) == 1) { $output->meetingrequest->location = $props[0]->Value(); } $props = $ical->GetPropertiesByPath('VEVENT/CLASS'); if (count($props) == 1) { switch ($props[0]->Value()) { case "PUBLIC": $output->meetingrequest->sensitivity = "0"; break; case "PRIVATE": $output->meetingrequest->sensitivity = "2"; break; case "CONFIDENTIAL": $output->meetingrequest->sensitivity = "3"; break; default: ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - No sensitivity class. Using 2")); $output->meetingrequest->sensitivity = "2"; break; } } // Get $tz from first timezone $props = $ical->GetPropertiesByPath("VTIMEZONE/TZID"); if (count($props) > 0) { // TimeZones shouldn't have dots $tzname = str_replace(".", "", $props[0]->Value()); $tz = TimezoneUtil::GetFullTZFromTZName($tzname); } else { $tz = TimezoneUtil::GetFullTZ(); } $output->meetingrequest->timezone = base64_encode(TimezoneUtil::getSyncBlobFromTZ($tz)); // Fixed values $output->meetingrequest->instancetype = 0; $output->meetingrequest->responserequested = 1; $output->meetingrequest->busystatus = 2; // TODO: reminder $output->meetingrequest->reminder = ""; }
<?php require_once 'vendor/autoload.php'; define('LOGLEVEL', LOGLEVEL_DEBUG); define('LOGUSERLEVEL', LOGLEVEL_DEVICEID); date_default_timezone_set('Europe/Madrid'); $body = file_get_contents('testing/samples/meeting_request.txt'); $ical = new iCalComponent(); $ical->ParseFrom($body); $props = $ical->GetPropertiesByPath("VTIMEZONE/TZID"); if (count($props) > 0) { $tzid = $props[0]->Value(); printf("TZID %s\n", $props[0]->Value()); } print_r(TimezoneUtil::GetFullTZFromTZName($tzid)); $body = file_get_contents('testing/samples/meeting_request_rim.txt'); $ical = new iCalComponent(); $ical->ParseFrom($body); $props = $ical->GetPropertiesByPath("VTIMEZONE/TZID"); if (count($props) > 0) { $tzid = $props[0]->Value(); printf("TZID %s\n", $props[0]->Value()); } print_r(TimezoneUtil::GetFullTZFromTZName($tzid));
function setUp() { // clearning the tz cache TimezoneUtil::$map = null; }
/** * Parse 1 VEvent * @param ical_vtodo $vtodo * @param SyncAppointment(Exception) $message * @param int $truncsize */ private function _ParseVTodoToSyncObject($vtodo, $message, $truncsize) { //Default $message->reminderset = "0"; $message->importance = "1"; $message->complete = "0"; $properties = $vtodo->GetProperties(); foreach ($properties as $property) { switch ($property->Name()) { case "SUMMARY": $message->subject = $property->Value(); break; case "STATUS": switch ($property->Value()) { case "NEEDS-ACTION": case "IN-PROCESS": $message->complete = "0"; break; case "COMPLETED": case "CANCELLED": $message->complete = "1"; break; } break; case "COMPLETED": $message->datecompleted = TimezoneUtil::MakeUTCDate($property->Value()); break; case "DUE": $message->utcduedate = TimezoneUtil::MakeUTCDate($property->Value()); break; case "PRIORITY": $priority = $property->Value(); if ($priority <= 3) { $message->importance = "0"; } if ($priority <= 6) { $message->importance = "1"; } if ($priority > 6) { $message->importance = "2"; } break; case "RRULE": $message->recurrence = $this->_ParseRecurrence($property->Value(), "vtodo"); break; case "CLASS": switch ($property->Value()) { case "PUBLIC": $message->sensitivity = "0"; break; case "PRIVATE": $message->sensitivity = "2"; break; case "CONFIDENTIAL": $message->sensitivity = "3"; break; } break; case "DTSTART": $message->utcstartdate = TimezoneUtil::MakeUTCDate($property->Value()); break; case "SUMMARY": $message->subject = $property->Value(); break; case "CATEGORIES": $categories = explode(",", $property->Value()); $message->categories = $categories; break; } } if (isset($message->recurrence)) { $message->recurrence->start = $message->utcstartdate; } $valarm = current($vtodo->GetComponents("VALARM")); if ($valarm) { $properties = $valarm->GetProperties(); foreach ($properties as $property) { if ($property->Name() == "TRIGGER") { $parameters = $property->Parameters(); if (array_key_exists("VALUE", $parameters) && $parameters["VALUE"] == "DATE-TIME") { $message->remindertime = TimezoneUtil::MakeUTCDate($property->Value()); $message->reminderset = "1"; } elseif (!array_key_exists("VALUE", $parameters) || $parameters["VALUE"] == "DURATION") { $val = str_replace("-", "", $property->Value()); $interval = new DateInterval($val); $start = date_create("@" . $message->utcstartdate); $message->remindertime = date_timestamp_get(date_sub($start, $interval)); $message->reminderset = "1"; } } } } return $message; }
/** * Generate a tzid from various formats * * @param str $timezone * * @access public * @return timezone id */ public static function ParseTimezone($timezone) { //(GMT+01.00) Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna if (preg_match('/GMT(\\+|\\-)0(\\d)/', $timezone, $matches)) { return "Etc/GMT" . $matches[1] . $matches[2]; } //(GMT+10.00) XXX / XXX / XXX / XXX if (preg_match('/GMT(\\+|\\-)1(\\d)/', $timezone, $matches)) { return "Etc/GMT" . $matches[1] . "1" . $matches[2]; } ///inverse.ca/20101018_1/Europe/Amsterdam or /inverse.ca/20101018_1/America/Argentina/Buenos_Aires if (preg_match('/\\/[.[:word:]]+\\/\\w+\\/(\\w+)\\/([\\w\\/]+)/', $timezone, $matches)) { return $matches[1] . "/" . $matches[2]; } return TimezoneUtil::getMSTZnameFromTZName(trim($timezone, '"')); }