aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre')
-rw-r--r--vendor/sabre/vobject/lib/Document.php6
-rw-r--r--vendor/sabre/vobject/lib/ITip/Broker.php13
-rw-r--r--vendor/sabre/vobject/lib/Parser/MimeDir.php8
-rw-r--r--vendor/sabre/vobject/lib/Property.php24
-rw-r--r--vendor/sabre/vobject/lib/Recur/RRuleIterator.php89
-rw-r--r--vendor/sabre/vobject/lib/Version.php2
6 files changed, 122 insertions, 20 deletions
diff --git a/vendor/sabre/vobject/lib/Document.php b/vendor/sabre/vobject/lib/Document.php
index 14a77c911..6b908c70e 100644
--- a/vendor/sabre/vobject/lib/Document.php
+++ b/vendor/sabre/vobject/lib/Document.php
@@ -186,10 +186,8 @@ abstract class Document extends Component
* @param mixed $value
* @param array $parameters
* @param string $valueType Force a specific valuetype, such as URI or TEXT
- *
- * @return Property
*/
- public function createProperty($name, $value = null, array $parameters = null, $valueType = null)
+ public function createProperty($name, $value = null, array $parameters = null, $valueType = null, int $lineIndex = null, string $lineString = null): Property
{
// If there's a . in the name, it means it's prefixed by a groupname.
if (false !== ($i = strpos($name, '.'))) {
@@ -223,7 +221,7 @@ abstract class Document extends Component
$parameters = [];
}
- return new $class($this, $name, $value, $parameters, $group);
+ return new $class($this, $name, $value, $parameters, $group, $lineIndex, $lineString);
}
/**
diff --git a/vendor/sabre/vobject/lib/ITip/Broker.php b/vendor/sabre/vobject/lib/ITip/Broker.php
index 80d9a5b31..dbdd80b78 100644
--- a/vendor/sabre/vobject/lib/ITip/Broker.php
+++ b/vendor/sabre/vobject/lib/ITip/Broker.php
@@ -338,7 +338,10 @@ class Broker
// Finding all the instances the attendee replied to.
foreach ($itipMessage->message->VEVENT as $vevent) {
- $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getValue() : 'master';
+ // Use the Unix timestamp returned by getTimestamp as a unique identifier for the recurrence.
+ // The Unix timestamp will be the same for an event, even if the reply from the attendee
+ // used a different format/timezone to express the event date-time.
+ $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getDateTime()->getTimestamp() : 'master';
$attendee = $vevent->ATTENDEE;
$instances[$recurId] = $attendee['PARTSTAT']->getValue();
if (isset($vevent->{'REQUEST-STATUS'})) {
@@ -351,7 +354,8 @@ class Broker
// all the instances where we have a reply for.
$masterObject = null;
foreach ($existingObject->VEVENT as $vevent) {
- $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getValue() : 'master';
+ // Use the Unix timestamp returned by getTimestamp as a unique identifier for the recurrence.
+ $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getDateTime()->getTimestamp() : 'master';
if ('master' === $recurId) {
$masterObject = $vevent;
}
@@ -398,7 +402,10 @@ class Broker
$newObject = $recurrenceIterator->getEventObject();
$recurrenceIterator->next();
- if (isset($newObject->{'RECURRENCE-ID'}) && $newObject->{'RECURRENCE-ID'}->getValue() === $recurId) {
+ // Compare the Unix timestamp returned by getTimestamp with the previously calculated timestamp.
+ // If they are the same, then this is a matching recurrence, even though its date-time may have
+ // been expressed in a different format/timezone.
+ if (isset($newObject->{'RECURRENCE-ID'}) && $newObject->{'RECURRENCE-ID'}->getDateTime()->getTimestamp() === $recurId) {
$found = true;
}
--$iterations;
diff --git a/vendor/sabre/vobject/lib/Parser/MimeDir.php b/vendor/sabre/vobject/lib/Parser/MimeDir.php
index 513f7bd0c..d484d6a39 100644
--- a/vendor/sabre/vobject/lib/Parser/MimeDir.php
+++ b/vendor/sabre/vobject/lib/Parser/MimeDir.php
@@ -83,6 +83,12 @@ class MimeDir extends Parser
$this->setInput($input);
}
+ if (!\is_resource($this->input)) {
+ // Null was passed as input, but there was no existing input buffer
+ // There is nothing to parse.
+ throw new ParseException('No input provided to parse');
+ }
+
if (0 !== $options) {
$this->options = $options;
}
@@ -447,7 +453,7 @@ class MimeDir extends Parser
}
}
- $propObj = $this->root->createProperty($property['name'], null, $namedParameters);
+ $propObj = $this->root->createProperty($property['name'], null, $namedParameters, null, $this->startLine, $line);
foreach ($namelessParameters as $namelessParameter) {
$propObj->add(null, $namelessParameter);
diff --git a/vendor/sabre/vobject/lib/Property.php b/vendor/sabre/vobject/lib/Property.php
index f6550246a..0805c139a 100644
--- a/vendor/sabre/vobject/lib/Property.php
+++ b/vendor/sabre/vobject/lib/Property.php
@@ -57,6 +57,20 @@ abstract class Property extends Node
public $delimiter = ';';
/**
+ * The line number in the original iCalendar / vCard file
+ * that corresponds with the current node
+ * if the node was read from a file.
+ */
+ public $lineIndex;
+
+ /**
+ * The line string from the original iCalendar / vCard file
+ * that corresponds with the current node
+ * if the node was read from a file.
+ */
+ public $lineString;
+
+ /**
* Creates the generic property.
*
* Parameters must be specified in key=>value syntax.
@@ -67,7 +81,7 @@ abstract class Property extends Node
* @param array $parameters List of parameters
* @param string $group The vcard property group
*/
- public function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null)
+ public function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null, int $lineIndex = null, string $lineString = null)
{
$this->name = $name;
$this->group = $group;
@@ -81,6 +95,14 @@ abstract class Property extends Node
if (!is_null($value)) {
$this->setValue($value);
}
+
+ if (!is_null($lineIndex)) {
+ $this->lineIndex = $lineIndex;
+ }
+
+ if (!is_null($lineString)) {
+ $this->lineString = $lineString;
+ }
}
/**
diff --git a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php
index 4f0e9070d..ca53b63ee 100644
--- a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php
+++ b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php
@@ -173,6 +173,14 @@ class RRuleIterator implements Iterator
protected $currentDate;
/**
+ * The number of hours that the next occurrence of an event
+ * jumped forward, usually because summer time started and
+ * the requested time-of-day like 0230 did not exist on that
+ * day. And so the event was scheduled 1 hour later at 0330.
+ */
+ protected $hourJump = 0;
+
+ /**
* Frequency is one of: secondly, minutely, hourly, daily, weekly, monthly,
* yearly.
*
@@ -320,11 +328,64 @@ class RRuleIterator implements Iterator
/* Functions that advance the iterator {{{ */
/**
+ * Gets the original start time of the RRULE.
+ *
+ * The value is formatted as a string with 24-hour:minute:second
+ */
+ protected function startTime(): string
+ {
+ return $this->startDate->format('H:i:s');
+ }
+
+ /**
+ * Advances currentDate by the interval.
+ * The time is set from the original startDate.
+ * If the recurrence is on a day when summer time started, then the
+ * time on that day may have jumped forward, for example, from 0230 to 0330.
+ * Using the original time means that the next recurrence will be calculated
+ * based on the original start time and the day/week/month/year interval.
+ * So the start time of the next occurrence can correctly revert to 0230.
+ */
+ protected function advanceTheDate(string $interval): void
+ {
+ $this->currentDate = $this->currentDate->modify($interval.' '.$this->startTime());
+ }
+
+ /**
+ * Does the processing for adjusting the time of multi-hourly events when summer time starts.
+ */
+ protected function adjustForTimeJumpsOfHourlyEvent(DateTimeInterface $previousEventDateTime): void
+ {
+ if (0 === $this->hourJump) {
+ // Remember if the clock time jumped forward on the next occurrence.
+ // That happens if the next event time is on a day when summer time starts
+ // and the event time is in the non-existent hour of the day.
+ // For example, an event that normally starts at 02:30 will
+ // have to start at 03:30 on that day.
+ // If the interval is just 1 hour, then there is no "jumping back" to do.
+ // The events that day will happen, for example, at 0030 0130 0330 0430 0530...
+ if ($this->interval > 1) {
+ $expectedHourOfNextDate = ((int) $previousEventDateTime->format('G') + $this->interval) % 24;
+ $actualHourOfNextDate = (int) $this->currentDate->format('G');
+ $this->hourJump = $actualHourOfNextDate - $expectedHourOfNextDate;
+ }
+ } else {
+ // The hour "jumped" for the previous occurrence, to avoid the non-existent time.
+ // currentDate got set ahead by (usually) 1 hour on that day.
+ // Adjust it back for this next occurrence.
+ $this->currentDate = $this->currentDate->sub(new \DateInterval('PT'.$this->hourJump.'H'));
+ $this->hourJump = 0;
+ }
+ }
+
+ /**
* Does the processing for advancing the iterator for hourly frequency.
*/
protected function nextHourly()
{
+ $previousEventDateTime = clone $this->currentDate;
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' hours');
+ $this->adjustForTimeJumpsOfHourlyEvent($previousEventDateTime);
}
/**
@@ -333,7 +394,7 @@ class RRuleIterator implements Iterator
protected function nextDaily()
{
if (!$this->byHour && !$this->byDay) {
- $this->currentDate = $this->currentDate->modify('+'.$this->interval.' days');
+ $this->advanceTheDate('+'.$this->interval.' days');
return;
}
@@ -392,7 +453,7 @@ class RRuleIterator implements Iterator
protected function nextWeekly()
{
if (!$this->byHour && !$this->byDay) {
- $this->currentDate = $this->currentDate->modify('+'.$this->interval.' weeks');
+ $this->advanceTheDate('+'.$this->interval.' weeks');
return;
}
@@ -414,7 +475,7 @@ class RRuleIterator implements Iterator
if ($this->byHour) {
$this->currentDate = $this->currentDate->modify('+1 hours');
} else {
- $this->currentDate = $this->currentDate->modify('+1 days');
+ $this->advanceTheDate('+1 days');
}
// Current day of the week
@@ -449,13 +510,13 @@ class RRuleIterator implements Iterator
// occur to the next month. We Must skip these invalid
// entries.
if ($currentDayOfMonth < 29) {
- $this->currentDate = $this->currentDate->modify('+'.$this->interval.' months');
+ $this->advanceTheDate('+'.$this->interval.' months');
} else {
$increase = 0;
do {
++$increase;
$tempDate = clone $this->currentDate;
- $tempDate = $tempDate->modify('+ '.($this->interval * $increase).' months');
+ $tempDate = $tempDate->modify('+ '.($this->interval * $increase).' months '.$this->startTime());
} while ($tempDate->format('j') != $currentDayOfMonth);
$this->currentDate = $tempDate;
}
@@ -506,11 +567,15 @@ class RRuleIterator implements Iterator
}
}
+ // Set the currentDate to the year and month that we are in, and the day of the month that we have selected.
+ // That day could be a day when summer time starts, and if the time of the event is, for example, 0230,
+ // then 0230 will not be a valid time on that day. So always apply the start time from the original startDate.
+ // The "modify" method will set the time forward to 0330, for example, if needed.
$this->currentDate = $this->currentDate->setDate(
(int) $this->currentDate->format('Y'),
(int) $this->currentDate->format('n'),
(int) $occurrence
- );
+ )->modify($this->startTime());
}
/**
@@ -627,7 +692,7 @@ class RRuleIterator implements Iterator
}
// The easiest form
- $this->currentDate = $this->currentDate->modify('+'.$this->interval.' years');
+ $this->advanceTheDate('+'.$this->interval.' years');
return;
}
@@ -651,7 +716,11 @@ class RRuleIterator implements Iterator
// If we advanced to the next month or year, the first
// occurrence is always correct.
if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) {
- break 2;
+ // only consider byMonth matches,
+ // otherwise, we don't follow RRule correctly
+ if (in_array($currentMonth, $this->byMonth)) {
+ break 2;
+ }
}
}
@@ -687,7 +756,7 @@ class RRuleIterator implements Iterator
(int) $currentYear,
(int) $currentMonth,
(int) $occurrence
- );
+ )->modify($this->startTime());
return;
} else {
@@ -704,7 +773,7 @@ class RRuleIterator implements Iterator
(int) $currentYear,
(int) $currentMonth,
(int) $currentDayOfMonth
- );
+ )->modify($this->startTime());
return;
}
diff --git a/vendor/sabre/vobject/lib/Version.php b/vendor/sabre/vobject/lib/Version.php
index c7ca69e14..309b995cf 100644
--- a/vendor/sabre/vobject/lib/Version.php
+++ b/vendor/sabre/vobject/lib/Version.php
@@ -14,5 +14,5 @@ class Version
/**
* Full version number.
*/
- public const VERSION = '4.5.4';
+ public const VERSION = '4.5.5';
}