Test Failed
Branch master (bfd46a)
by Mike
10:35 queued 01:43
created
mapi/class.mapiexception.php 1 patch
Switch Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -25,37 +25,37 @@
 block discarded – undo
25 25
 			}
26 26
 
27 27
 			switch ($this->getCode()) {
28
-			case MAPI_E_NO_ACCESS:
29
-				return dgettext("kopano", "You have insufficient privileges to open this object.");
28
+				case MAPI_E_NO_ACCESS:
29
+					return dgettext("kopano", "You have insufficient privileges to open this object.");
30 30
 
31
-			case MAPI_E_LOGON_FAILED:
32
-			case MAPI_E_UNCONFIGURED:
33
-				return dgettext("kopano", "Logon Failed. Please check your username/password.");
31
+				case MAPI_E_LOGON_FAILED:
32
+				case MAPI_E_UNCONFIGURED:
33
+					return dgettext("kopano", "Logon Failed. Please check your username/password.");
34 34
 
35
-			case MAPI_E_NETWORK_ERROR:
36
-				return dgettext("kopano", "Can not connect to Kopano server.");
35
+				case MAPI_E_NETWORK_ERROR:
36
+					return dgettext("kopano", "Can not connect to Kopano server.");
37 37
 
38
-			case MAPI_E_UNKNOWN_ENTRYID:
39
-				return dgettext("kopano", "Can not open object with provided id.");
38
+				case MAPI_E_UNKNOWN_ENTRYID:
39
+					return dgettext("kopano", "Can not open object with provided id.");
40 40
 
41
-			case MAPI_E_NO_RECIPIENTS:
42
-				return dgettext("kopano", "There are no recipients in the message.");
41
+				case MAPI_E_NO_RECIPIENTS:
42
+					return dgettext("kopano", "There are no recipients in the message.");
43 43
 
44
-			case MAPI_E_NOT_FOUND:
45
-				return dgettext("kopano", "Can not find object.");
44
+				case MAPI_E_NOT_FOUND:
45
+					return dgettext("kopano", "Can not find object.");
46 46
 
47
-			case MAPI_E_INTERFACE_NOT_SUPPORTED:
48
-			case MAPI_E_INVALID_PARAMETER:
49
-			case MAPI_E_INVALID_ENTRYID:
50
-			case MAPI_E_INVALID_OBJECT:
51
-			case MAPI_E_TOO_COMPLEX:
52
-			case MAPI_E_CORRUPT_DATA:
53
-			case MAPI_E_END_OF_SESSION:
54
-			case MAPI_E_AMBIGUOUS_RECIP:
55
-			case MAPI_E_COLLISION:
56
-			case MAPI_E_UNCONFIGURED:
57
-			default:
58
-				return sprintf(dgettext("kopano", "Unknown MAPI Error: %s"), get_mapi_error_name($this->getCode()));
47
+				case MAPI_E_INTERFACE_NOT_SUPPORTED:
48
+				case MAPI_E_INVALID_PARAMETER:
49
+				case MAPI_E_INVALID_ENTRYID:
50
+				case MAPI_E_INVALID_OBJECT:
51
+				case MAPI_E_TOO_COMPLEX:
52
+				case MAPI_E_CORRUPT_DATA:
53
+				case MAPI_E_END_OF_SESSION:
54
+				case MAPI_E_AMBIGUOUS_RECIP:
55
+				case MAPI_E_COLLISION:
56
+				case MAPI_E_UNCONFIGURED:
57
+				default:
58
+					return sprintf(dgettext("kopano", "Unknown MAPI Error: %s"), get_mapi_error_name($this->getCode()));
59 59
 			}
60 60
 		}
61 61
 	}
Please login to merge, or discard this patch.
mapi/class.baserecurrence.php 1 patch
Switch Indentation   +618 added lines, -618 removed lines patch added patch discarded remove patch
@@ -156,94 +156,94 @@  discard block
 block discarded – undo
156 156
 			$rdata = substr($rdata, 10);
157 157
 
158 158
 			switch ($data["rtype"]) {
159
-			case 0x0A:
160
-				// Daily
161
-				if (strlen($rdata) < 12) {
162
-					return $ret;
163
-				}
164
-				$data = unpack("Vunknown/Veveryn/Vregen", $rdata);
165
-				$ret["everyn"] = $data["everyn"];
166
-				$ret["regen"] = $data["regen"];
159
+				case 0x0A:
160
+					// Daily
161
+					if (strlen($rdata) < 12) {
162
+						return $ret;
163
+					}
164
+					$data = unpack("Vunknown/Veveryn/Vregen", $rdata);
165
+					$ret["everyn"] = $data["everyn"];
166
+					$ret["regen"] = $data["regen"];
167 167
 
168
-				switch ($ret["subtype"]) {
169
-				case 0:
170
-					$rdata = substr($rdata, 12);
171
-					break;
168
+					switch ($ret["subtype"]) {
169
+						case 0:
170
+							$rdata = substr($rdata, 12);
171
+							break;
172 172
 
173
-				case 1:
174
-					$rdata = substr($rdata, 16);
175
-					break;
176
-				}
173
+						case 1:
174
+							$rdata = substr($rdata, 16);
175
+							break;
176
+					}
177 177
 				break;
178 178
 
179
-			case 0x0B:
180
-				// Weekly
181
-				if (strlen($rdata) < 16) {
182
-					return $ret;
183
-				}
179
+				case 0x0B:
180
+					// Weekly
181
+					if (strlen($rdata) < 16) {
182
+						return $ret;
183
+					}
184 184
 
185
-				$data = unpack("Vconst1/Veveryn/Vregen", $rdata);
186
-				$rdata = substr($rdata, 12);
185
+					$data = unpack("Vconst1/Veveryn/Vregen", $rdata);
186
+					$rdata = substr($rdata, 12);
187 187
 
188
-				$ret["everyn"] = $data["everyn"];
189
-				$ret["regen"] = $data["regen"];
190
-				$ret["weekdays"] = 0;
188
+					$ret["everyn"] = $data["everyn"];
189
+					$ret["regen"] = $data["regen"];
190
+					$ret["weekdays"] = 0;
191 191
 
192
-				if ($data["regen"] == 0) {
193
-					$data = unpack("Vweekdays", $rdata);
194
-					$rdata = substr($rdata, 4);
195
-					$ret["weekdays"] = $data["weekdays"];
196
-				}
197
-				break;
192
+					if ($data["regen"] == 0) {
193
+						$data = unpack("Vweekdays", $rdata);
194
+						$rdata = substr($rdata, 4);
195
+						$ret["weekdays"] = $data["weekdays"];
196
+					}
197
+					break;
198 198
 
199
-			case 0x0C:
200
-				// Monthly
201
-				if (strlen($rdata) < 16) {
202
-					return $ret;
203
-				}
199
+				case 0x0C:
200
+					// Monthly
201
+					if (strlen($rdata) < 16) {
202
+						return $ret;
203
+					}
204 204
 
205
-				$data = unpack("Vconst1/Veveryn/Vregen/Vmonthday", $rdata);
206
-				$ret["everyn"] = $data["everyn"];
207
-				$ret["regen"] = $data["regen"];
208
-				if ($ret["subtype"] == 3) {
209
-					$ret["weekdays"] = $data["monthday"];
210
-				}
211
-				else {
212
-					$ret["monthday"] = $data["monthday"];
213
-				}
205
+					$data = unpack("Vconst1/Veveryn/Vregen/Vmonthday", $rdata);
206
+					$ret["everyn"] = $data["everyn"];
207
+					$ret["regen"] = $data["regen"];
208
+					if ($ret["subtype"] == 3) {
209
+						$ret["weekdays"] = $data["monthday"];
210
+					}
211
+					else {
212
+						$ret["monthday"] = $data["monthday"];
213
+					}
214 214
 
215
-				$rdata = substr($rdata, 16);
216
-				if ($ret["subtype"] == 3) {
217
-					$data = unpack("Vnday", $rdata);
218
-					$ret["nday"] = $data["nday"];
219
-					$rdata = substr($rdata, 4);
220
-				}
221
-				break;
215
+					$rdata = substr($rdata, 16);
216
+					if ($ret["subtype"] == 3) {
217
+						$data = unpack("Vnday", $rdata);
218
+						$ret["nday"] = $data["nday"];
219
+						$rdata = substr($rdata, 4);
220
+					}
221
+					break;
222 222
 
223
-			case 0x0D:
224
-				// Yearly
225
-				if (strlen($rdata) < 16) {
226
-					return $ret;
227
-				}
223
+				case 0x0D:
224
+					// Yearly
225
+					if (strlen($rdata) < 16) {
226
+						return $ret;
227
+					}
228 228
 
229
-				$data = unpack("Vmonth/Veveryn/Vregen/Vmonthday", $rdata);
230
-				$ret["month"] = $data["month"];
231
-				$ret["everyn"] = $data["everyn"];
232
-				$ret["regen"] = $data["regen"];
233
-				if ($ret["subtype"] == 3) {
234
-					$ret["weekdays"] = $data["monthday"];
235
-				}
236
-				else {
237
-					$ret["monthday"] = $data["monthday"];
238
-				}
229
+					$data = unpack("Vmonth/Veveryn/Vregen/Vmonthday", $rdata);
230
+					$ret["month"] = $data["month"];
231
+					$ret["everyn"] = $data["everyn"];
232
+					$ret["regen"] = $data["regen"];
233
+					if ($ret["subtype"] == 3) {
234
+						$ret["weekdays"] = $data["monthday"];
235
+					}
236
+					else {
237
+						$ret["monthday"] = $data["monthday"];
238
+					}
239 239
 
240
-				$rdata = substr($rdata, 16);
241
-				if ($ret["subtype"] == 3) {
242
-					$data = unpack("Vnday", $rdata);
243
-					$ret["nday"] = $data["nday"];
244
-					$rdata = substr($rdata, 4);
245
-				}
246
-				break;
240
+					$rdata = substr($rdata, 16);
241
+					if ($ret["subtype"] == 3) {
242
+						$data = unpack("Vnday", $rdata);
243
+						$ret["nday"] = $data["nday"];
244
+						$rdata = substr($rdata, 4);
245
+					}
246
+					break;
247 247
 			}
