From 2a3ca65b623b3ae920afbe12853c996f183b9ad9 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Fri, 3 Nov 2023 13:22:52 +0000 Subject: [PATCH] Replaced deprecated gmstrftime() with IntlDateFormatter. Move converter from Streamer to Utils for logging. Make public methods start with an uppercase letter. Print cutoffdate in human readable format (YYYY-MM-DD). References: Issue #103 --- lib/core/streamer.php | 31 ++---------------------- lib/grommunio/grommunio.php | 4 ++-- lib/grommunio/importer.php | 2 +- lib/grommunio/mapiprovider.php | 17 ++++++------- lib/syncobjects/syncappointment.php | 4 ++-- lib/utils/utils.php | 37 ++++++++++++++++++++++++++++- 6 files changed, 52 insertions(+), 43 deletions(-) diff --git a/lib/core/streamer.php b/lib/core/streamer.php index cce1d25..d5e96d6 100644 --- a/lib/core/streamer.php +++ b/lib/core/streamer.php @@ -165,7 +165,7 @@ public function Decode(&$decoder) { if (isset($map[self::STREAMER_TYPE])) { // Complex type, decode recursively if ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE || $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE_DASHES) { - $decoded = Utils::parseDate($decoder->getElementContent()); + $decoded = Utils::ParseDate($decoder->getElementContent()); if (!$decoder->getElementEndTag()) { return false; } @@ -333,7 +333,7 @@ public function Encode(&$encoder) { if (isset($map[self::STREAMER_TYPE]) && ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE || $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE_DASHES)) { if ($this->{$map[self::STREAMER_VAR]} != 0) { // don't output 1-1-1970 - $encoder->content($this->formatDate($this->{$map[self::STREAMER_VAR]}, $map[self::STREAMER_TYPE])); + $encoder->content(Utils::FormatDate($this->{$map[self::STREAMER_VAR]}, $map[self::STREAMER_TYPE])); } } elseif (isset($map[self::STREAMER_TYPE]) && $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_HEX) { @@ -463,31 +463,4 @@ public function jsonDeserialize($stdObj) { } } } - - /*---------------------------------------------------------------------------------------------------------- - * Private methods for conversion - */ - - /** - * Formats a timestamp - * Oh yeah, this is beautiful. Exchange outputs date fields differently in calendar items - * and emails. We could just always send one or the other, but unfortunately nokia's 'Mail for - * exchange' depends on this quirk. So we have to send a different date type depending on where - * it's used. Sigh. - * - * @param int $ts - * @param int $type - * - * @return string - */ - private function formatDate($ts, $type) { - if ($type == self::STREAMER_TYPE_DATE) { - return gmstrftime("%Y%m%dT%H%M%SZ", $ts); - } - if ($type == self::STREAMER_TYPE_DATE_DASHES) { - return gmstrftime("%Y-%m-%dT%H:%M:%S.000Z", $ts); - } - // fallback to dashes (should never be reached) - return gmstrftime("%Y-%m-%dT%H:%M:%S.000Z", $ts); - } } diff --git a/lib/grommunio/grommunio.php b/lib/grommunio/grommunio.php index 1ca668d..38600c7 100644 --- a/lib/grommunio/grommunio.php +++ b/lib/grommunio/grommunio.php @@ -872,13 +872,13 @@ public function MeetingResponse($folderid, $request) { // AS-16.1: did the attendee propose a new time ? if (!empty($request['proposedstarttime'])) { - $request['proposedstarttime'] = Utils::parseDate($request['proposedstarttime']); + $request['proposedstarttime'] = Utils::ParseDate($request['proposedstarttime']); } else { $request['proposedstarttime'] = false; } if (!empty($request['proposedendtime'])) { - $request['proposedendtime'] = Utils::parseDate($request['proposedendtime']); + $request['proposedendtime'] = Utils::ParseDate($request['proposedendtime']); } else { $request['proposedendtime'] = false; diff --git a/lib/grommunio/importer.php b/lib/grommunio/importer.php index e2a6b2a..061352d 100644 --- a/lib/grommunio/importer.php +++ b/lib/grommunio/importer.php @@ -248,7 +248,7 @@ private function isModificationAllowed($messageid) { // check the sync interval if ($this->cutoffdate !== false) { - SLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesICS->isModificationAllowed('%s'): cut off date is: %s", $messageid, $this->cutoffdate)); + SLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesICS->isModificationAllowed('%s'): cut off date is: %s (%s)", $messageid, Utils::FormatDate($this->cutoffdate), $this->cutoffdate)); if (($this->contentClass == "Email" && !MAPIUtils::IsInEmailSyncInterval($this->store, $mapimessage, $this->cutoffdate)) || ($this->contentClass == "Calendar" && !MAPIUtils::IsInCalendarSyncInterval($this->store, $mapimessage, $this->cutoffdate))) { SLog::Write(LOGLEVEL_WARN, sprintf("ImportChangesICS->isModificationAllowed('%s'): Message in %s is outside the sync interval. Data not saved.", $messageid, $this->contentClass)); diff --git a/lib/grommunio/mapiprovider.php b/lib/grommunio/mapiprovider.php index 3360c1b..44b65a2 100644 --- a/lib/grommunio/mapiprovider.php +++ b/lib/grommunio/mapiprovider.php @@ -459,6 +459,7 @@ private function getRecurrence($mapimessage, $recurprops, &$syncMessage, &$syncR break; } } + // Termination switch ($recurrence->recur["term"]) { case 0x21: @@ -1438,8 +1439,8 @@ private function setAppointment($mapimessage, $appointment) { // AS 16: incoming instanceid means we need to create/update an appointment exception if (Request::GetProtocolVersion() >= 16.0 && isset($appointment->instanceid) && $appointment->instanceid) { - // this property wasn't decoded so use Streamer->parseDate to convert it into a timestamp and get basedate from it - $instanceid = Utils::parseDate($appointment->instanceid); + // this property wasn't decoded so use Utils->ParseDate to convert it into a timestamp and get basedate from it + $instanceid = Utils::ParseDate($appointment->instanceid); $basedate = $this->getDayStartOfTimestamp($instanceid); // get compatible TZ data @@ -1526,11 +1527,11 @@ private function setAppointment($mapimessage, $appointment) { if (isset($existingstartendprops[$amapping["starttime"]]) && !isset($appointment->starttime)) { $appointment->starttime = $existingstartendprops[$amapping["starttime"]]; - SLog::Write(LOGLEVEL_WBXML, sprintf("MAPIProvider->setAppointment(): Parameter 'starttime' was not set, using value from MAPI %d (%s).", $appointment->starttime, gmstrftime("%Y%m%dT%H%M%SZ", $appointment->starttime))); + SLog::Write(LOGLEVEL_WBXML, sprintf("MAPIProvider->setAppointment(): Parameter 'starttime' was not set, using value from MAPI %d (%s).", $appointment->starttime, Utils::FormatDate($appointment->starttime))); } if (isset($existingstartendprops[$amapping["endtime"]]) && !isset($appointment->endtime)) { $appointment->endtime = $existingstartendprops[$amapping["endtime"]]; - SLog::Write(LOGLEVEL_WBXML, sprintf("MAPIProvider->setAppointment(): Parameter 'endtime' was not set, using value from MAPI %d (%s).", $appointment->endtime, gmstrftime("%Y%m%dT%H%M%SZ", $appointment->endtime))); + SLog::Write(LOGLEVEL_WBXML, sprintf("MAPIProvider->setAppointment(): Parameter 'endtime' was not set, using value from MAPI %d (%s).", $appointment->endtime, Utils::FormatDate($appointment->endtime))); } } if (!isset($appointment->starttime) || !isset($appointment->endtime)) { @@ -2187,7 +2188,7 @@ private function GetTZOffset($ts) { $Offset = date("O", $ts); $Parity = $Offset < 0 ? -1 : 1; - $Offset = $Parity * $Offset; + $Offset *= $Parity; $Offset = ($Offset - ($Offset % 100)) / 100 * 60 + $Offset % 100; return $Parity * $Offset; @@ -2546,7 +2547,7 @@ private function getTimestampOfWeek($year, $month, $week, $wday, $hour, $minute, while (1) { $monthnow = gmdate("n", $date); // gmdate returns 1-12 if ($monthnow > $month) { - $date = $date - (24 * 7 * 60 * 60); + $date -= (24 * 7 * 60 * 60); } else { break; @@ -2853,9 +2854,9 @@ private function setRecurrence($message, &$recur) { * * @see http://developer.berlios.de/mantis/view.php?id=486 * - * @param string $email + * @param string $email * - * @return string or false on error + * @return string or false on error */ private function extractEmailAddress($email) { if (!isset($this->zRFC822)) { diff --git a/lib/syncobjects/syncappointment.php b/lib/syncobjects/syncappointment.php index 8d4c28e..2f59c9d 100644 --- a/lib/syncobjects/syncappointment.php +++ b/lib/syncobjects/syncappointment.php @@ -337,12 +337,12 @@ public function Check($logAsDebug = false) { // Case 1, 3a (endtime won't be changed as it's set) if (!isset($this->starttime)) { $this->starttime = $calcstart; - SLog::Write(LOGLEVEL_WBXML, sprintf("SyncAppointment->Check(): Parameter 'starttime' was not set, setting it to %d (%s).", $this->starttime, gmstrftime("%Y%m%dT%H%M%SZ", $this->starttime))); + SLog::Write(LOGLEVEL_WBXML, sprintf("SyncAppointment->Check(): Parameter 'starttime' was not set, setting it to %d (%s).", $this->starttime, Utils::FormatDate($this->starttime))); } // Case 1, 4 if (!isset($this->endtime)) { $this->endtime = $calcstart + 1800; // 30 min after calcstart - SLog::Write(LOGLEVEL_WBXML, sprintf("SyncAppointment->Check(): Parameter 'endtime' was not set, setting it to %d (%s).", $this->endtime, gmstrftime("%Y%m%dT%H%M%SZ", $this->endtime))); + SLog::Write(LOGLEVEL_WBXML, sprintf("SyncAppointment->Check(): Parameter 'endtime' was not set, setting it to %d (%s).", $this->endtime, Utils::FormatDate($this->endtime))); } } diff --git a/lib/utils/utils.php b/lib/utils/utils.php index 67320d8..651dd16 100644 --- a/lib/utils/utils.php +++ b/lib/utils/utils.php @@ -869,7 +869,7 @@ public static function SplitMessageId($id) { * * @return long */ - public static function parseDate($ts) { + public static function ParseDate($ts) { if (preg_match("/(\\d{4})[^0-9]*(\\d{2})[^0-9]*(\\d{2})(T(\\d{2})[^0-9]*(\\d{2})[^0-9]*(\\d{2})(.\\d+)?Z){0,1}$/", $ts, $matches)) { if ($matches[1] >= 2038) { $matches[1] = 2038; @@ -894,6 +894,41 @@ public static function parseDate($ts) { return 0; } + /** + * Transforms an unix timestamp into an AS timestamp or a human readable format. + * + * Oh yeah, this is beautiful. Exchange outputs date fields differently in calendar items + * and emails. We could just always send one or the other, but unfortunately nokia's 'Mail for + * exchange' depends on this quirk. So we have to send a different date type depending on where + * it's used. Sigh. + * + * @param int $ts + * @param int $type int (StreamerType) (optional) if not set a human readable format is returned + * + * @return string + */ + public static function FormatDate($ts, $type = "") { + // fallback to a human readable format (used for logging) + $formatString = "yyyy-MM-dd HH:mm:SS' UTC'"; + if ($type == Streamer::STREAMER_TYPE_DATE) { + $formatString = "yyyyMMdd'T'HHmmSS'Z'"; + } + elseif ($type == Streamer::STREAMER_TYPE_DATE_DASHES) { + $formatString = "yyyy-MM-dd'T'HH:mm:SS'.000Z'"; + } + + $formatter = datefmt_create( + 'en_US', + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + 'UTC', + IntlDateFormatter::GREGORIAN, + $formatString + ); + + return datefmt_format($formatter, $ts); + } + /** * Returns the appropriate SyncObjectResponse object based on message class. *