248 248
 
249 249
 			if (strlen($rdata) < 16) {
@@ -573,312 +573,312 @@  discard block
 block discarded – undo
573 573
 			$term = (int) $this->recur["type"];
574 574
 
575 575
 			switch ($term) {
576
-			case 0x0A:
577
-				// Daily
578
-				if (!isset($this->recur["everyn"])) {
579
-					return;
580
-				}
581
-
582
-				if ($this->recur["subtype"] == 1) {
583
-					// Daily every workday
584
-					$rdata .= pack("VVVV", (6 * 24 * 60), 1, 0, 0x3E);
585
-				}
586
-				else {
587
-					// Daily every N days (everyN in minutes)
588
-					$everyn = ((int) $this->recur["everyn"]) / 1440;
589
-					// Calc first occ
590
-					$firstocc = $this->unixDataToRecurData($this->recur["start"]) % ((int) $this->recur["everyn"]);
591
-					$rdata .= pack("VVV", $firstocc, (int) $this->recur["everyn"], $this->recur["regen"] ? 1 : 0);
592
-				}
593
-				break;
594
-
595
-			case 0x0B:
596
-				// Weekly
597
-				if (!isset($this->recur["everyn"])) {
598
-					return;
599
-				}
600
-				if (!$this->recur["regen"] && !isset($this->recur["weekdays"])) {
601
-					return;
602
-				}
603
-
604
-				// No need to calculate startdate if sliding flag was set.
605
-				if (!$this->recur['regen']) {
606
-					// Calculate start date of recurrence
607
-
608
-					// Find the first day that matches one of the weekdays selected
609
-					$daycount = 0;
610
-					$dayskip = -1;
611
-					for ($j = 0; $j < 7; ++$j) {
612
-						if (((int) $this->recur["weekdays"]) & (1 << (($dayofweek + $j) % 7))) {
613
-							if ($dayskip == -1) {
614
-								$dayskip = $j;
615
-							}
616
-							++$daycount;
617
-						}
576
+				case 0x0A:
577
+					// Daily
578
+					if (!isset($this->recur["everyn"])) {
579
+						return;
618 580
 					}
619 581
 
620
-					// $dayskip is the number of days to skip from the startdate until the first occurrence
621
-					// $daycount is the number of days per week that an occurrence occurs
622
-					$weekskip = 0;
623
-					if (($dayofweek < $weekstart && $dayskip > 0) || ($dayofweek + $dayskip) > 6) {
624
-						$weekskip = 1;
582
+					if ($this->recur["subtype"] == 1) {
583
+						// Daily every workday
584
+						$rdata .= pack("VVVV", (6 * 24 * 60), 1, 0, 0x3E);
625 585
 					}
626
-
627
-					// Check if the recurrence ends after a number of occurrences, in that case we must calculate the
628
-					// remaining occurrences based on the start of the recurrence.
629
-					if (((int) $this->recur["term"]) == 0x22) {
630
-						// $weekskip is the amount of weeks to skip from the startdate before the first occurrence
631
-						// $forwardcount is the maximum number of week occurrences we can go ahead after the first occurrence that
632
-						// is still inside the recurrence. We subtract one to make sure that the last week is never forwarded over
633
-						// (eg when numoccur = 2, and daycount = 1)
634
-						$forwardcount = floor((int) ($this->recur["numoccur"] - 1) / $daycount);
635
-
636
-						// $restocc is the number of occurrences left after $forwardcount whole weeks of occurrences, minus one
637
-						// for the occurrence on the first day
638
-						$restocc = ((int) $this->recur["numoccur"]) - ($forwardcount * $daycount) - 1;
639
-
640
-						// $forwardcount is now the number of weeks we can go forward and still be inside the recurrence
641
-						$forwardcount *= (int) $this->recur["everyn"];
586
+					else {
587
+						// Daily every N days (everyN in minutes)
588
+						$everyn = ((int) $this->recur["everyn"]) / 1440;
589
+						// Calc first occ
590
+						$firstocc = $this->unixDataToRecurData($this->recur["start"]) % ((int) $this->recur["everyn"]);
591
+						$rdata .= pack("VVV", $firstocc, (int) $this->recur["everyn"], $this->recur["regen"] ? 1 : 0);
642 592
 					}
593
+					break;
643 594
 
644
-					// The real start is start + dayskip + weekskip-1 (since dayskip will already bring us into the next week)
645
-					$this->recur["start"] = ((int) $this->recur["start"]) + ($dayskip * 24 * 60 * 60) + ($weekskip * (((int) $this->recur["everyn"]) - 1) * 7 * 24 * 60 * 60);
646
-				}
647
-
648
-				// Calc first occ
649
-				$firstocc = ($this->unixDataToRecurData($this->recur["start"])) % (((int) $this->recur["everyn"]) * 7 * 24 * 60);
650
-				$firstocc -= (((int) gmdate("w", (int) $this->recur["start"])) - 1) * 24 * 60;
651
-
652
-				if ($this->recur["regen"]) {
653
-					$rdata .= pack("VVV", $firstocc, (int) $this->recur["everyn"], 1);
654
-				}
655
-				else {
656
-					$rdata .= pack("VVVV", $firstocc, (int) $this->recur["everyn"], 0, (int) $this->recur["weekdays"]);
657
-				}
658
-				break;
659
-
660
-			case 0x0C:
661
-				// Monthly
662
-			case 0x0D:
663
-				// Yearly
664
-				if (!isset($this->recur["everyn"])) {
665
-					return;
666
-				}
667
-				if ($term == 0x0D /* yearly */ && !isset($this->recur["month"])) {
668
-					return;
669
-				}
670
-				if ($term == 0x0C /* monthly */) {
671
-					$everyn = (int) $this->recur["everyn"];
672
-				}
673
-				else {
674
-					$everyn = $this->recur["regen"] ? ((int) $this->recur["everyn"]) * 12 : 12;
675
-				}
676
-
677
-				// Get montday/month/year of original start
678
-				$curmonthday = gmdate("j", (int) $this->recur["start"]);
679
-				$curyear = gmdate("Y", (int) $this->recur["start"]);
680
-				$curmonth = gmdate("n", (int) $this->recur["start"]);
681
-
682
-				// Check if the recurrence ends after a number of occurrences, in that case we must calculate the
683
-				// remaining occurrences based on the start of the recurrence.
684
-				if (((int) $this->recur["term"]) == 0x22) {
685
-					// $forwardcount is the number of occurrences we can skip and still be inside the recurrence range (minus
686
-					// one to make sure there are always at least one occurrence left)
687
-					$forwardcount = ((((int) $this->recur["numoccur"]) - 1) * $everyn);
688
-				}
689
-
690
-				// Get month for yearly on D'th day of month M
691
-				if ($term == 0x0D /* yearly */) {
692
-					$selmonth = floor(((int) $this->recur["month"]) / (24 * 60 * 29)) + 1;
693
-				} // 1=jan, 2=feb, eg
694
-
695
-				switch ((int) $this->recur["subtype"]) {
696
-				// on D day of every M month
697
-				case 2:
698
-					if (!isset($this->recur["monthday"])) {
595
+				case 0x0B:
596
+					// Weekly
597
+					if (!isset($this->recur["everyn"])) {
598
+						return;
599
+					}
600
+					if (!$this->recur["regen"] && !isset($this->recur["weekdays"])) {
699 601
 						return;
700 602
 					}
701
-					// Recalc startdate
702
-					// Set on the right begin day
703
-					// Go the beginning of the month
704
-					$this->recur["start"] -= ($curmonthday - 1) * 24 * 60 * 60;
705
-					// Go the the correct month day
706
-					$this->recur["start"] += (((int) $this->recur["monthday"]) - 1) * 24 * 60 * 60;
707
-
708
-					// If the previous calculation gave us a start date *before* the original start date, then we need to skip to the next occurrence
709
-					if (($term == 0x0C /* monthly */ && ((int) $this->recur["monthday"]) < $curmonthday) ||
710
-						($term == 0x0D /* yearly */ && ($selmonth < $curmonth || ($selmonth == $curmonth && ((int) $this->recur["monthday"]) < $curmonthday)))) {
711
-						if ($term == 0x0D /* yearly */) {
712
-							$count = ($everyn - ($curmonth - $selmonth));
713
-						} // Yearly, go to next occurrence in 'everyn' months minus difference in first occurrence and original date
714
-						else {
715
-							$count = $everyn;
716
-						} // Monthly, go to next occurrence in 'everyn' months
717
-
718
-						// Forward by $count months. This is done by getting the number of days in that month and forwarding that many days
719
-						for ($i = 0; $i < $count; ++$i) {
720
-							$this->recur["start"] += $this->getMonthInSeconds($curyear, $curmonth);
721
-							if ($curmonth == 12) {
722
-								++$curyear;
723
-								$curmonth = 0;
603
+
604
+					// No need to calculate startdate if sliding flag was set.
605
+					if (!$this->recur['regen']) {
606
+						// Calculate start date of recurrence
607
+
608
+						// Find the first day that matches one of the weekdays selected
609
+						$daycount = 0;
610
+						$dayskip = -1;
611
+						for ($j = 0; $j < 7; ++$j) {
612
+							if (((int) $this->recur["weekdays"]) & (1 << (($dayofweek + $j) % 7))) {
613
+								if ($dayskip == -1) {
614
+									$dayskip = $j;
615
+								}
616
+								++$daycount;
724 617
 							}
725
-							++$curmonth;
726 618
 						}
727
-					}
728 619
 
729
-					// "start" is now pointing to the first occurrence, except that it will overshoot if the
730
-					// month in which it occurs has less days than specified as the day of the month. So 31st
731
-					// of each month will overshoot in february (29 days). We compensate for that by checking
732
-					// if the day of the month we got is wrong, and then back up to the last day of the previous
733
-					// month.
734
-					if (((int) $this->recur["monthday"]) >= 28 && ((int) $this->recur["monthday"]) <= 31 &&
735
-						gmdate("j", ((int) $this->recur["start"])) < ((int) $this->recur["monthday"])) {
736
-						$this->recur["start"] -= gmdate("j", ((int) $this->recur["start"])) * 24 * 60 * 60;
620
+						// $dayskip is the number of days to skip from the startdate until the first occurrence
621
+						// $daycount is the number of days per week that an occurrence occurs
622
+						$weekskip = 0;
623
+						if (($dayofweek < $weekstart && $dayskip > 0) || ($dayofweek + $dayskip) > 6) {
624
+							$weekskip = 1;
625
+						}
626
+
627
+						// Check if the recurrence ends after a number of occurrences, in that case we must calculate the
628
+						// remaining occurrences based on the start of the recurrence.
629
+						if (((int) $this->recur["term"]) == 0x22) {
630
+							// $weekskip is the amount of weeks to skip from the startdate before the first occurrence
631
+							// $forwardcount is the maximum number of week occurrences we can go ahead after the first occurrence that
632
+							// is still inside the recurrence. We subtract one to make sure that the last week is never forwarded over
633
+							// (eg when numoccur = 2, and daycount = 1)
634
+							$forwardcount = floor((int) ($this->recur["numoccur"] - 1) / $daycount);
635
+
636
+							// $restocc is the number of occurrences left after $forwardcount whole weeks of occurrences, minus one
637
+							// for the occurrence on the first day
638
+							$restocc = ((int) $this->recur["numoccur"]) - ($forwardcount * $daycount) - 1;
639
+
640
+							// $forwardcount is now the number of weeks we can go forward and still be inside the recurrence
641
+							$forwardcount *= (int) $this->recur["everyn"];
642
+						}
643
+
644
+						// The real start is start + dayskip + weekskip-1 (since dayskip will already bring us into the next week)
645
+						$this->recur["start"] = ((int) $this->recur["start"]) + ($dayskip * 24 * 60 * 60) + ($weekskip * (((int) $this->recur["everyn"]) - 1) * 7 * 24 * 60 * 60);
737 646
 					}
738 647
 
739
-					// "start" is now the first occurrence
740
-					if ($term == 0x0C /* monthly */) {
741
-						// Calc first occ
742
-						$monthIndex = ((((12 % $everyn) * ((((int) gmdate("Y", $this->recur["start"])) - 1601) % $everyn)) % $everyn) + (((int) gmdate("n", $this->recur["start"])) - 1)) % $everyn;
648
+					// Calc first occ
649
+					$firstocc = ($this->unixDataToRecurData($this->recur["start"])) % (((int) $this->recur["everyn"]) * 7 * 24 * 60);
650
+					$firstocc -= (((int) gmdate("w", (int) $this->recur["start"])) - 1) * 24 * 60;
743 651
 
744
-						$firstocc = 0;
745
-						for ($i = 0; $i < $monthIndex; ++$i) {
746
-							$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), ($i % 12) + 1) / 60;
747
-						}
748
-						$rdata .= pack("VVVV", $firstocc, $everyn, $this->recur["regen"], (int) $this->recur["monthday"]);
652
+					if ($this->recur["regen"]) {
653
+						$rdata .= pack("VVV", $firstocc, (int) $this->recur["everyn"], 1);
749 654
 					}
750 655
 					else {
751
-						// Calc first occ
752
-						$firstocc = 0;
753
-						$monthIndex = (int) gmdate("n", $this->recur["start"]);
754
-						for ($i = 1; $i < $monthIndex; ++$i) {
755
-							$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i) / 60;
756
-						}
757
-						$rdata .= pack("VVVV", $firstocc, $everyn, $this->recur["regen"], (int) $this->recur["monthday"]);
656
+						$rdata .= pack("VVVV", $firstocc, (int) $this->recur["everyn"], 0, (int) $this->recur["weekdays"]);
758 657
 					}
759 658
 					break;
760 659
 
761
-				case 3:
762
-					// monthly: on Nth weekday of every M month
763
-					// yearly: on Nth weekday of M month
764
-					if (!isset($this->recur["weekdays"]) && !isset($this->recur["nday"])) {
660
+				case 0x0C:
661
+					// Monthly
662
+				case 0x0D:
663
+					// Yearly
664
+					if (!isset($this->recur["everyn"])) {
765 665
 						return;
766 666
 					}
767
-
768
-					$weekdays = (int) $this->recur["weekdays"];
769
-					$nday = (int) $this->recur["nday"];
770
-
771
-					// Calc startdate
772
-					$monthbegindow = (int) $this->recur["start"];
773
-
774
-					if ($nday == 5) {
775
-						// Set date on the last day of the last month
776
-						$monthbegindow += (gmdate("t", $monthbegindow) - gmdate("j", $monthbegindow)) * 24 * 60 * 60;
667
+					if ($term == 0x0D /* yearly */ && !isset($this->recur["month"])) {
668
+						return;
669
+					}
670
+					if ($term == 0x0C /* monthly */) {
671
+						$everyn = (int) $this->recur["everyn"];
777 672
 					}
778 673
 					else {
779
-						// Set on the first day of the month
780
-						$monthbegindow -= ((gmdate("j", $monthbegindow) - 1) * 24 * 60 * 60);
674
+						$everyn = $this->recur["regen"] ? ((int) $this->recur["everyn"]) * 12 : 12;
675
+					}
676
+
677
+					// Get montday/month/year of original start
678
+					$curmonthday = gmdate("j", (int) $this->recur["start"]);
679
+					$curyear = gmdate("Y", (int) $this->recur["start"]);
680
+					$curmonth = gmdate("n", (int) $this->recur["start"]);
681
+
682
+					// Check if the recurrence ends after a number of occurrences, in that case we must calculate the
683
+					// remaining occurrences based on the start of the recurrence.
684
+					if (((int) $this->recur["term"]) == 0x22) {
685
+						// $forwardcount is the number of occurrences we can skip and still be inside the recurrence range (minus
686
+						// one to make sure there are always at least one occurrence left)
687
+						$forwardcount = ((((int) $this->recur["numoccur"]) - 1) * $everyn);
781 688
 					}
782 689
 
690
+					// Get month for yearly on D'th day of month M
783 691
 					if ($term == 0x0D /* yearly */) {
784
-						// Set on right month
785
-						if ($selmonth < $curmonth) {
786
-							$tmp = 12 - $curmonth + $selmonth;
787
-						}
788
-						else {
789
-							$tmp = ($selmonth - $curmonth);
790
-						}
692
+						$selmonth = floor(((int) $this->recur["month"]) / (24 * 60 * 29)) + 1;
693
+					} // 1=jan, 2=feb, eg
791 694
 
792
-						for ($i = 0; $i < $tmp; ++$i) {
793
-							$monthbegindow += $this->getMonthInSeconds($curyear, $curmonth);
794
-							if ($curmonth == 12) {
795
-								++$curyear;
796
-								$curmonth = 0;
695
+					switch ((int) $this->recur["subtype"]) {
696
+					// on D day of every M month
697
+						case 2:
698
+							if (!isset($this->recur["monthday"])) {
699
+								return;
700
+							}
701
+							// Recalc startdate
702
+							// Set on the right begin day
703
+							// Go the beginning of the month
704
+							$this->recur["start"] -= ($curmonthday - 1) * 24 * 60 * 60;
705
+							// Go the the correct month day
706
+							$this->recur["start"] += (((int) $this->recur["monthday"]) - 1) * 24 * 60 * 60;
707
+
708
+							// If the previous calculation gave us a start date *before* the original start date, then we need to skip to the next occurrence
709
+							if (($term == 0x0C /* monthly */ && ((int) $this->recur["monthday"]) < $curmonthday) ||
710
+								($term == 0x0D /* yearly */ && ($selmonth < $curmonth || ($selmonth == $curmonth && ((int) $this->recur["monthday"]) < $curmonthday)))) {
711
+								if ($term == 0x0D /* yearly */) {
712
+									$count = ($everyn - ($curmonth - $selmonth));
713
+								} // Yearly, go to next occurrence in 'everyn' months minus difference in first occurrence and original date
714
+								else {
715
+									$count = $everyn;
716
+								} // Monthly, go to next occurrence in 'everyn' months
717
+
718
+								// Forward by $count months. This is done by getting the number of days in that month and forwarding that many days
719
+								for ($i = 0; $i < $count; ++$i) {
720
+									$this->recur["start"] += $this->getMonthInSeconds($curyear, $curmonth);
721
+									if ($curmonth == 12) {
722
+										++$curyear;
723
+										$curmonth = 0;
724
+									}
725
+									++$curmonth;
726
+								}
797 727
 							}
798
-							++$curmonth;
799
-						}
800
-					}
801
-					else {
802
-						// Check or you exist in the right month
803
-						for ($i = 0; $i < 7; ++$i) {
804
-							if ($nday == 5 && (1 << ((gmdate("w", $monthbegindow) - $i) % 7)) & $weekdays) {
805
-								$day = gmdate("j", $monthbegindow) - $i;
806 728
 
807
-								break;
729
+							// "start" is now pointing to the first occurrence, except that it will overshoot if the
730
+							// month in which it occurs has less days than specified as the day of the month. So 31st
731
+							// of each month will overshoot in february (29 days). We compensate for that by checking
732
+							// if the day of the month we got is wrong, and then back up to the last day of the previous
733
+							// month.
734
+							if (((int) $this->recur["monthday"]) >= 28 && ((int) $this->recur["monthday"]) <= 31 &&
735
+								gmdate("j", ((int) $this->recur["start"])) < ((int) $this->recur["monthday"])) {
736
+								$this->recur["start"] -= gmdate("j", ((int) $this->recur["start"])) * 24 * 60 * 60;
808 737
 							}
809
-							if ($nday != 5 && (1 << ((gmdate("w", $monthbegindow) + $i) % 7)) & $weekdays) {
810
-								$day = (($nday - 1) * 7) + ($i + 1);
811 738
 
812
-								break;
739
+							// "start" is now the first occurrence
740
+							if ($term == 0x0C /* monthly */) {
741
+								// Calc first occ
742
+								$monthIndex = ((((12 % $everyn) * ((((int) gmdate("Y", $this->recur["start"])) - 1601) % $everyn)) % $everyn) + (((int) gmdate("n", $this->recur["start"])) - 1)) % $everyn;
743
+
744
+								$firstocc = 0;
745
+								for ($i = 0; $i < $monthIndex; ++$i) {
746
+									$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), ($i % 12) + 1) / 60;
747
+								}
748
+								$rdata .= pack("VVVV", $firstocc, $everyn, $this->recur["regen"], (int) $this->recur["monthday"]);
749
+							}
750
+							else {
751
+								// Calc first occ
752
+								$firstocc = 0;
753
+								$monthIndex = (int) gmdate("n", $this->recur["start"]);
754
+								for ($i = 1; $i < $monthIndex; ++$i) {
755
+									$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i) / 60;
756
+								}
757
+								$rdata .= pack("VVVV", $firstocc, $everyn, $this->recur["regen"], (int) $this->recur["monthday"]);
758
+							}
759
+							break;
760
+
761
+						case 3:
762
+							// monthly: on Nth weekday of every M month
763
+							// yearly: on Nth weekday of M month
764
+							if (!isset($this->recur["weekdays"]) && !isset($this->recur["nday"])) {
765
+								return;
813 766
 							}
814
-						}
815 767
 
816
-						// Goto the next X month
817
-						if (isset($day) && ($day < gmdate("j", (int) $this->recur["start"]))) {
768
+							$weekdays = (int) $this->recur["weekdays"];
769
+							$nday = (int) $this->recur["nday"];
770
+
771
+							// Calc startdate
772
+							$monthbegindow = (int) $this->recur["start"];
773
+
818 774
 							if ($nday == 5) {
819
-								$monthbegindow += 24 * 60 * 60;
820
-								if ($curmonth == 12) {
821
-									++$curyear;
822
-									$curmonth = 0;
823
-								}
824
-								++$curmonth;
775
+								// Set date on the last day of the last month
776
+								$monthbegindow += (gmdate("t", $monthbegindow) - gmdate("j", $monthbegindow)) * 24 * 60 * 60;
777
+							}
778
+							else {
779
+								// Set on the first day of the month
780
+								$monthbegindow -= ((gmdate("j", $monthbegindow) - 1) * 24 * 60 * 60);
825 781
 							}
826 782
 
827
-							for ($i = 0; $i < $everyn; ++$i) {
828
-								$monthbegindow += $this->getMonthInSeconds($curyear, $curmonth);
829
-								if ($curmonth == 12) {
830
-									++$curyear;
831
-									$curmonth = 0;
783
+							if ($term == 0x0D /* yearly */) {
784
+								// Set on right month
785
+								if ($selmonth < $curmonth) {
786
+									$tmp = 12 - $curmonth + $selmonth;
787
+								}
788
+								else {
789
+									$tmp = ($selmonth - $curmonth);
790
+								}
791
+
792
+								for ($i = 0; $i < $tmp; ++$i) {
793
+									$monthbegindow += $this->getMonthInSeconds($curyear, $curmonth);
794
+									if ($curmonth == 12) {
795
+										++$curyear;
796
+										$curmonth = 0;
797
+									}
798
+									++$curmonth;
832 799
 								}
833
-								++$curmonth;
834 800
 							}
835
-							if ($nday == 5) {
836
-								$monthbegindow -= 24 * 60 * 60;
801
+							else {
802
+								// Check or you exist in the right month
803
+								for ($i = 0; $i < 7; ++$i) {
804
+									if ($nday == 5 && (1 << ((gmdate("w", $monthbegindow) - $i) % 7)) & $weekdays) {
805
+										$day = gmdate("j", $monthbegindow) - $i;
806
+
807
+										break;
808
+									}
809
+									if ($nday != 5 && (1 << ((gmdate("w", $monthbegindow) + $i) % 7)) & $weekdays) {
810
+										$day = (($nday - 1) * 7) + ($i + 1);
811
+
812
+										break;
813
+									}
814
+								}
815
+
816
+								// Goto the next X month
817
+								if (isset($day) && ($day < gmdate("j", (int) $this->recur["start"]))) {
818
+									if ($nday == 5) {
819
+										$monthbegindow += 24 * 60 * 60;
820
+										if ($curmonth == 12) {
821
+											++$curyear;
822
+											$curmonth = 0;
823
+										}
824
+										++$curmonth;
825
+									}
826
+
827
+									for ($i = 0; $i < $everyn; ++$i) {
828
+										$monthbegindow += $this->getMonthInSeconds($curyear, $curmonth);
829
+										if ($curmonth == 12) {
830
+											++$curyear;
831
+											$curmonth = 0;
832
+										}
833
+										++$curmonth;
834
+									}
835
+									if ($nday == 5) {
836
+										$monthbegindow -= 24 * 60 * 60;
837
+									}
838
+								}
837 839
 							}
838
-						}
839
-					}
840 840
 
841
-					// FIXME: weekstart?
841
+							// FIXME: weekstart?
842 842
 
843
-					$day = 0;
844
-					// Set start on the right day
845
-					for ($i = 0; $i < 7; ++$i) {
846
-						if ($nday == 5 && (1 << ((gmdate("w", $monthbegindow) - $i) % 7)) & $weekdays) {
847
-							$day = $i;
843
+							$day = 0;
844
+							// Set start on the right day
845
+							for ($i = 0; $i < 7; ++$i) {
846
+								if ($nday == 5 && (1 << ((gmdate("w", $monthbegindow) - $i) % 7)) & $weekdays) {
847
+									$day = $i;
848 848
 
849
-							break;
850
-						}
851
-						if ($nday != 5 && (1 << ((gmdate("w", $monthbegindow) + $i) % 7)) & $weekdays) {
852
-							$day = ($nday - 1) * 7 + ($i + 1);
849
+									break;
850
+								}
851
+								if ($nday != 5 && (1 << ((gmdate("w", $monthbegindow) + $i) % 7)) & $weekdays) {
852
+									$day = ($nday - 1) * 7 + ($i + 1);
853 853
 
854
-							break;
855
-						}
856
-					}
857
-					if ($nday == 5) {
858
-						$monthbegindow -= $day * 24 * 60 * 60;
859
-					}
860
-					else {
861
-						$monthbegindow += ($day - 1) * 24 * 60 * 60;
862
-					}
854
+									break;
855
+								}
856
+							}
857
+							if ($nday == 5) {
858
+								$monthbegindow -= $day * 24 * 60 * 60;
859
+							}
860
+							else {
861
+								$monthbegindow += ($day - 1) * 24 * 60 * 60;
862
+							}
863 863
 
864
-					$firstocc = 0;
865
-					if ($term == 0x0C /* monthly */) {
866
-						// Calc first occ
867
-						$monthIndex = ((((12 % $everyn) * (((int) gmdate("Y", $this->recur["start"]) - 1601) % $everyn)) % $everyn) + (((int) gmdate("n", $this->recur["start"])) - 1)) % $everyn;
868
-						for ($i = 0; $i < $monthIndex; ++$i) {
869
-							$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), ($i % 12) + 1) / 60;
870
-						}
871
-						$rdata .= pack("VVVVV", $firstocc, $everyn, 0, $weekdays, $nday);
872
-						break;
873
-					}
874
-					// Calc first occ
875
-					$monthIndex = (int) gmdate("n", $this->recur["start"]);
876
-					for ($i = 1; $i < $monthIndex; ++$i) {
877
-						$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i) / 60;
864
+							$firstocc = 0;
865
+							if ($term == 0x0C /* monthly */) {
866
+								// Calc first occ
867
+								$monthIndex = ((((12 % $everyn) * (((int) gmdate("Y", $this->recur["start"]) - 1601) % $everyn)) % $everyn) + (((int) gmdate("n", $this->recur["start"])) - 1)) % $everyn;
868
+								for ($i = 0; $i < $monthIndex; ++$i) {
869
+									$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), ($i % 12) + 1) / 60;
870
+								}
871
+								$rdata .= pack("VVVVV", $firstocc, $everyn, 0, $weekdays, $nday);
872
+								break;
873
+							}
874
+							// Calc first occ
875
+							$monthIndex = (int) gmdate("n", $this->recur["start"]);
876
+							for ($i = 1; $i < $monthIndex; ++$i) {
877
+								$firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i) / 60;
878
+							}
879
+							$rdata .= pack("VVVVV", $firstocc, $everyn, 0, $weekdays, $nday);
880
+							break;
878 881
 					}
879
-					$rdata .= pack("VVVVV", $firstocc, $everyn, 0, $weekdays, $nday);
880
-					break;
881
-				}
882 882
 				break;
883 883
 			}
884 884
 
@@ -892,20 +892,20 @@  discard block
 block discarded – undo
892 892
 
893 893
 			switch ($term) {
894 894
 			// After the given enddate
895
-			case 0x21:
896
-				$rdata .= pack("V", 10);
897
-				break;
898
-			// After a number of times
899
-			case 0x22:
900
-				if (!isset($this->recur["numoccur"])) {
901
-					return;
902
-				}
903
-				$rdata .= pack("V", (int) $this->recur["numoccur"]);
904
-				break;
905
-			// Never ends
906
-			case 0x23:
907
-				$rdata .= pack("V", 0);
908
-				break;
895
+				case 0x21:
896
+					$rdata .= pack("V", 10);
897
+					break;
898
+				// After a number of times
899
+				case 0x22:
900
+					if (!isset($this->recur["numoccur"])) {
901
+						return;
902
+					}
903
+					$rdata .= pack("V", (int) $this->recur["numoccur"]);
904
+					break;
905
+				// Never ends
906
+				case 0x23:
907
+					$rdata .= pack("V", 0);
908
+					break;
909 909
 			}
910 910
 
911 911
 			// Strange little thing for the recurrence type "every workday"
@@ -958,135 +958,135 @@  discard block
 block discarded – undo
958 958
 			// Set enddate
959 959
 			switch ($term) {
960 960
 			// After the given enddate
961
-			case 0x21:
962
-				$rdata .= pack("V", $this->unixDataToRecurData((int) $this->recur["end"]));
963
-				break;
964
-			// After a number of times
965
-			case 0x22:
966
-				// @todo: calculate enddate with intval($this->recur["startocc"]) + intval($this->recur["duration"]) > 24 hour
967
-				$occenddate = (int) $this->recur["start"];
968
-
969
-				switch ((int) $this->recur["type"]) {
970
-				case 0x0A: // daily
971
-					if ($this->recur["subtype"] != 1) {
972
-						// -1 because the first day already counts (from 1-1-1980 to 1-1-1980 is 1 occurrence)
973
-						$occenddate += (((int) $this->recur["everyn"]) * 60 * (((int) $this->recur["numoccur"] - 1)));
974
-						break;
975
-					}
976
-					// Daily every workday
977
-					$restocc = (int) $this->recur["numoccur"];
978
-					// Get starting weekday
979
-					$nowtime = $this->gmtime($occenddate);
980
-					$j = $nowtime["tm_wday"];
981
-
982
-					while (1) {
983
-						if (($j % 7) > 0 && ($j % 7) < 6) {
984
-							--$restocc;
985
-						}
986
-						++$j;
987
-						if ($restocc <= 0) {
988
-							break;
989
-						}
990
-						$occenddate += 24 * 60 * 60;
991
-					}
961
+				case 0x21:
962
+					$rdata .= pack("V", $this->unixDataToRecurData((int) $this->recur["end"]));
992 963
 					break;
964
+				// After a number of times
965
+				case 0x22:
966
+					// @todo: calculate enddate with intval($this->recur["startocc"]) + intval($this->recur["duration"]) > 24 hour
967
+					$occenddate = (int) $this->recur["start"];
968
+
969
+					switch ((int) $this->recur["type"]) {
970
+						case 0x0A: // daily
971
+							if ($this->recur["subtype"] != 1) {
972
+								// -1 because the first day already counts (from 1-1-1980 to 1-1-1980 is 1 occurrence)
973
+								$occenddate += (((int) $this->recur["everyn"]) * 60 * (((int) $this->recur["numoccur"] - 1)));
974
+								break;
975
+							}
976
+							// Daily every workday
977
+							$restocc = (int) $this->recur["numoccur"];
978
+							// Get starting weekday
979
+							$nowtime = $this->gmtime($occenddate);
980
+							$j = $nowtime["tm_wday"];
981
+
982
+							while (1) {
983
+								if (($j % 7) > 0 && ($j % 7) < 6) {
984
+									--$restocc;
985
+								}
986
+								++$j;
987
+								if ($restocc <= 0) {
988
+									break;
989
+								}
990
+								$occenddate += 24 * 60 * 60;
991
+							}
992
+							break;
993 993
 
994
-				case 0x0B: // weekly
995
-					// Needed values
996
-					// $forwardcount - number of weeks we can skip forward
997
-					// $restocc - number of remaining occurrences after the week skip
998
-
999
-					// Add the weeks till the last item
1000
-					$occenddate += ($forwardcount * 7 * 24 * 60 * 60);
1001
-					$dayofweek = gmdate("w", $occenddate);
1002
-
1003
-					// Loop through the last occurrences until we have had them all
1004
-					for ($j = 1; $restocc > 0; ++$j) {
1005
-						// Jump to the next week (which may be N weeks away) when going over the week boundary
1006
-						if ((($dayofweek + $j) % 7) == $weekstart) {
1007
-							$occenddate += (((int) $this->recur["everyn"]) - 1) * 7 * 24 * 60 * 60;
1008
-						}
994
+						case 0x0B: // weekly
995
+							// Needed values
996
+							// $forwardcount - number of weeks we can skip forward
997
+							// $restocc - number of remaining occurrences after the week skip
1009 998
 
1010
-						// If this is a matching day, once less occurrence to process
1011
-						if (((int) $this->recur["weekdays"]) & (1 << (($dayofweek + $j) % 7))) {
1012
-							--$restocc;
1013
-						}
999
+							// Add the weeks till the last item
1000
+							$occenddate += ($forwardcount * 7 * 24 * 60 * 60);
1001
+							$dayofweek = gmdate("w", $occenddate);
1014 1002
 
1015
-						// Next day
1016
-						$occenddate += 24 * 60 * 60;
1017
-					}
1018
-					break;
1003
+							// Loop through the last occurrences until we have had them all
1004
+							for ($j = 1; $restocc > 0; ++$j) {
1005
+								// Jump to the next week (which may be N weeks away) when going over the week boundary
1006
+								if ((($dayofweek + $j) % 7) == $weekstart) {
1007
+									$occenddate += (((int) $this->recur["everyn"]) - 1) * 7 * 24 * 60 * 60;
1008
+								}
1019 1009
 
1020
-				case 0x0C: // monthly
1021
-				case 0x0D: // yearly
1022
-					$curyear = gmdate("Y", (int) $this->recur["start"]);
1023
-					$curmonth = gmdate("n", (int) $this->recur["start"]);
1024
-					// $forwardcount = months
1010
+								// If this is a matching day, once less occurrence to process
1011
+								if (((int) $this->recur["weekdays"]) & (1 << (($dayofweek + $j) % 7))) {
1012
+									--$restocc;
1013
+								}
1025 1014
 
1026
-					switch ((int) $this->recur["subtype"]) {
1027
-					case 2: // on D day of every M month
1028
-						while ($forwardcount > 0) {
1029
-							$occenddate += $this->getMonthInSeconds($curyear, $curmonth);
1030
-							if ($curmonth >= 12) {
1031
-								$curmonth = 1;
1032
-								++$curyear;
1015
+								// Next day
1016
+								$occenddate += 24 * 60 * 60;
1033 1017
 							}
1034
-							else {
1035
-								++$curmonth;
1036
-							}
1037
-							--$forwardcount;
1038
-						}
1018
+							break;
1039 1019
 
1040
-						// compensation between 28 and 31
1041
-						if (((int) $this->recur["monthday"]) >= 28 && ((int) $this->recur["monthday"]) <= 31 &&
1042
-							gmdate("j", $occenddate) < ((int) $this->recur["monthday"])) {
1043
-							if (gmdate("j", $occenddate) < 28) {
1044
-								$occenddate -= gmdate("j", $occenddate) * 24 * 60 * 60;
1045
-							}
1046
-							else {
1047
-								$occenddate += (gmdate("t", $occenddate) - gmdate("j", $occenddate)) * 24 * 60 * 60;
1048
-							}
1049
-						}
1050
-						break;
1020
+						case 0x0C: // monthly
1021
+						case 0x0D: // yearly
1022
+							$curyear = gmdate("Y", (int) $this->recur["start"]);
1023
+							$curmonth = gmdate("n", (int) $this->recur["start"]);
1024
+							// $forwardcount = months
1025
+
1026
+							switch ((int) $this->recur["subtype"]) {
1027
+								case 2: // on D day of every M month
1028
+									while ($forwardcount > 0) {
1029
+										$occenddate += $this->getMonthInSeconds($curyear, $curmonth);
1030
+										if ($curmonth >= 12) {
1031
+											$curmonth = 1;
1032
+											++$curyear;
1033
+										}
1034
+										else {
1035
+											++$curmonth;
1036
+										}
1037
+										--$forwardcount;
1038
+									}
1051 1039
 
1052
-					case 3: // on Nth weekday of every M month
1053
-						$nday = (int) $this->recur["nday"]; // 1 tot 5
1054
-						$weekdays = (int) $this->recur["weekdays"];
1055
-						while ($forwardcount > 0) {
1056
-							$occenddate += $this->getMonthInSeconds($curyear, $curmonth);
1057
-							if ($curmonth >= 12) {
1058
-								$curmonth = 1;
1059
-								++$curyear;
1060
-							}
1061
-							else {
1062
-								++$curmonth;
1063
-							}
1064
-							--$forwardcount;
1065
-						}
1066
-						if ($nday == 5) {
1067
-							// Set date on the last day of the last month
1068
-							$occenddate += (gmdate("t", $occenddate) - gmdate("j", $occenddate)) * 24 * 60 * 60;
1069
-						}
1070
-						else {
1071
-							// Set date on the first day of the last month
1072
-							$occenddate -= (gmdate("j", $occenddate) - 1) * 24 * 60 * 60;
1073
-						}
1040
+									// compensation between 28 and 31
1041
+									if (((int) $this->recur["monthday"]) >= 28 && ((int) $this->recur["monthday"]) <= 31 &&
1042
+										gmdate("j", $occenddate) < ((int) $this->recur["monthday"])) {
1043
+										if (gmdate("j", $occenddate) < 28) {
1044
+											$occenddate -= gmdate("j", $occenddate) * 24 * 60 * 60;
1045
+										}
1046
+										else {
1047
+											$occenddate += (gmdate("t", $occenddate) - gmdate("j", $occenddate)) * 24 * 60 * 60;
1048
+										}
1049
+									}
1050
+									break;
1074 1051
 
1075
-						for ($i = 0; $i < 7; ++$i) {
1076
-							if ($nday == 5 && (1 << ((gmdate("w", $occenddate) - $i) % 7)) & $weekdays) {
1077
-								$occenddate -= $i * 24 * 60 * 60;
1052
+								case 3: // on Nth weekday of every M month
1053
+									$nday = (int) $this->recur["nday"]; // 1 tot 5
1054
+									$weekdays = (int) $this->recur["weekdays"];
1055
+									while ($forwardcount > 0) {
1056
+										$occenddate += $this->getMonthInSeconds($curyear, $curmonth);
1057
+										if ($curmonth >= 12) {
1058
+											$curmonth = 1;
1059
+											++$curyear;
1060
+										}
1061
+										else {
1062
+											++$curmonth;
1063
+										}
1064
+										--$forwardcount;
1065
+									}
1066
+									if ($nday == 5) {
1067
+										// Set date on the last day of the last month
1068
+										$occenddate += (gmdate("t", $occenddate) - gmdate("j", $occenddate)) * 24 * 60 * 60;
1069
+									}
1070
+									else {
1071
+										// Set date on the first day of the last month
1072
+										$occenddate -= (gmdate("j", $occenddate) - 1) * 24 * 60 * 60;
1073
+									}
1078 1074
 
1079
-								break;
1080
-							}
1081
-							if ($nday != 5 && (1 << ((gmdate("w", $occenddate) + $i) % 7)) & $weekdays) {
1082
-								$occenddate += ($i + (($nday - 1) * 7)) * 24 * 60 * 60;
1075
+									for ($i = 0; $i < 7; ++$i) {
1076
+										if ($nday == 5 && (1 << ((gmdate("w", $occenddate) - $i) % 7)) & $weekdays) {
1077
+											$occenddate -= $i * 24 * 60 * 60;
1083 1078
 
1084
-								break;
1079
+											break;
1080
+										}
1081
+										if ($nday != 5 && (1 << ((gmdate("w", $occenddate) + $i) % 7)) & $weekdays) {
1082
+											$occenddate += ($i + (($nday - 1) * 7)) * 24 * 60 * 60;
1083
+
1084
+											break;
1085
+										}
1086
+									}
1087
+									break; // case 3:
1085 1088
 							}
1086
-						}
1087
-						break; // case 3:
1088
-					}
1089
-					break;
1089
+						break;
1090 1090
 				}
1091 1091
 
1092 1092
 				if (defined("PHP_INT_MAX") && $occenddate > PHP_INT_MAX) {
@@ -1097,11 +1097,11 @@  discard block
 block discarded – undo
1097 1097
 				$rdata .= pack("V", $this->unixDataToRecurData((int) $this->recur["end"]));
1098 1098
 				break;
1099 1099
 			// Never ends
1100
-			case 0x23:
1101
-			default:
1102
-				$this->recur["end"] = 0x7FFFFFFF; // max date -> 2038
1103
-				$rdata .= pack("V", 0x5AE980DF);
1104
-				break;
1100
+				case 0x23:
1101
+				default:
1102
+					$this->recur["end"] = 0x7FFFFFFF; // max date -> 2038
1103
+					$rdata .= pack("V", 0x5AE980DF);
1104
+					break;
1105 1105
 			}
1106 1106
 
1107 1107
 			// UTC date
@@ -1647,188 +1647,188 @@  discard block
 block discarded – undo
1647 1647
 				// Loop through the entire recurrence range of dates, and check for each occurrence whether it is in the view range.
1648 1648
 
1649 1649
 				switch ($this->recur["type"]) {
1650
-				case 10:
1651
-					// Daily
1652
-					if ($this->recur["everyn"] <= 0) {
1653
-						$this->recur["everyn"] = 1440;
1654
-					}
1650
+					case 10:
1651
+						// Daily
1652
+						if ($this->recur["everyn"] <= 0) {
1653
+							$this->recur["everyn"] = 1440;
1654
+						}
1655 1655
 
1656
-					if ($this->recur["subtype"] == 0) {
1657
-						// Every Nth day
1658
-						for ($now = $daystart; $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += 60 * $this->recur["everyn"]) {
1659
-							$this->processOccurrenceItem($items, $start, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1656
+						if ($this->recur["subtype"] == 0) {
1657
+							// Every Nth day
1658
+							for ($now = $daystart; $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += 60 * $this->recur["everyn"]) {
1659
+								$this->processOccurrenceItem($items, $start, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1660
+							}
1661
+							break;
1660 1662
 						}
1661
-						break;
1662
-					}
1663
-					// Every workday
1664
-					for ($now = $daystart; $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += 60 * 1440) {
1665
-						$nowtime = $this->gmtime($now);
1666
-						if ($nowtime["tm_wday"] > 0 && $nowtime["tm_wday"] < 6) { // only add items in the given timespace
1667
-							$this->processOccurrenceItem($items, $start, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1663
+						// Every workday
1664
+						for ($now = $daystart; $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += 60 * 1440) {
1665
+							$nowtime = $this->gmtime($now);
1666
+							if ($nowtime["tm_wday"] > 0 && $nowtime["tm_wday"] < 6) { // only add items in the given timespace
1667
+								$this->processOccurrenceItem($items, $start, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1668
+							}
1668 1669
 						}
1669
-					}
1670
-					break;
1671
-
1672
-				case 11:
1673
-					// Weekly
1674
-					if ($this->recur["everyn"] <= 0) {
1675
-						$this->recur["everyn"] = 1;
1676
-					}
1670
+						break;
1677 1671
 
1678
-					// If sliding flag is set then move to 'n' weeks
1679
-					if ($this->recur['regen']) {
1680
-						$daystart += (60 * 60 * 24 * 7 * $this->recur["everyn"]);
1681
-					}
1672
+					case 11:
1673
+						// Weekly
1674
+						if ($this->recur["everyn"] <= 0) {
1675
+							$this->recur["everyn"] = 1;
1676
+						}
1682 1677
 
1683
-					for ($now = $daystart; $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += (60 * 60 * 24 * 7 * $this->recur["everyn"])) {
1678
+						// If sliding flag is set then move to 'n' weeks
1684 1679
 						if ($this->recur['regen']) {
1685
-							$this->processOccurrenceItem($items, $start, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1686
-
1687
-							break;
1680
+							$daystart += (60 * 60 * 24 * 7 * $this->recur["everyn"]);
1688 1681
 						}
1689
-						// Loop through the whole following week to the first occurrence of the week, add each day that is specified
1690
-						for ($wday = 0; $wday < 7; ++$wday) {
1691
-							$daynow = $now + $wday * 60 * 60 * 24;
1692
-							// checks weather the next coming day in recurring pattern is less than or equal to end day of the recurring item
1693
-							if ($daynow > $dayend) {
1694
-								continue;
1695
-							}
1696
-							$nowtime = $this->gmtime($daynow); // Get the weekday of the current day
1697
-							if (($this->recur["weekdays"] & (1 << $nowtime["tm_wday"]))) { // Selected ?
1698
-								$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1699
-							}
1700
-						}
1701
-					}
1702
-					break;
1703 1682
 
1704
-				case 12:
1705
-					// Monthly
1706
-					if ($this->recur["everyn"] <= 0) {
1707
-						$this->recur["everyn"] = 1;
1708
-					}
1683
+						for ($now = $daystart; $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += (60 * 60 * 24 * 7 * $this->recur["everyn"])) {
1684
+							if ($this->recur['regen']) {
1685
+								$this->processOccurrenceItem($items, $start, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1709 1686
 
1710
-					// Loop through all months from start to end of occurrence, starting at beginning of first month
1711
-					for ($now = $this->monthStartOf($daystart); $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += $this->daysInMonth($now, $this->recur["everyn"]) * 24 * 60 * 60) {
1712
-						if (isset($this->recur["monthday"]) && ($this->recur['monthday'] != "undefined") && !$this->recur['regen']) { // Day M of every N months
1713
-							$difference = 1;
1714
-							if ($this->daysInMonth($now, $this->recur["everyn"]) < $this->recur["monthday"]) {
1715
-								$difference = $this->recur["monthday"] - $this->daysInMonth($now, $this->recur["everyn"]) + 1;
1687
+								break;
1716 1688
 							}
1717
-
1718
-							$daynow = $now + (($this->recur["monthday"] - $difference) * 24 * 60 * 60);
1719
-							// checks weather the next coming day in recurrence pattern is less than or equal to end day of the recurring item
1720
-							if ($daynow <= $dayend) {
1721
-								$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1689
+							// Loop through the whole following week to the first occurrence of the week, add each day that is specified
1690
+							for ($wday = 0; $wday < 7; ++$wday) {
1691
+								$daynow = $now + $wday * 60 * 60 * 24;
1692
+								// checks weather the next coming day in recurring pattern is less than or equal to end day of the recurring item
1693
+								if ($daynow > $dayend) {
1694
+									continue;
1695
+								}
1696
+								$nowtime = $this->gmtime($daynow); // Get the weekday of the current day
1697
+								if (($this->recur["weekdays"] & (1 << $nowtime["tm_wday"]))) { // Selected ?
1698
+									$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1699
+								}
1722 1700
 							}
1723 1701
 						}
1724
-						elseif (isset($this->recur["nday"], $this->recur["weekdays"])) { // Nth [weekday] of every N months
1725
-							// Sanitize input
1726
-							if ($this->recur["weekdays"] == 0) {
1727
-								$this->recur["weekdays"] = 1;
1728
-							}
1702
+						break;
1729 1703
 
1730
-							// If nday is not set to the last day in the month
1731
-							if ($this->recur["nday"] < 5) {
1732
-								// keep the track of no. of time correct selection pattern(like 2nd weekday, 4th fiday, etc.)is matched
1733
-								$ndaycounter = 0;
1734
-								// Find matching weekday in this month
1735
-								for ($day = 0; $day < $this->daysInMonth($now, 1); ++$day) {
1736
-									$daynow = $now + $day * 60 * 60 * 24;
1737
-									$nowtime = $this->gmtime($daynow); // Get the weekday of the current day
1704
+					case 12:
1705
+						// Monthly
1706
+						if ($this->recur["everyn"] <= 0) {
1707
+							$this->recur["everyn"] = 1;
1708
+						}
1738 1709
 
1739
-									if ($this->recur["weekdays"] & (1 << $nowtime["tm_wday"])) { // Selected ?
1740
-										++$ndaycounter;
1741
-									}
1742
-									// check the selected pattern is same as asked Nth weekday,If so set the firstday
1743
-									if ($this->recur["nday"] == $ndaycounter) {
1744
-										$firstday = $day;
1710
+						// Loop through all months from start to end of occurrence, starting at beginning of first month
1711
+						for ($now = $this->monthStartOf($daystart); $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += $this->daysInMonth($now, $this->recur["everyn"]) * 24 * 60 * 60) {
1712
+							if (isset($this->recur["monthday"]) && ($this->recur['monthday'] != "undefined") && !$this->recur['regen']) { // Day M of every N months
1713
+								$difference = 1;
1714
+								if ($this->daysInMonth($now, $this->recur["everyn"]) < $this->recur["monthday"]) {
1715
+									$difference = $this->recur["monthday"] - $this->daysInMonth($now, $this->recur["everyn"]) + 1;
1716
+								}
1745 1717
 
1746
-										break;
1747
-									}
1718
+								$daynow = $now + (($this->recur["monthday"] - $difference) * 24 * 60 * 60);
1719
+								// checks weather the next coming day in recurrence pattern is less than or equal to end day of the recurring item
1720
+								if ($daynow <= $dayend) {
1721
+									$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1748 1722
 								}
1749
-								// $firstday is the day of the month on which the asked pattern of nth weekday matches
1750
-								$daynow = $now + $firstday * 60 * 60 * 24;
1751 1723
 							}
1752
-							else {
1753
-								// Find last day in the month ($now is the firstday of the month)
1754
-								$NumDaysInMonth = $this->daysInMonth($now, 1);
1755
-								$daynow = $now + (($NumDaysInMonth - 1) * 24 * 60 * 60);
1724
+							elseif (isset($this->recur["nday"], $this->recur["weekdays"])) { // Nth [weekday] of every N months
1725
+								// Sanitize input
1726
+								if ($this->recur["weekdays"] == 0) {
1727
+									$this->recur["weekdays"] = 1;
1728
+								}
1729
+
1730
+								// If nday is not set to the last day in the month
1731
+								if ($this->recur["nday"] < 5) {
1732
+									// keep the track of no. of time correct selection pattern(like 2nd weekday, 4th fiday, etc.)is matched
1733
+									$ndaycounter = 0;
1734
+									// Find matching weekday in this month
1735
+									for ($day = 0; $day < $this->daysInMonth($now, 1); ++$day) {
1736
+										$daynow = $now + $day * 60 * 60 * 24;
1737
+										$nowtime = $this->gmtime($daynow); // Get the weekday of the current day
1738
+
1739
+										if ($this->recur["weekdays"] & (1 << $nowtime["tm_wday"])) { // Selected ?
1740
+											++$ndaycounter;
1741
+										}
1742
+										// check the selected pattern is same as asked Nth weekday,If so set the firstday
1743
+										if ($this->recur["nday"] == $ndaycounter) {
1744
+											$firstday = $day;
1745
+
1746
+											break;
1747
+										}
1748
+									}
1749
+									// $firstday is the day of the month on which the asked pattern of nth weekday matches
1750
+									$daynow = $now + $firstday * 60 * 60 * 24;
1751
+								}
1752
+								else {
1753
+									// Find last day in the month ($now is the firstday of the month)
1754
+									$NumDaysInMonth = $this->daysInMonth($now, 1);
1755
+									$daynow = $now + (($NumDaysInMonth - 1) * 24 * 60 * 60);
1756 1756
 
1757
-								$nowtime = $this->gmtime($daynow);
1758
-								while (($this->recur["weekdays"] & (1 << $nowtime["tm_wday"])) == 0) {
1759
-									$daynow -= 86400;
1760 1757
 									$nowtime = $this->gmtime($daynow);
1758
+									while (($this->recur["weekdays"] & (1 << $nowtime["tm_wday"])) == 0) {
1759
+										$daynow -= 86400;
1760
+										$nowtime = $this->gmtime($daynow);
1761
+									}
1761 1762
 								}
1762
-							}
1763 1763
 
1764
-							/*
1764
+								/*
1765 1765
 							 * checks weather the next coming day in recurrence pattern is less than or equal to end day of the			* recurring item.Also check weather the coming day in recurrence pattern is greater than or equal to start * of recurring pattern, so that appointment that fall under the recurrence range are only displayed.
1766 1766
 							 */
1767
-							if ($daynow <= $dayend && $daynow >= $daystart) {
1768
-								$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1767
+								if ($daynow <= $dayend && $daynow >= $daystart) {
1768
+									$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1769
+								}
1769 1770
 							}
1770
-						}
1771
-						elseif ($this->recur['regen']) {
1772
-							$next_month_start = $now + ($this->daysInMonth($now, 1) * 24 * 60 * 60);
1773
-							$now = $daystart + ($this->daysInMonth($next_month_start, $this->recur['everyn']) * 24 * 60 * 60);
1774
-							if ($now <= $dayend) {
1775
-								$this->processOccurrenceItem($items, $daystart, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1771
+							elseif ($this->recur['regen']) {
1772
+								$next_month_start = $now + ($this->daysInMonth($now, 1) * 24 * 60 * 60);
1773
+								$now = $daystart + ($this->daysInMonth($next_month_start, $this->recur['everyn']) * 24 * 60 * 60);
1774
+								if ($now <= $dayend) {
1775
+									$this->processOccurrenceItem($items, $daystart, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1776
+								}
1776 1777
 							}
1777 1778
 						}
1778
-					}
1779
-					break;
1780
-
1781
-				case 13:
1782
-					// Yearly
1783
-					if ($this->recur["everyn"] <= 0) {
1784
-						$this->recur["everyn"] = 12;
1785
-					}
1779
+						break;
1786 1780
 
1787
-					for ($now = $this->yearStartOf($daystart); $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += $this->daysInMonth($now, $this->recur["everyn"]) * 24 * 60 * 60) {
1788
-						if (isset($this->recur["monthday"]) && !$this->recur['regen']) { // same as monthly, but in a specific month
1789
-							// recur["month"] is in minutes since the beginning of the year
1790
-							$month = $this->monthOfYear($this->recur["month"]); // $month is now month of year [0..11]
1791
-							$monthday = $this->recur["monthday"]; // $monthday is day of the month [1..31]
1792
-							$monthstart = $now + $this->daysInMonth($now, $month) * 24 * 60 * 60; // $monthstart is the timestamp of the beginning of the month
1793
-							if ($monthday > $this->daysInMonth($monthstart, 1)) {
1794
-								$monthday = $this->daysInMonth($monthstart, 1);
1795
-							}	// Cap $monthday on month length (eg 28 feb instead of 29 feb)
1796
-							$daynow = $monthstart + ($monthday - 1) * 24 * 60 * 60;
1797
-							$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1781
+					case 13:
1782
+						// Yearly
1783
+						if ($this->recur["everyn"] <= 0) {
1784
+							$this->recur["everyn"] = 12;
1798 1785
 						}
1799
-						elseif (isset($this->recur["nday"], $this->recur["weekdays"])) { // Nth [weekday] in month X of every N years
1800
-							// Go the correct month
1801
-							$monthnow = $now + $this->daysInMonth($now, $this->monthOfYear($this->recur["month"])) * 24 * 60 * 60;
1802 1786
 
1803
-							// Find first matching weekday in this month
1804
-							for ($wday = 0; $wday < 7; ++$wday) {
1805
-								$daynow = $monthnow + $wday * 60 * 60 * 24;
1806
-								$nowtime = $this->gmtime($daynow); // Get the weekday of the current day
1787
+						for ($now = $this->yearStartOf($daystart); $now <= $dayend && ($limit == 0 || count($items) < $limit); $now += $this->daysInMonth($now, $this->recur["everyn"]) * 24 * 60 * 60) {
1788
+							if (isset($this->recur["monthday"]) && !$this->recur['regen']) { // same as monthly, but in a specific month
1789
+								// recur["month"] is in minutes since the beginning of the year
1790
+								$month = $this->monthOfYear($this->recur["month"]); // $month is now month of year [0..11]
1791
+								$monthday = $this->recur["monthday"]; // $monthday is day of the month [1..31]
1792
+								$monthstart = $now + $this->daysInMonth($now, $month) * 24 * 60 * 60; // $monthstart is the timestamp of the beginning of the month
1793
+								if ($monthday > $this->daysInMonth($monthstart, 1)) {
1794
+									$monthday = $this->daysInMonth($monthstart, 1);
1795
+								}	// Cap $monthday on month length (eg 28 feb instead of 29 feb)
1796
+								$daynow = $monthstart + ($monthday - 1) * 24 * 60 * 60;
1797
+								$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1798
+							}
1799
+							elseif (isset($this->recur["nday"], $this->recur["weekdays"])) { // Nth [weekday] in month X of every N years
1800
+								// Go the correct month
1801
+								$monthnow = $now + $this->daysInMonth($now, $this->monthOfYear($this->recur["month"])) * 24 * 60 * 60;
1807 1802
 
1808
-								if ($this->recur["weekdays"] & (1 << $nowtime["tm_wday"])) { // Selected ?
1809
-									$firstday = $wday;
1803
+								// Find first matching weekday in this month
1804
+								for ($wday = 0; $wday < 7; ++$wday) {
1805
+									$daynow = $monthnow + $wday * 60 * 60 * 24;
1806
+									$nowtime = $this->gmtime($daynow); // Get the weekday of the current day
1810 1807
 
1811
-									break;
1808
+									if ($this->recur["weekdays"] & (1 << $nowtime["tm_wday"])) { // Selected ?
1809
+										$firstday = $wday;
1810
+
1811
+										break;
1812
+									}
1812 1813
 								}
1813
-							}
1814 1814
 
1815
-							// Same as above (monthly)
1816
-							$daynow = $monthnow + ($firstday + ($this->recur["nday"] - 1) * 7) * 60 * 60 * 24;
1817
-							while ($this->monthStartOf($daynow) != $this->monthStartOf($monthnow)) {
1818
-								$daynow -= 7 * 60 * 60 * 24;
1819
-							}
1815
+								// Same as above (monthly)
1816
+								$daynow = $monthnow + ($firstday + ($this->recur["nday"] - 1) * 7) * 60 * 60 * 24;
1817
+								while ($this->monthStartOf($daynow) != $this->monthStartOf($monthnow)) {
1818
+									$daynow -= 7 * 60 * 60 * 24;
1819
+								}
1820 1820
 
1821
-							$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1822
-						}
1823
-						elseif ($this->recur['regen']) {
1824
-							$year_starttime = $this->gmtime($now);
1825
-							$is_next_leapyear = $this->isLeapYear($year_starttime['tm_year'] + 1900 + 1);	// +1 next year
1826
-							$now = $daystart + ($is_next_leapyear ? 31622400 /* Leap year in seconds */ : 31536000 /* year in seconds */);
1827
-							if ($now <= $dayend) {
1828
-								$this->processOccurrenceItem($items, $daystart, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1821
+								$this->processOccurrenceItem($items, $start, $end, $daynow, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1822
+							}
1823
+							elseif ($this->recur['regen']) {
1824
+								$year_starttime = $this->gmtime($now);
1825
+								$is_next_leapyear = $this->isLeapYear($year_starttime['tm_year'] + 1900 + 1);	// +1 next year
1826
+								$now = $daystart + ($is_next_leapyear ? 31622400 /* Leap year in seconds */ : 31536000 /* year in seconds */);
1827
+								if ($now <= $dayend) {
1828
+									$this->processOccurrenceItem($items, $daystart, $end, $now, $this->recur["startocc"], $this->recur["endocc"], $this->tz, $remindersonly);
1829
+								}
1829 1830
 							}
1830 1831
 						}
1831
-					}
1832 1832
 				}
1833 1833
 				// to get all exception items
1834 1834
 				if (!empty($this->recur['changed_occurrences'])) {
Please login to merge, or discard this patch.