Test Setup Failed
Branch master (463395)
by Mike
02:40
created
server.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -21,7 +21,7 @@  discard block
 block discarded – undo
21 21
 
22 22
 // don't log any Sabre asset requests (images etc)
23 23
 if (isset($_REQUEST['sabreAction']) && $_REQUEST['sabreAction'] == 'asset') {
24
-	$logger->resetConfiguration();
24
+    $logger->resetConfiguration();
25 25
 }
26 26
 
27 27
 // log the start data
@@ -39,9 +39,9 @@  discard block
 block discarded – undo
39 39
 
40 40
 // Setting up the directory tree
41 41
 $nodes = [
42
-	new \Sabre\DAVACL\PrincipalCollection($principalBackend),
43
-	new \Sabre\CardDAV\AddressBookRoot($principalBackend, $gCarddavBackend),
44
-	new \Sabre\CalDAV\CalendarRoot($principalBackend, $gCaldavBackend),
42
+    new \Sabre\DAVACL\PrincipalCollection($principalBackend),
43
+    new \Sabre\CardDAV\AddressBookRoot($principalBackend, $gCarddavBackend),
44
+    new \Sabre\CalDAV\CalendarRoot($principalBackend, $gCaldavBackend),
45 45
 ];
46 46
 
47 47
 // initialize the server
@@ -76,11 +76,11 @@  discard block
 block discarded – undo
76 76
 $server->addPlugin($caldavPlugin);
77 77
 
78 78
 if (strlen(SYNC_DB) > 0) {
79
-	$server->addPlugin(new \Sabre\DAV\Sync\Plugin());
79
+    $server->addPlugin(new \Sabre\DAV\Sync\Plugin());
80 80
 }
81 81
 
82 82
 if (DEVELOPER_MODE) {
83
-	$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false));
83
+    $server->addPlugin(new \Sabre\DAV\Browser\Plugin(false));
84 84
 }
85 85
 
86 86
 $server->exec();
@@ -89,10 +89,10 @@  discard block
 block discarded – undo
89 89
 $logger->LogOutgoing($server->httpResponse);
90 90
 
91 91
 $logger->debug(
92
-	"httpcode='%s' memory='%s/%s' time='%ss'",
93
-	http_response_code(),
94
-	$logger->FormatBytes(memory_get_peak_usage(false)),
95
-	$logger->FormatBytes(memory_get_peak_usage(true)),
96
-	number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 2)
92
+    "httpcode='%s' memory='%s/%s' time='%ss'",
93
+    http_response_code(),
94
+    $logger->FormatBytes(memory_get_peak_usage(false)),
95
+    $logger->FormatBytes(memory_get_peak_usage(true)),
96
+    number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 2)
97 97
 );
98 98
 $logger->debug('------------------ End');
Please login to merge, or discard this patch.
mapi/class.baseexception.php 1 patch
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -18,121 +18,121 @@
 block discarded – undo
18 18
  * getTraceAsString() - formatted string of trace
19 19
  */
20 20
 class BaseException extends Exception {
21
-	/**
22
-	 * Base name of the file, so we don't have to use static path of the file.
23
-	 */
24
-	private $baseFile;
25
-
26
-	/**
27
-	 * Flag to check if exception is already handled or not.
28
-	 */
29
-	public $isHandled = false;
30
-
31
-	/**
32
-	 * The exception message to show at client side.
33
-	 */
34
-	public $displayMessage;
35
-
36
-	/**
37
-	 * @param string    $errorMessage
38
-	 * @param int       $code
39
-	 * @param Exception $previous
40
-	 * @param string    $displayMessage
41
-	 */
42
-	public function __construct($errorMessage, $code = 0, Exception $previous = null, $displayMessage = null) {
43
-		// assign display message
44
-		$this->displayMessage = $displayMessage;
45
-
46
-		parent::__construct($errorMessage, (int) $code, $previous);
47
-	}
48
-
49
-	/**
50
-	 * @return string returns file name and line number combined where exception occurred
51
-	 */
52
-	public function getFileLine() {
53
-		return $this->getBaseFile() . ':' . $this->getLine();
54
-	}
55
-
56
-	/**
57
-	 * @return string returns message that should be sent to client to display
58
-	 */
59
-	public function getDisplayMessage() {
60
-		if (!is_null($this->displayMessage)) {
61
-			return $this->displayMessage;
62
-		}
63
-
64
-		return $this->getMessage();
65
-	}
66
-
67
-	/**
68
-	 * Function sets display message of an exception that will be sent to the client side
69
-	 * to show it to user.
70
-	 *
71
-	 * @param string $message display message
72
-	 */
73
-	public function setDisplayMessage($message) {
74
-		$this->displayMessage = $message;
75
-	}
76
-
77
-	/**
78
-	 * Function sets a flag in exception class to indicate that exception is already handled
79
-	 * so if it is caught again in the top level of function stack then we have to silently
80
-	 * ignore it.
81
-	 */
82
-	public function setHandled() {
83
-		$this->isHandled = true;
84
-	}
85
-
86
-	/**
87
-	 * @return string returns base path of the file where exception occurred
88
-	 */
89
-	public function getBaseFile() {
90
-		if (is_null($this->baseFile)) {
91
-			$this->baseFile = basename(parent::getFile());
92
-		}
93
-
94
-		return $this->baseFile;
95
-	}
96
-
97
-	/**
98
-	 * Function will check for PHP version if it is greater than 5.3 then we can use its default implementation
99
-	 * otherwise we have to use our own implementation of chanining functionality.
100
-	 *
101
-	 * @return Exception returns previous exception
102
-	 */
103
-	public function _getPrevious() {
104
-		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
105
-			return $this->_previous;
106
-		}
107
-
108
-		return parent::getPrevious();
109
-	}
110
-
111
-	/**
112
-	 * String representation of the exception, also handles previous exception.
113
-	 *
114
-	 * @return string
115
-	 */
116
-	public function __toString() {
117
-		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
118
-			if (($e = $this->getPrevious()) !== null) {
119
-				return $e->__toString() .
120
-						"\n\nNext " .
121
-						parent::__toString();
122
-			}
123
-		}
124
-
125
-		return parent::__toString();
126
-	}
127
-
128
-	/**
129
-	 * Name of the class of exception.
130
-	 *
131
-	 * @return string
132
-	 */
133
-	public function getName() {
134
-		return get_class($this);
135
-	}
136
-
137
-	// @TODO getTrace and getTraceAsString
21
+    /**
22
+     * Base name of the file, so we don't have to use static path of the file.
23
+     */
24
+    private $baseFile;
25
+
26
+    /**
27
+     * Flag to check if exception is already handled or not.
28
+     */
29
+    public $isHandled = false;
30
+
31
+    /**
32
+     * The exception message to show at client side.
33
+     */
34
+    public $displayMessage;
35
+
36
+    /**
37
+     * @param string    $errorMessage
38
+     * @param int       $code
39
+     * @param Exception $previous
40
+     * @param string    $displayMessage
41
+     */
42
+    public function __construct($errorMessage, $code = 0, Exception $previous = null, $displayMessage = null) {
43
+        // assign display message
44
+        $this->displayMessage = $displayMessage;
45
+
46
+        parent::__construct($errorMessage, (int) $code, $previous);
47
+    }
48
+
49
+    /**
50
+     * @return string returns file name and line number combined where exception occurred
51
+     */
52
+    public function getFileLine() {
53
+        return $this->getBaseFile() . ':' . $this->getLine();
54
+    }
55
+
56
+    /**
57
+     * @return string returns message that should be sent to client to display
58
+     */
59
+    public function getDisplayMessage() {
60
+        if (!is_null($this->displayMessage)) {
61
+            return $this->displayMessage;
62
+        }
63
+
64
+        return $this->getMessage();
65
+    }
66
+
67
+    /**
68
+     * Function sets display message of an exception that will be sent to the client side
69
+     * to show it to user.
70
+     *
71
+     * @param string $message display message
72
+     */
73
+    public function setDisplayMessage($message) {
74
+        $this->displayMessage = $message;
75
+    }
76
+
77
+    /**
78
+     * Function sets a flag in exception class to indicate that exception is already handled
79
+     * so if it is caught again in the top level of function stack then we have to silently
80
+     * ignore it.
81
+     */
82
+    public function setHandled() {
83
+        $this->isHandled = true;
84
+    }
85
+
86
+    /**
87
+     * @return string returns base path of the file where exception occurred
88
+     */
89
+    public function getBaseFile() {
90
+        if (is_null($this->baseFile)) {
91
+            $this->baseFile = basename(parent::getFile());
92
+        }
93
+
94
+        return $this->baseFile;
95
+    }
96
+
97
+    /**
98
+     * Function will check for PHP version if it is greater than 5.3 then we can use its default implementation
99
+     * otherwise we have to use our own implementation of chanining functionality.
100
+     *
101
+     * @return Exception returns previous exception
102
+     */
103
+    public function _getPrevious() {
104
+        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
105
+            return $this->_previous;
106
+        }
107
+
108
+        return parent::getPrevious();
109
+    }
110
+
111
+    /**
112
+     * String representation of the exception, also handles previous exception.
113
+     *
114
+     * @return string
115
+     */
116
+    public function __toString() {
117
+        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
118
+            if (($e = $this->getPrevious()) !== null) {
119
+                return $e->__toString() .
120
+                        "\n\nNext " .
121
+                        parent::__toString();
122
+            }
123
+        }
124
+
125
+        return parent::__toString();
126
+    }
127
+
128
+    /**
129
+     * Name of the class of exception.
130
+     *
131
+     * @return string
132
+     */
133
+    public function getName() {
134
+        return get_class($this);
135
+    }
136
+
137
+    // @TODO getTrace and getTraceAsString
138 138
 }
Please login to merge, or discard this patch.
mapi/class.freebusypublish.php 2 patches
Indentation   +238 added lines, -238 removed lines patch added patch discarded remove patch
@@ -6,271 +6,271 @@
 block discarded – undo
6 6
  */
7 7
 
8 8
 class FreeBusyPublish {
9
-	public $session;
10
-	public $calendar;
11
-	public $entryid;
12
-	public $starttime;
13
-	public $length;
14
-	public $store;
15
-	public $proptags;
9
+    public $session;
10
+    public $calendar;
11
+    public $entryid;
12
+    public $starttime;
13
+    public $length;
14
+    public $store;
15
+    public $proptags;
16 16
 
17
-	/**
18
-	 * @param mapi_session $session  MAPI Session
19
-	 * @param mapi_folder  $calendar Calendar to publish
20
-	 * @param string       $entryid  AddressBook Entry ID for the user we're publishing for
21
-	 * @param mixed        $store
22
-	 */
23
-	public function __construct($session, $store, $calendar, $entryid) {
24
-		$properties["entryid"] = PR_ENTRYID;
25
-		$properties["parent_entryid"] = PR_PARENT_ENTRYID;
26
-		$properties["message_class"] = PR_MESSAGE_CLASS;
27
-		$properties["icon_index"] = PR_ICON_INDEX;
28
-		$properties["subject"] = PR_SUBJECT;
29
-		$properties["display_to"] = PR_DISPLAY_TO;
30
-		$properties["importance"] = PR_IMPORTANCE;
31
-		$properties["sensitivity"] = PR_SENSITIVITY;
32
-		$properties["startdate"] = "PT_SYSTIME:PSETID_Appointment:0x820d";
33
-		$properties["duedate"] = "PT_SYSTIME:PSETID_Appointment:0x820e";
34
-		$properties["recurring"] = "PT_BOOLEAN:PSETID_Appointment:0x8223";
35
-		$properties["recurring_data"] = "PT_BINARY:PSETID_Appointment:0x8216";
36
-		$properties["busystatus"] = "PT_LONG:PSETID_Appointment:0x8205";
37
-		$properties["label"] = "PT_LONG:PSETID_Appointment:0x8214";
38
-		$properties["alldayevent"] = "PT_BOOLEAN:PSETID_Appointment:0x8215";
39
-		$properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
40
-		$properties["meeting"] = "PT_LONG:PSETID_Appointment:0x8217";
41
-		$properties["startdate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8235";
42
-		$properties["enddate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8236";
43
-		$properties["location"] = "PT_STRING8:PSETID_Appointment:0x8208";
44
-		$properties["duration"] = "PT_LONG:PSETID_Appointment:0x8213";
45
-		$properties["responsestatus"] = "PT_LONG:PSETID_Appointment:0x8218";
46
-		$properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
47
-		$properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
48
-		$properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
49
-		$properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
50
-		$properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
51
-		$properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
52
-		$properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
53
-		$properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
54
-		$properties["basedate"] = "PT_SYSTIME:PSETID_Appointment:0x8228";
55
-		$properties["timezone_data"] = "PT_BINARY:PSETID_Appointment:0x8233";
56
-		$this->proptags = getPropIdsFromStrings($store, $properties);
17
+    /**
18
+     * @param mapi_session $session  MAPI Session
19
+     * @param mapi_folder  $calendar Calendar to publish
20
+     * @param string       $entryid  AddressBook Entry ID for the user we're publishing for
21
+     * @param mixed        $store
22
+     */
23
+    public function __construct($session, $store, $calendar, $entryid) {
24
+        $properties["entryid"] = PR_ENTRYID;
25
+        $properties["parent_entryid"] = PR_PARENT_ENTRYID;
26
+        $properties["message_class"] = PR_MESSAGE_CLASS;
27
+        $properties["icon_index"] = PR_ICON_INDEX;
28
+        $properties["subject"] = PR_SUBJECT;
29
+        $properties["display_to"] = PR_DISPLAY_TO;
30
+        $properties["importance"] = PR_IMPORTANCE;
31
+        $properties["sensitivity"] = PR_SENSITIVITY;
32
+        $properties["startdate"] = "PT_SYSTIME:PSETID_Appointment:0x820d";
33
+        $properties["duedate"] = "PT_SYSTIME:PSETID_Appointment:0x820e";
34
+        $properties["recurring"] = "PT_BOOLEAN:PSETID_Appointment:0x8223";
35
+        $properties["recurring_data"] = "PT_BINARY:PSETID_Appointment:0x8216";
36
+        $properties["busystatus"] = "PT_LONG:PSETID_Appointment:0x8205";
37
+        $properties["label"] = "PT_LONG:PSETID_Appointment:0x8214";
38
+        $properties["alldayevent"] = "PT_BOOLEAN:PSETID_Appointment:0x8215";
39
+        $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
40
+        $properties["meeting"] = "PT_LONG:PSETID_Appointment:0x8217";
41
+        $properties["startdate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8235";
42
+        $properties["enddate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8236";
43
+        $properties["location"] = "PT_STRING8:PSETID_Appointment:0x8208";
44
+        $properties["duration"] = "PT_LONG:PSETID_Appointment:0x8213";
45
+        $properties["responsestatus"] = "PT_LONG:PSETID_Appointment:0x8218";
46
+        $properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
47
+        $properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
48
+        $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
49
+        $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
50
+        $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
51
+        $properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
52
+        $properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
53
+        $properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
54
+        $properties["basedate"] = "PT_SYSTIME:PSETID_Appointment:0x8228";
55
+        $properties["timezone_data"] = "PT_BINARY:PSETID_Appointment:0x8233";
56
+        $this->proptags = getPropIdsFromStrings($store, $properties);
57 57
 
58
-		$this->session = $session;
59
-		$this->calendar = $calendar;
60
-		$this->entryid = $entryid;
61
-		$this->store = $store;
62
-	}
58
+        $this->session = $session;
59
+        $this->calendar = $calendar;
60
+        $this->entryid = $entryid;
61
+        $this->store = $store;
62
+    }
63 63
 
64
-	/**
65
-	 * Publishes the information.
66
-	 *
67
-	 * @paam timestamp $starttime Time from which to publish data  (usually now)
68
-	 * @paam integer $length Amount of seconds from $starttime we should publish
69
-	 *
70
-	 * @param mixed $starttime
71
-	 * @param mixed $length
72
-	 */
73
-	public function publishFB($starttime, $length) {
74
-		$start = $starttime;
75
-		$end = $starttime + $length;
64
+    /**
65
+     * Publishes the information.
66
+     *
67
+     * @paam timestamp $starttime Time from which to publish data  (usually now)
68
+     * @paam integer $length Amount of seconds from $starttime we should publish
69
+     *
70
+     * @param mixed $starttime
71
+     * @param mixed $length
72
+     */
73
+    public function publishFB($starttime, $length) {
74
+        $start = $starttime;
75
+        $end = $starttime + $length;
76 76
 
77
-		// Get all the items in the calendar that we need
77
+        // Get all the items in the calendar that we need
78 78
 
79
-		$calendaritems = [];
79
+        $calendaritems = [];
80 80
 
81
-		$restrict = [RES_OR, [
82
-			// (item[start] >= start && item[start] <= end)
83
-			[RES_AND, [
84
-				[RES_PROPERTY, [RELOP => RELOP_GE, ULPROPTAG => $this->proptags["startdate"], VALUE => $start]],
85
-				[RES_PROPERTY, [RELOP => RELOP_LE, ULPROPTAG => $this->proptags["startdate"], VALUE => $end]],
86
-			]],
87
-			// OR
88
-			// (item[end] >= start && item[end] <= end)
89
-			[RES_AND, [
90
-				[RES_PROPERTY, [RELOP => RELOP_GE, ULPROPTAG => $this->proptags["duedate"], VALUE => $start]],
91
-				[RES_PROPERTY, [RELOP => RELOP_LE, ULPROPTAG => $this->proptags["duedate"], VALUE => $end]],
92
-			]],
93
-			// OR
94
-			// (item[start] < start && item[end] > end)
95
-			[RES_AND, [
96
-				[RES_PROPERTY, [RELOP => RELOP_LT, ULPROPTAG => $this->proptags["startdate"], VALUE => $start]],
97
-				[RES_PROPERTY, [RELOP => RELOP_GT, ULPROPTAG => $this->proptags["duedate"], VALUE => $end]],
98
-			]],
99
-			// OR
100
-			[RES_OR, [
101
-				// OR
102
-				// (EXIST(ecurrence_enddate_property) && item[isRecurring] == true && item[end] >= start)
103
-				[RES_AND, [
104
-					[RES_EXIST, [ULPROPTAG => $this->proptags["enddate_recurring"]]],
105
-					[RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $this->proptags["recurring"], VALUE => true]],
106
-					[RES_PROPERTY, [RELOP => RELOP_GE, ULPROPTAG => $this->proptags["enddate_recurring"], VALUE => $start]],
107
-				]],
108
-				// OR
109
-				// (!EXIST(ecurrence_enddate_property) && item[isRecurring] == true && item[start] <= end)
110
-				[RES_AND, [
111
-					[RES_NOT, [
112
-						[RES_EXIST, [ULPROPTAG => $this->proptags["enddate_recurring"]]],
113
-					]],
114
-					[RES_PROPERTY, [RELOP => RELOP_LE, ULPROPTAG => $this->proptags["startdate"], VALUE => $end]],
115
-					[RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $this->proptags["recurring"], VALUE => true]],
116
-				]],
117
-			]], // EXISTS OR
118
-		]]; // global OR
81
+        $restrict = [RES_OR, [
82
+            // (item[start] >= start && item[start] <= end)
83
+            [RES_AND, [
84
+                [RES_PROPERTY, [RELOP => RELOP_GE, ULPROPTAG => $this->proptags["startdate"], VALUE => $start]],
85
+                [RES_PROPERTY, [RELOP => RELOP_LE, ULPROPTAG => $this->proptags["startdate"], VALUE => $end]],
86
+            ]],
87
+            // OR
88
+            // (item[end] >= start && item[end] <= end)
89
+            [RES_AND, [
90
+                [RES_PROPERTY, [RELOP => RELOP_GE, ULPROPTAG => $this->proptags["duedate"], VALUE => $start]],
91
+                [RES_PROPERTY, [RELOP => RELOP_LE, ULPROPTAG => $this->proptags["duedate"], VALUE => $end]],
92
+            ]],
93
+            // OR
94
+            // (item[start] < start && item[end] > end)
95
+            [RES_AND, [
96
+                [RES_PROPERTY, [RELOP => RELOP_LT, ULPROPTAG => $this->proptags["startdate"], VALUE => $start]],
97
+                [RES_PROPERTY, [RELOP => RELOP_GT, ULPROPTAG => $this->proptags["duedate"], VALUE => $end]],
98
+            ]],
99
+            // OR
100
+            [RES_OR, [
101
+                // OR
102
+                // (EXIST(ecurrence_enddate_property) && item[isRecurring] == true && item[end] >= start)
103
+                [RES_AND, [
104
+                    [RES_EXIST, [ULPROPTAG => $this->proptags["enddate_recurring"]]],
105
+                    [RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $this->proptags["recurring"], VALUE => true]],
106
+                    [RES_PROPERTY, [RELOP => RELOP_GE, ULPROPTAG => $this->proptags["enddate_recurring"], VALUE => $start]],
107
+                ]],
108
+                // OR
109
+                // (!EXIST(ecurrence_enddate_property) && item[isRecurring] == true && item[start] <= end)
110
+                [RES_AND, [
111
+                    [RES_NOT, [
112
+                        [RES_EXIST, [ULPROPTAG => $this->proptags["enddate_recurring"]]],
113
+                    ]],
114
+                    [RES_PROPERTY, [RELOP => RELOP_LE, ULPROPTAG => $this->proptags["startdate"], VALUE => $end]],
115
+                    [RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $this->proptags["recurring"], VALUE => true]],
116
+                ]],
117
+            ]], // EXISTS OR
118
+        ]]; // global OR
119 119
 
120
-		$contents = mapi_folder_getcontentstable($this->calendar);
121
-		mapi_table_restrict($contents, $restrict);
120
+        $contents = mapi_folder_getcontentstable($this->calendar);
121
+        mapi_table_restrict($contents, $restrict);
122 122
 
123
-		while (1) {
124
-			$rows = mapi_table_queryrows($contents, array_values($this->proptags), 0, 50);
123
+        while (1) {
124
+            $rows = mapi_table_queryrows($contents, array_values($this->proptags), 0, 50);
125 125
 
126
-			if (!is_array($rows)) {
127
-				break;
128
-			}
126
+            if (!is_array($rows)) {
127
+                break;
128
+            }
129 129
 
130
-			if (empty($rows)) {
131
-				break;
132
-			}
130
+            if (empty($rows)) {
131
+                break;
132
+            }
133 133
 
134
-			foreach ($rows as $row) {
135
-				$occurrences = [];
136
-				if (isset($row[$this->proptags['recurring']]) && $row[$this->proptags['recurring']]) {
137
-					$recur = new Recurrence($this->store, $row);
134
+            foreach ($rows as $row) {
135
+                $occurrences = [];
136
+                if (isset($row[$this->proptags['recurring']]) && $row[$this->proptags['recurring']]) {
137
+                    $recur = new Recurrence($this->store, $row);
138 138
 
139
-					$occurrences = $recur->getItems($starttime, $starttime + $length);
140
-				}
141
-				else {
142
-					$occurrences[] = $row;
143
-				}
139
+                    $occurrences = $recur->getItems($starttime, $starttime + $length);
140
+                }
141
+                else {
142
+                    $occurrences[] = $row;
143
+                }
144 144
 
145
-				$calendaritems = array_merge($calendaritems, $occurrences);
146
-			}
147
-		}
145
+                $calendaritems = array_merge($calendaritems, $occurrences);
146
+            }
147
+        }
148 148
 
149
-		// $calendaritems now contains all the calendar items in the specified time
150
-		// frame. We now need to merge these into a flat array of begin/end/status
151
-		// objects. This also filters out all the 'free' items (status 0)
149
+        // $calendaritems now contains all the calendar items in the specified time
150
+        // frame. We now need to merge these into a flat array of begin/end/status
151
+        // objects. This also filters out all the 'free' items (status 0)
152 152
 
153
-		$freebusy = $this->mergeItemsFB($calendaritems);
153
+        $freebusy = $this->mergeItemsFB($calendaritems);
154 154
 
155
-		// $freebusy now contains the start, end and status of all items, merged.
155
+        // $freebusy now contains the start, end and status of all items, merged.
156 156
 
157
-		// Get the FB interface
158
-		try {
159
-			$fbsupport = mapi_freebusysupport_open($this->session, $this->store);
160
-		}
161
-		catch (MAPIException $e) {
162
-			if ($e->getCode() == MAPI_E_NOT_FOUND) {
163
-				$e->setHandled();
164
-				if (function_exists("dump")) {
165
-					dump("Error in opening freebusysupport object.");
166
-				}
167
-			}
168
-		}
157
+        // Get the FB interface
158
+        try {
159
+            $fbsupport = mapi_freebusysupport_open($this->session, $this->store);
160
+        }
161
+        catch (MAPIException $e) {
162
+            if ($e->getCode() == MAPI_E_NOT_FOUND) {
163
+                $e->setHandled();
164
+                if (function_exists("dump")) {
165
+                    dump("Error in opening freebusysupport object.");
166
+                }
167
+            }
168
+        }
169 169
 
170
-		// Open updater for this user
171
-		if (!isset($fbsupport) || !$fbsupport) {
172
-			return;
173
-		}
174
-		$updaters = mapi_freebusysupport_loadupdate($fbsupport, [$this->entryid]);
175
-		$updater = $updaters[0];
170
+        // Open updater for this user
171
+        if (!isset($fbsupport) || !$fbsupport) {
172
+            return;
173
+        }
174
+        $updaters = mapi_freebusysupport_loadupdate($fbsupport, [$this->entryid]);
175
+        $updater = $updaters[0];
176 176
 
177
-		// Send the data
178
-		mapi_freebusyupdate_reset($updater);
179
-		mapi_freebusyupdate_publish($updater, $freebusy);
180
-		mapi_freebusyupdate_savechanges($updater, $start - 24 * 60 * 60, $end);
177
+        // Send the data
178
+        mapi_freebusyupdate_reset($updater);
179
+        mapi_freebusyupdate_publish($updater, $freebusy);
180
+        mapi_freebusyupdate_savechanges($updater, $start - 24 * 60 * 60, $end);
181 181
 
182
-		// We're finished
183
-		mapi_freebusysupport_close($fbsupport);
184
-	}
182
+        // We're finished
183
+        mapi_freebusysupport_close($fbsupport);
184
+    }
185 185
 
186
-	/**
187
-	 * Sorts by timestamp, if equal, then end before start.
188
-	 *
189
-	 * @param mixed $a
190
-	 * @param mixed $b
191
-	 */
192
-	public function cmp($a, $b) {
193
-		if ($a["time"] != $b["time"]) {
194
-			return $a["time"] > $b["time"] ? 1 : -1;
195
-		}
196
-		if ($a["type"] < $b["type"]) {
197
-			return 1;
198
-		}
199
-		if ($a["type"] > $b["type"]) {
200
-			return -1;
201
-		}
186
+    /**
187
+     * Sorts by timestamp, if equal, then end before start.
188
+     *
189
+     * @param mixed $a
190
+     * @param mixed $b
191
+     */
192
+    public function cmp($a, $b) {
193
+        if ($a["time"] != $b["time"]) {
194
+            return $a["time"] > $b["time"] ? 1 : -1;
195
+        }
196
+        if ($a["type"] < $b["type"]) {
197
+            return 1;
198
+        }
199
+        if ($a["type"] > $b["type"]) {
200
+            return -1;
201
+        }
202 202
 
203
-		return 0;
204
-	}
203
+        return 0;
204
+    }
205 205
 
206
-	/**
207
-	 * Function mergeItems.
208
-	 *
209
-	 * @author Steve Hardy
210
-	 *
211
-	 * @param mixed $items
212
-	 */
213
-	public function mergeItemsFB($items) {
214
-		$merged = [];
215
-		$timestamps = [];
216
-		$csubj = [];
217
-		$cbusy = [];
218
-		$level = 0;
219
-		$laststart = null;
206
+    /**
207
+     * Function mergeItems.
208
+     *
209
+     * @author Steve Hardy
210
+     *
211
+     * @param mixed $items
212
+     */
213
+    public function mergeItemsFB($items) {
214
+        $merged = [];
215
+        $timestamps = [];
216
+        $csubj = [];
217
+        $cbusy = [];
218
+        $level = 0;
219
+        $laststart = null;
220 220
 
221
-		foreach ($items as $item) {
222
-			$ts["type"] = 0;
223
-			$ts["time"] = $item[$this->proptags["startdate"]];
224
-			$ts["subject"] = $item[PR_SUBJECT];
225
-			$ts["status"] = isset($item[$this->proptags["busystatus"]]) ? $item[$this->proptags["busystatus"]] : 0; // ZP-197
226
-			$timestamps[] = $ts;
221
+        foreach ($items as $item) {
222
+            $ts["type"] = 0;
223
+            $ts["time"] = $item[$this->proptags["startdate"]];
224
+            $ts["subject"] = $item[PR_SUBJECT];
225
+            $ts["status"] = isset($item[$this->proptags["busystatus"]]) ? $item[$this->proptags["busystatus"]] : 0; // ZP-197
226
+            $timestamps[] = $ts;
227 227
 
228
-			$ts["type"] = 1;
229
-			$ts["time"] = $item[$this->proptags["duedate"]];
230
-			$ts["subject"] = $item[PR_SUBJECT];
231
-			$ts["status"] = isset($item[$this->proptags["busystatus"]]) ? $item[$this->proptags["busystatus"]] : 0; // ZP-197
232
-			$timestamps[] = $ts;
233
-		}
228
+            $ts["type"] = 1;
229
+            $ts["time"] = $item[$this->proptags["duedate"]];
230
+            $ts["subject"] = $item[PR_SUBJECT];
231
+            $ts["status"] = isset($item[$this->proptags["busystatus"]]) ? $item[$this->proptags["busystatus"]] : 0; // ZP-197
232
+            $timestamps[] = $ts;
233
+        }
234 234
 
235
-		usort($timestamps, [$this, "cmp"]);
236
-		$laststart = 0;
235
+        usort($timestamps, [$this, "cmp"]);
236
+        $laststart = 0;
237 237
 
238
-		foreach ($timestamps as $ts) {
239
-			switch ($ts["type"]) {
240
-		case 0: // Start
241
-				if ($level != 0 && $laststart != $ts["time"]) {
242
-					$newitem["start"] = $laststart;
243
-					$newitem["end"] = $ts["time"];
244
-					$newitem["subject"] = join(",", $csubj);
245
-					$newitem["status"] = !empty($cbusy) ? max($cbusy) : 0;
246
-					if ($newitem["status"] > 0) {
247
-						$merged[] = $newitem;
248
-					}
249
-				}
250
-			++$level;
251
-			$csubj[] = $ts["subject"];
252
-			$cbusy[] = $ts["status"];
253
-			$laststart = $ts["time"];
254
-			break;
238
+        foreach ($timestamps as $ts) {
239
+            switch ($ts["type"]) {
240
+        case 0: // Start
241
+                if ($level != 0 && $laststart != $ts["time"]) {
242
+                    $newitem["start"] = $laststart;
243
+                    $newitem["end"] = $ts["time"];
244
+                    $newitem["subject"] = join(",", $csubj);
245
+                    $newitem["status"] = !empty($cbusy) ? max($cbusy) : 0;
246
+                    if ($newitem["status"] > 0) {
247
+                        $merged[] = $newitem;
248
+                    }
249
+                }
250
+            ++$level;
251
+            $csubj[] = $ts["subject"];
252
+            $cbusy[] = $ts["status"];
253
+            $laststart = $ts["time"];
254
+            break;
255 255
 
256
-		case 1: // End
257
-			if ($laststart != $ts["time"]) {
258
-				$newitem["start"] = $laststart;
259
-				$newitem["end"] = $ts["time"];
260
-				$newitem["subject"] = join(",", $csubj);
261
-				$newitem["status"] = !empty($cbusy) ? max($cbusy) : 0;
262
-				if ($newitem["status"] > 0) {
263
-					$merged[] = $newitem;
264
-				}
265
-			}
266
-			--$level;
267
-			array_splice($csubj, array_search($ts["subject"], $csubj, 1), 1);
268
-			array_splice($cbusy, array_search($ts["status"], $cbusy, 1), 1);
269
-			$laststart = $ts["time"];
270
-			break;
271
-			}
272
-		}
256
+        case 1: // End
257
+            if ($laststart != $ts["time"]) {
258
+                $newitem["start"] = $laststart;
259
+                $newitem["end"] = $ts["time"];
260
+                $newitem["subject"] = join(",", $csubj);
261
+                $newitem["status"] = !empty($cbusy) ? max($cbusy) : 0;
262
+                if ($newitem["status"] > 0) {
263
+                    $merged[] = $newitem;
264
+                }
265
+            }
266
+            --$level;
267
+            array_splice($csubj, array_search($ts["subject"], $csubj, 1), 1);
268
+            array_splice($cbusy, array_search($ts["status"], $cbusy, 1), 1);
269
+            $laststart = $ts["time"];
270
+            break;
271
+            }
272
+        }
273 273
 
274
-		return $merged;
275
-	}
274
+        return $merged;
275
+    }
276 276
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -4 removed lines patch added patch discarded remove patch
@@ -137,8 +137,7 @@  discard block
 block discarded – undo
137 137
 					$recur = new Recurrence($this->store, $row);
138 138
 
139 139
 					$occurrences = $recur->getItems($starttime, $starttime + $length);
140
-				}
141
-				else {
140
+				} else {
142 141
 					$occurrences[] = $row;
143 142
 				}
144 143
 
@@ -157,8 +156,7 @@  discard block
 block discarded – undo
157 156
 		// Get the FB interface
158 157
 		try {
159 158
 			$fbsupport = mapi_freebusysupport_open($this->session, $this->store);
160
-		}
161
-		catch (MAPIException $e) {
159
+		} catch (MAPIException $e) {
162 160
 			if ($e->getCode() == MAPI_E_NOT_FOUND) {
163 161
 				$e->setHandled();
164 162
 				if (function_exists("dump")) {
Please login to merge, or discard this patch.
mapi/class.taskrecurrence.php 2 patches
Indentation   +403 added lines, -403 removed lines patch added patch discarded remove patch
@@ -5,409 +5,409 @@
 block discarded – undo
5 5
  * SPDX-FileCopyrightText: Copyright 2020 grommunio GmbH
6 6
  */
7 7
 
8
-	class TaskRecurrence extends BaseRecurrence {
9
-		/**
10
-		 * Timezone info which is always false for task.
11
-		 */
12
-		public $tz = false;
13
-
14
-		public function __construct($store, $message) {
15
-			$this->store = $store;
16
-			$this->message = $message;
17
-
18
-			$properties = [];
19
-			$properties["entryid"] = PR_ENTRYID;
20
-			$properties["parent_entryid"] = PR_PARENT_ENTRYID;
21
-			$properties["icon_index"] = PR_ICON_INDEX;
22
-			$properties["message_class"] = PR_MESSAGE_CLASS;
23
-			$properties["message_flags"] = PR_MESSAGE_FLAGS;
24
-			$properties["subject"] = PR_SUBJECT;
25
-			$properties["importance"] = PR_IMPORTANCE;
26
-			$properties["sensitivity"] = PR_SENSITIVITY;
27
-			$properties["last_modification_time"] = PR_LAST_MODIFICATION_TIME;
28
-			$properties["status"] = "PT_LONG:PSETID_Task:0x8101";
29
-			$properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102";
30
-			$properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104";
31
-			$properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105";
32
-			$properties["reset_reminder"] = "PT_BOOLEAN:PSETID_Task:0x8107";
33
-			$properties["dead_occurrence"] = "PT_BOOLEAN:PSETID_Task:0x8109";
34
-			$properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f";
35
-			$properties["recurring_data"] = "PT_BINARY:PSETID_Task:0x8116";
36
-			$properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110";
37
-			$properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111";
38
-			$properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c";
39
-			$properties["task_f_creator"] = "PT_BOOLEAN:PSETID_Task:0x811e";
40
-			$properties["owner"] = "PT_STRING8:PSETID_Task:0x811f";
41
-			$properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126";
42
-
43
-			$properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
44
-			$properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
45
-			$properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
46
-
47
-			$properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
48
-			$properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
49
-			$properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
50
-			$properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
51
-
52
-			$properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
53
-			$properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
54
-			$properties["commonassign"] = "PT_LONG:PSETID_Common:0x8518";
55
-			$properties["flagdueby"] = "PT_SYSTIME:PSETID_Common:0x8560";
56
-			$properties["side_effects"] = "PT_LONG:PSETID_Common:0x8510";
57
-			$properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
58
-			$properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
59
-
60
-			$this->proptags = getPropIdsFromStrings($store, $properties);
61
-
62
-			parent::__construct($store, $message, $properties);
63
-		}
64
-
65
-		/**
66
-		 * Function which saves recurrence and also regenerates task if necessary.
67
-		 *
68
-		 *@param array $recur new recurrence properties
69
-		 *
70
-		 *@return array of properties of regenerated task else false
71
-		 */
72
-		public function setRecurrence(&$recur) {
73
-			$this->recur = $recur;
74
-			$this->action = &$recur;
75
-
76
-			if (!isset($this->recur["changed_occurences"])) {
77
-				$this->recur["changed_occurences"] = [];
78
-			}
79
-
80
-			if (!isset($this->recur["deleted_occurences"])) {
81
-				$this->recur["deleted_occurences"] = [];
82
-			}
83
-
84
-			if (!isset($this->recur['startocc'])) {
85
-				$this->recur['startocc'] = 0;
86
-			}
87
-			if (!isset($this->recur['endocc'])) {
88
-				$this->recur['endocc'] = 0;
89
-			}
90
-
91
-			// Save recurrence because we need proper startrecurrdate and endrecurrdate
92
-			$this->saveRecurrence();
93
-
94
-			// Update $this->recur with proper startrecurrdate and endrecurrdate updated after saving recurrence
95
-			$msgProps = mapi_getprops($this->message, [$this->proptags['recurring_data']]);
96
-			$recurring_data = $this->parseRecurrence($msgProps[$this->proptags['recurring_data']]);
97
-			foreach ($recurring_data as $key => $value) {
98
-				$this->recur[$key] = $value;
99
-			}
100
-
101
-			$this->setFirstOccurrence();
102
-
103
-			// Let's see if next occurrence has to be generated
104
-			return $this->moveToNextOccurrence();
105
-		}
106
-
107
-		/**
108
-		 * Sets task object to first occurrence if startdate/duedate of task object is different from first occurrence.
109
-		 */
110
-		public function setFirstOccurrence() {
111
-			// Check if it is already the first occurrence
112
-			if ($this->action['start'] == $this->recur["start"]) {
113
-				return;
114
-			}
115
-			$items = $this->getNextOccurrence();
116
-
117
-			$props = [];
118
-			$props[$this->proptags['startdate']] = $items[$this->proptags['startdate']];
119
-			$props[$this->proptags['commonstart']] = $items[$this->proptags['startdate']];
120
-
121
-			$props[$this->proptags['duedate']] = $items[$this->proptags['duedate']];
122
-			$props[$this->proptags['commonend']] = $items[$this->proptags['duedate']];
123
-
124
-			mapi_setprops($this->message, $props);
125
-		}
126
-
127
-		/**
128
-		 * Function which creates new task as current occurrence and moves the
129
-		 * existing task to next occurrence.
130
-		 *
131
-		 *@param array $recur $action from client
132
-		 *
133
-		 *@return bool if moving to next occurrence succeed then it returns
134
-		 *		properties of either newly created task or existing task ELSE
135
-		 *		false because that was last occurrence
136
-		 */
137
-		public function moveToNextOccurrence() {
138
-			$result = false;
139
-			/*
8
+    class TaskRecurrence extends BaseRecurrence {
9
+        /**
10
+         * Timezone info which is always false for task.
11
+         */
12
+        public $tz = false;
13
+
14
+        public function __construct($store, $message) {
15
+            $this->store = $store;
16
+            $this->message = $message;
17
+
18
+            $properties = [];
19
+            $properties["entryid"] = PR_ENTRYID;
20
+            $properties["parent_entryid"] = PR_PARENT_ENTRYID;
21
+            $properties["icon_index"] = PR_ICON_INDEX;
22
+            $properties["message_class"] = PR_MESSAGE_CLASS;
23
+            $properties["message_flags"] = PR_MESSAGE_FLAGS;
24
+            $properties["subject"] = PR_SUBJECT;
25
+            $properties["importance"] = PR_IMPORTANCE;
26
+            $properties["sensitivity"] = PR_SENSITIVITY;
27
+            $properties["last_modification_time"] = PR_LAST_MODIFICATION_TIME;
28
+            $properties["status"] = "PT_LONG:PSETID_Task:0x8101";
29
+            $properties["percent_complete"] = "PT_DOUBLE:PSETID_Task:0x8102";
30
+            $properties["startdate"] = "PT_SYSTIME:PSETID_Task:0x8104";
31
+            $properties["duedate"] = "PT_SYSTIME:PSETID_Task:0x8105";
32
+            $properties["reset_reminder"] = "PT_BOOLEAN:PSETID_Task:0x8107";
33
+            $properties["dead_occurrence"] = "PT_BOOLEAN:PSETID_Task:0x8109";
34
+            $properties["datecompleted"] = "PT_SYSTIME:PSETID_Task:0x810f";
35
+            $properties["recurring_data"] = "PT_BINARY:PSETID_Task:0x8116";
36
+            $properties["actualwork"] = "PT_LONG:PSETID_Task:0x8110";
37
+            $properties["totalwork"] = "PT_LONG:PSETID_Task:0x8111";
38
+            $properties["complete"] = "PT_BOOLEAN:PSETID_Task:0x811c";
39
+            $properties["task_f_creator"] = "PT_BOOLEAN:PSETID_Task:0x811e";
40
+            $properties["owner"] = "PT_STRING8:PSETID_Task:0x811f";
41
+            $properties["recurring"] = "PT_BOOLEAN:PSETID_Task:0x8126";
42
+
43
+            $properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
44
+            $properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
45
+            $properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
46
+
47
+            $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
48
+            $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
49
+            $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
50
+            $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
51
+
52
+            $properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
53
+            $properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
54
+            $properties["commonassign"] = "PT_LONG:PSETID_Common:0x8518";
55
+            $properties["flagdueby"] = "PT_SYSTIME:PSETID_Common:0x8560";
56
+            $properties["side_effects"] = "PT_LONG:PSETID_Common:0x8510";
57
+            $properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
58
+            $properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
59
+
60
+            $this->proptags = getPropIdsFromStrings($store, $properties);
61
+
62
+            parent::__construct($store, $message, $properties);
63
+        }
64
+
65
+        /**
66
+         * Function which saves recurrence and also regenerates task if necessary.
67
+         *
68
+         *@param array $recur new recurrence properties
69
+         *
70
+         *@return array of properties of regenerated task else false
71
+         */
72
+        public function setRecurrence(&$recur) {
73
+            $this->recur = $recur;
74
+            $this->action = &$recur;
75
+
76
+            if (!isset($this->recur["changed_occurences"])) {
77
+                $this->recur["changed_occurences"] = [];
78
+            }
79
+
80
+            if (!isset($this->recur["deleted_occurences"])) {
81
+                $this->recur["deleted_occurences"] = [];
82
+            }
83
+
84
+            if (!isset($this->recur['startocc'])) {
85
+                $this->recur['startocc'] = 0;
86
+            }
87
+            if (!isset($this->recur['endocc'])) {
88
+                $this->recur['endocc'] = 0;
89
+            }
90
+
91
+            // Save recurrence because we need proper startrecurrdate and endrecurrdate
92
+            $this->saveRecurrence();
93
+
94
+            // Update $this->recur with proper startrecurrdate and endrecurrdate updated after saving recurrence
95
+            $msgProps = mapi_getprops($this->message, [$this->proptags['recurring_data']]);
96
+            $recurring_data = $this->parseRecurrence($msgProps[$this->proptags['recurring_data']]);
97
+            foreach ($recurring_data as $key => $value) {
98
+                $this->recur[$key] = $value;
99
+            }
100
+
101
+            $this->setFirstOccurrence();
102
+
103
+            // Let's see if next occurrence has to be generated
104
+            return $this->moveToNextOccurrence();
105
+        }
106
+
107
+        /**
108
+         * Sets task object to first occurrence if startdate/duedate of task object is different from first occurrence.
109
+         */
110
+        public function setFirstOccurrence() {
111
+            // Check if it is already the first occurrence
112
+            if ($this->action['start'] == $this->recur["start"]) {
113
+                return;
114
+            }
115
+            $items = $this->getNextOccurrence();
116
+
117
+            $props = [];
118
+            $props[$this->proptags['startdate']] = $items[$this->proptags['startdate']];
119
+            $props[$this->proptags['commonstart']] = $items[$this->proptags['startdate']];
120
+
121
+            $props[$this->proptags['duedate']] = $items[$this->proptags['duedate']];
122
+            $props[$this->proptags['commonend']] = $items[$this->proptags['duedate']];
123
+
124
+            mapi_setprops($this->message, $props);
125
+        }
126
+
127
+        /**
128
+         * Function which creates new task as current occurrence and moves the
129
+         * existing task to next occurrence.
130
+         *
131
+         *@param array $recur $action from client
132
+         *
133
+         *@return bool if moving to next occurrence succeed then it returns
134
+         *		properties of either newly created task or existing task ELSE
135
+         *		false because that was last occurrence
136
+         */
137
+        public function moveToNextOccurrence() {
138
+            $result = false;
139
+            /*
140 140
 			 * Every recurring task should have a 'duedate'. If a recurring task is created with no start/end date
141 141
 			 * then we create first two occurrence separately and for first occurrence recurrence has ended.
142 142
 			 */
143
-			if ((empty($this->action['startdate']) && empty($this->action['duedate'])) ||
144
-				($this->action['complete'] == 1) || (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence'])) {
145
-				$nextOccurrence = $this->getNextOccurrence();
146
-				$result = mapi_getprops($this->message, [PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID]);
147
-
148
-				$props = [];
149
-				if ($nextOccurrence) {
150
-					if (!isset($this->action['deleteOccurrence'])) {
151
-						// Create current occurrence as separate task
152
-						$result = $this->regenerateTask($this->action['complete']);
153
-					}
154
-
155
-					// Set reminder for next occurrence
156
-					$this->setReminder($nextOccurrence);
157
-
158
-					// Update properties for next occurrence
159
-					$this->action['duedate'] = $props[$this->proptags['duedate']] = $nextOccurrence[$this->proptags['duedate']];
160
-					$this->action['commonend'] = $props[$this->proptags['commonend']] = $nextOccurrence[$this->proptags['duedate']];
161
-
162
-					$this->action['startdate'] = $props[$this->proptags['startdate']] = $nextOccurrence[$this->proptags['startdate']];
163
-					$this->action['commonstart'] = $props[$this->proptags['commonstart']] = $nextOccurrence[$this->proptags['startdate']];
164
-
165
-					// If current task as been mark as 'Complete' then next occurrence should be incomplete.
166
-					if (isset($this->action['complete']) && $this->action['complete'] == 1) {
167
-						$this->action['status'] = $props[$this->proptags["status"]] = olTaskNotStarted;
168
-						$this->action['complete'] = $props[$this->proptags["complete"]] = false;
169
-						$this->action['percent_complete'] = $props[$this->proptags["percent_complete"]] = 0;
170
-					}
171
-
172
-					$props[$this->proptags["dead_occurrence"]] = false;
173
-				}
174
-				else {
175
-					if (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence']) {
176
-						return false;
177
-					}
178
-
179
-					// Didn't get next occurrence, probably this is the last one, so recurrence ends here
180
-					$props[$this->proptags["dead_occurrence"]] = true;
181
-					$props[$this->proptags["datecompleted"]] = $this->action['datecompleted'];
182
-					$props[$this->proptags["task_f_creator"]] = true;
183
-
184
-					// OL props
185
-					$props[$this->proptags["side_effects"]] = 1296;
186
-					$props[$this->proptags["icon_index"]] = 1280;
187
-				}
188
-
189
-				mapi_setprops($this->message, $props);
190
-			}
191
-
192
-			return $result;
193
-		}
194
-
195
-		/**
196
-		 * Function which return properties of next occurrence.
197
-		 *
198
-		 *@return array startdate/enddate of next occurrence
199
-		 */
200
-		public function getNextOccurrence() {
201
-			if ($this->recur) {
202
-				$items = [];
203
-
204
-				// @TODO: fix start of range
205
-				$start = isset($this->messageprops[$this->proptags["duedate"]]) ? $this->messageprops[$this->proptags["duedate"]] : $this->action['start'];
206
-				$dayend = ($this->recur['term'] == 0x23) ? 0x7FFFFFFF : $this->dayStartOf($this->recur["end"]);
207
-
208
-				// Fix recur object
209
-				$this->recur['startocc'] = 0;
210
-				$this->recur['endocc'] = 0;
211
-
212
-				// Retrieve next occurrence
213
-				$items = $this->getItems($start, $dayend, 1);
214
-
215
-				return !empty($items) ? $items[0] : false;
216
-			}
217
-		}
218
-
219
-		/**
220
-		 * Function which clones current occurrence and sets appropriate properties.
221
-		 * The original recurring item is moved to next occurrence.
222
-		 *
223
-		 *@param bool $markComplete true if existing occurrence has to be mark complete else false
224
-		 */
225
-		public function regenerateTask($markComplete) {
226
-			// Get all properties
227
-			$taskItemProps = mapi_getprops($this->message);
228
-
229
-			if (isset($this->action["subject"])) {
230
-				$taskItemProps[$this->proptags["subject"]] = $this->action["subject"];
231
-			}
232
-			if (isset($this->action["importance"])) {
233
-				$taskItemProps[$this->proptags["importance"]] = $this->action["importance"];
234
-			}
235
-			if (isset($this->action["startdate"])) {
236
-				$taskItemProps[$this->proptags["startdate"]] = $this->action["startdate"];
237
-				$taskItemProps[$this->proptags["commonstart"]] = $this->action["startdate"];
238
-			}
239
-			if (isset($this->action["duedate"])) {
240
-				$taskItemProps[$this->proptags["duedate"]] = $this->action["duedate"];
241
-				$taskItemProps[$this->proptags["commonend"]] = $this->action["duedate"];
242
-			}
243
-
244
-			$folder = mapi_msgstore_openentry($this->store, $taskItemProps[PR_PARENT_ENTRYID]);
245
-			$newMessage = mapi_folder_createmessage($folder);
246
-
247
-			$taskItemProps[$this->proptags["status"]] = $markComplete ? olTaskComplete : olTaskNotStarted;
248
-			$taskItemProps[$this->proptags["complete"]] = $markComplete;
249
-			$taskItemProps[$this->proptags["percent_complete"]] = $markComplete ? 1 : 0;
250
-
251
-			// This occurrence has been marked as 'Complete' so disable reminder
252
-			if ($markComplete) {
253
-				$taskItemProps[$this->proptags["reset_reminder"]] = false;
254
-				$taskItemProps[$this->proptags["reminder"]] = false;
255
-				$taskItemProps[$this->proptags["datecompleted"]] = $this->action["datecompleted"];
256
-
257
-				unset($this->action[$this->proptags['datecompleted']]);
258
-			}
259
-
260
-			// Recurrence ends for this item
261
-			$taskItemProps[$this->proptags["dead_occurrence"]] = true;
262
-			$taskItemProps[$this->proptags["task_f_creator"]] = true;
263
-
264
-			// OL props
265
-			$taskItemProps[$this->proptags["side_effects"]] = 1296;
266
-			$taskItemProps[$this->proptags["icon_index"]] = 1280;
267
-
268
-			// Copy recipients
269
-			$recipienttable = mapi_message_getrecipienttable($this->message);
270
-			$recipients = mapi_table_queryallrows($recipienttable, [PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_RECIPIENT_ENTRYID, PR_RECIPIENT_TYPE, PR_SEND_INTERNET_ENCODING, PR_SEND_RICH_INFO, PR_RECIPIENT_DISPLAY_NAME, PR_ADDRTYPE, PR_DISPLAY_TYPE, PR_RECIPIENT_TRACKSTATUS, PR_RECIPIENT_TRACKSTATUS_TIME, PR_RECIPIENT_FLAGS, PR_ROWID]);
271
-
272
-			$copy_to_recipientTable = mapi_message_getrecipienttable($newMessage);
273
-			$copy_to_recipientRows = mapi_table_queryallrows($copy_to_recipientTable, [PR_ROWID]);
274
-			foreach ($copy_to_recipientRows as $recipient) {
275
-				mapi_message_modifyrecipients($newMessage, MODRECIP_REMOVE, [$recipient]);
276
-			}
277
-			mapi_message_modifyrecipients($newMessage, MODRECIP_ADD, $recipients);
278
-
279
-			// Copy attachments
280
-			$attachmentTable = mapi_message_getattachmenttable($this->message);
281
-			if ($attachmentTable) {
282
-				$attachments = mapi_table_queryallrows($attachmentTable, [PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD]);
283
-
284
-				foreach ($attachments as $attach_props) {
285
-					$attach_old = mapi_message_openattach($this->message, (int) $attach_props[PR_ATTACH_NUM]);
286
-					$attach_newResourceMsg = mapi_message_createattach($newMessage);
287
-
288
-					mapi_copyto($attach_old, [], [], $attach_newResourceMsg, 0);
289
-					mapi_savechanges($attach_newResourceMsg);
290
-				}
291
-			}
292
-
293
-			mapi_setprops($newMessage, $taskItemProps);
294
-			mapi_savechanges($newMessage);
295
-
296
-			// Update body of original message
297
-			$msgbody = mapi_openproperty($this->message, PR_BODY);
298
-			$msgbody = trim($msgbody, "\0");
299
-			$separator = "------------\r\n";
300
-
301
-			if (!empty($msgbody) && strrpos($msgbody, $separator) === false) {
302
-				$msgbody = $separator . $msgbody;
303
-				$stream = mapi_openproperty($this->message, PR_BODY, IID_IStream, 0, MAPI_CREATE | MAPI_MODIFY);
304
-				mapi_stream_setsize($stream, strlen($msgbody));
305
-				mapi_stream_write($stream, $msgbody);
306
-				mapi_stream_commit($stream);
307
-			}
308
-
309
-			// We need these properties to notify client
310
-			return mapi_getprops($newMessage, [PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID]);
311
-		}
312
-
313
-		/**
314
-		 * processOccurrenceItem, adds an item to a list of occurrences, but only if the
315
-		 * resulting occurrence starts or ends in the interval <$start, $end>.
316
-		 *
317
-		 * @param array $items    reference to the array to be added to
318
-		 * @param date  $start    start of timeframe in GMT TIME
319
-		 * @param date  $end      end of timeframe in GMT TIME
320
-		 * @param date  $basedate (hour/sec/min assumed to be 00:00:00) in LOCAL TIME OF THE OCCURRENCE
321
-		 * @param mixed $now
322
-		 */
323
-		public function processOccurrenceItem(&$items, $start, $end, $now) {
324
-			if ($now <= $start) {
325
-				return;
326
-			}
327
-			$newItem = [];
328
-			$newItem[$this->proptags['startdate']] = $now;
329
-
330
-			// If startdate and enddate are set on task, then slide enddate according to duration
331
-			if (isset($this->messageprops[$this->proptags["startdate"]], $this->messageprops[$this->proptags["duedate"]])) {
332
-				$newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']] + ($this->messageprops[$this->proptags["duedate"]] - $this->messageprops[$this->proptags["startdate"]]);
333
-			}
334
-			else {
335
-				$newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']];
336
-			}
337
-			$items[] = $newItem;
338
-		}
339
-
340
-		/**
341
-		 * Function which marks existing occurrence to 'Complete'.
342
-		 *
343
-		 *@param array $recur array action from client
344
-		 *
345
-		 *@return array of properties of regenerated task else false
346
-		 */
347
-		public function markOccurrenceComplete(&$recur) {
348
-			// Fix timezone object
349
-			$this->tz = false;
350
-			$this->action = &$recur;
351
-			$dead_occurrence = isset($this->messageprops[$this->proptags['dead_occurrence']]) ? $this->messageprops[$this->proptags['dead_occurrence']] : false;
352
-
353
-			if (!$dead_occurrence) {
354
-				return $this->moveToNextOccurrence();
355
-			}
356
-
357
-			return false;
358
-		}
359
-
360
-		/**
361
-		 * Function which sets reminder on recurring task after existing occurrence has been deleted or marked complete.
362
-		 *
363
-		 *@param array $nextOccurrence properties of next occurrence
364
-		 */
365
-		public function setReminder($nextOccurrence) {
366
-			$props = [];
367
-			if ($nextOccurrence) {
368
-				// Check if reminder is reset. Default is 'false'
369
-				$reset_reminder = isset($this->messageprops[$this->proptags['reset_reminder']]) ? $this->messageprops[$this->proptags['reset_reminder']] : false;
370
-				$reminder = $this->messageprops[$this->proptags['reminder']];
371
-
372
-				// Either reminder was already set OR reminder was set but was dismissed bty user
373
-				if ($reminder || $reset_reminder) {
374
-					// Reminder can be set at any time either before or after the duedate, so get duration between the reminder time and duedate
375
-					$reminder_time = isset($this->messageprops[$this->proptags['reminder_time']]) ? $this->messageprops[$this->proptags['reminder_time']] : 0;
376
-					$reminder_difference = isset($this->messageprops[$this->proptags['duedate']]) ? $this->messageprops[$this->proptags['duedate']] : 0;
377
-					$reminder_difference = $reminder_difference - $reminder_time;
378
-
379
-					// Apply duration to next calculated duedate
380
-					$next_reminder_time = $nextOccurrence[$this->proptags['duedate']] - $reminder_difference;
381
-
382
-					$props[$this->proptags['reminder_time']] = $next_reminder_time;
383
-					$props[$this->proptags['flagdueby']] = $next_reminder_time;
384
-					$this->action['reminder'] = $props[$this->proptags['reminder']] = true;
385
-				}
386
-			}
387
-			else {
388
-				// Didn't get next occurrence, probably this is the last occurrence
389
-				$props[$this->proptags['reminder']] = false;
390
-				$props[$this->proptags['reset_reminder']] = false;
391
-			}
392
-
393
-			if (!empty($props)) {
394
-				mapi_setprops($this->message, $props);
395
-			}
396
-		}
397
-
398
-		/**
399
-		 * Function which recurring task to next occurrence.
400
-		 * It simply doesn't regenerate task.
401
-		 *
402
-		 * @param array $action
403
-		 */
404
-		public function deleteOccurrence($action) {
405
-			$this->tz = false;
406
-			$this->action = $action;
407
-			$result = $this->moveToNextOccurrence();
408
-
409
-			mapi_savechanges($this->message);
410
-
411
-			return $result;
412
-		}
413
-	}
143
+            if ((empty($this->action['startdate']) && empty($this->action['duedate'])) ||
144
+                ($this->action['complete'] == 1) || (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence'])) {
145
+                $nextOccurrence = $this->getNextOccurrence();
146
+                $result = mapi_getprops($this->message, [PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID]);
147
+
148
+                $props = [];
149
+                if ($nextOccurrence) {
150
+                    if (!isset($this->action['deleteOccurrence'])) {
151
+                        // Create current occurrence as separate task
152
+                        $result = $this->regenerateTask($this->action['complete']);
153
+                    }
154
+
155
+                    // Set reminder for next occurrence
156
+                    $this->setReminder($nextOccurrence);
157
+
158
+                    // Update properties for next occurrence
159
+                    $this->action['duedate'] = $props[$this->proptags['duedate']] = $nextOccurrence[$this->proptags['duedate']];
160
+                    $this->action['commonend'] = $props[$this->proptags['commonend']] = $nextOccurrence[$this->proptags['duedate']];
161
+
162
+                    $this->action['startdate'] = $props[$this->proptags['startdate']] = $nextOccurrence[$this->proptags['startdate']];
163
+                    $this->action['commonstart'] = $props[$this->proptags['commonstart']] = $nextOccurrence[$this->proptags['startdate']];
164
+
165
+                    // If current task as been mark as 'Complete' then next occurrence should be incomplete.
166
+                    if (isset($this->action['complete']) && $this->action['complete'] == 1) {
167
+                        $this->action['status'] = $props[$this->proptags["status"]] = olTaskNotStarted;
168
+                        $this->action['complete'] = $props[$this->proptags["complete"]] = false;
169
+                        $this->action['percent_complete'] = $props[$this->proptags["percent_complete"]] = 0;
170
+                    }
171
+
172
+                    $props[$this->proptags["dead_occurrence"]] = false;
173
+                }
174
+                else {
175
+                    if (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence']) {
176
+                        return false;
177
+                    }
178
+
179
+                    // Didn't get next occurrence, probably this is the last one, so recurrence ends here
180
+                    $props[$this->proptags["dead_occurrence"]] = true;
181
+                    $props[$this->proptags["datecompleted"]] = $this->action['datecompleted'];
182
+                    $props[$this->proptags["task_f_creator"]] = true;
183
+
184
+                    // OL props
185
+                    $props[$this->proptags["side_effects"]] = 1296;
186
+                    $props[$this->proptags["icon_index"]] = 1280;
187
+                }
188
+
189
+                mapi_setprops($this->message, $props);
190
+            }
191
+
192
+            return $result;
193
+        }
194
+
195
+        /**
196
+         * Function which return properties of next occurrence.
197
+         *
198
+         *@return array startdate/enddate of next occurrence
199
+         */
200
+        public function getNextOccurrence() {
201
+            if ($this->recur) {
202
+                $items = [];
203
+
204
+                // @TODO: fix start of range
205
+                $start = isset($this->messageprops[$this->proptags["duedate"]]) ? $this->messageprops[$this->proptags["duedate"]] : $this->action['start'];
206
+                $dayend = ($this->recur['term'] == 0x23) ? 0x7FFFFFFF : $this->dayStartOf($this->recur["end"]);
207
+
208
+                // Fix recur object
209
+                $this->recur['startocc'] = 0;
210
+                $this->recur['endocc'] = 0;
211
+
212
+                // Retrieve next occurrence
213
+                $items = $this->getItems($start, $dayend, 1);
214
+
215
+                return !empty($items) ? $items[0] : false;
216
+            }
217
+        }
218
+
219
+        /**
220
+         * Function which clones current occurrence and sets appropriate properties.
221
+         * The original recurring item is moved to next occurrence.
222
+         *
223
+         *@param bool $markComplete true if existing occurrence has to be mark complete else false
224
+         */
225
+        public function regenerateTask($markComplete) {
226
+            // Get all properties
227
+            $taskItemProps = mapi_getprops($this->message);
228
+
229
+            if (isset($this->action["subject"])) {
230
+                $taskItemProps[$this->proptags["subject"]] = $this->action["subject"];
231
+            }
232
+            if (isset($this->action["importance"])) {
233
+                $taskItemProps[$this->proptags["importance"]] = $this->action["importance"];
234
+            }
235
+            if (isset($this->action["startdate"])) {
236
+                $taskItemProps[$this->proptags["startdate"]] = $this->action["startdate"];
237
+                $taskItemProps[$this->proptags["commonstart"]] = $this->action["startdate"];
238
+            }
239
+            if (isset($this->action["duedate"])) {
240
+                $taskItemProps[$this->proptags["duedate"]] = $this->action["duedate"];
241
+                $taskItemProps[$this->proptags["commonend"]] = $this->action["duedate"];
242
+            }
243
+
244
+            $folder = mapi_msgstore_openentry($this->store, $taskItemProps[PR_PARENT_ENTRYID]);
245
+            $newMessage = mapi_folder_createmessage($folder);
246
+
247
+            $taskItemProps[$this->proptags["status"]] = $markComplete ? olTaskComplete : olTaskNotStarted;
248
+            $taskItemProps[$this->proptags["complete"]] = $markComplete;
249
+            $taskItemProps[$this->proptags["percent_complete"]] = $markComplete ? 1 : 0;
250
+
251
+            // This occurrence has been marked as 'Complete' so disable reminder
252
+            if ($markComplete) {
253
+                $taskItemProps[$this->proptags["reset_reminder"]] = false;
254
+                $taskItemProps[$this->proptags["reminder"]] = false;
255
+                $taskItemProps[$this->proptags["datecompleted"]] = $this->action["datecompleted"];
256
+
257
+                unset($this->action[$this->proptags['datecompleted']]);
258
+            }
259
+
260
+            // Recurrence ends for this item
261
+            $taskItemProps[$this->proptags["dead_occurrence"]] = true;
262
+            $taskItemProps[$this->proptags["task_f_creator"]] = true;
263
+
264
+            // OL props
265
+            $taskItemProps[$this->proptags["side_effects"]] = 1296;
266
+            $taskItemProps[$this->proptags["icon_index"]] = 1280;
267
+
268
+            // Copy recipients
269
+            $recipienttable = mapi_message_getrecipienttable($this->message);
270
+            $recipients = mapi_table_queryallrows($recipienttable, [PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_RECIPIENT_ENTRYID, PR_RECIPIENT_TYPE, PR_SEND_INTERNET_ENCODING, PR_SEND_RICH_INFO, PR_RECIPIENT_DISPLAY_NAME, PR_ADDRTYPE, PR_DISPLAY_TYPE, PR_RECIPIENT_TRACKSTATUS, PR_RECIPIENT_TRACKSTATUS_TIME, PR_RECIPIENT_FLAGS, PR_ROWID]);
271
+
272
+            $copy_to_recipientTable = mapi_message_getrecipienttable($newMessage);
273
+            $copy_to_recipientRows = mapi_table_queryallrows($copy_to_recipientTable, [PR_ROWID]);
274
+            foreach ($copy_to_recipientRows as $recipient) {
275
+                mapi_message_modifyrecipients($newMessage, MODRECIP_REMOVE, [$recipient]);
276
+            }
277
+            mapi_message_modifyrecipients($newMessage, MODRECIP_ADD, $recipients);
278
+
279
+            // Copy attachments
280
+            $attachmentTable = mapi_message_getattachmenttable($this->message);
281
+            if ($attachmentTable) {
282
+                $attachments = mapi_table_queryallrows($attachmentTable, [PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD]);
283
+
284
+                foreach ($attachments as $attach_props) {
285
+                    $attach_old = mapi_message_openattach($this->message, (int) $attach_props[PR_ATTACH_NUM]);
286
+                    $attach_newResourceMsg = mapi_message_createattach($newMessage);
287
+
288
+                    mapi_copyto($attach_old, [], [], $attach_newResourceMsg, 0);
289
+                    mapi_savechanges($attach_newResourceMsg);
290
+                }
291
+            }
292
+
293
+            mapi_setprops($newMessage, $taskItemProps);
294
+            mapi_savechanges($newMessage);
295
+
296
+            // Update body of original message
297
+            $msgbody = mapi_openproperty($this->message, PR_BODY);
298
+            $msgbody = trim($msgbody, "\0");
299
+            $separator = "------------\r\n";
300
+
301
+            if (!empty($msgbody) && strrpos($msgbody, $separator) === false) {
302
+                $msgbody = $separator . $msgbody;
303
+                $stream = mapi_openproperty($this->message, PR_BODY, IID_IStream, 0, MAPI_CREATE | MAPI_MODIFY);
304
+                mapi_stream_setsize($stream, strlen($msgbody));
305
+                mapi_stream_write($stream, $msgbody);
306
+                mapi_stream_commit($stream);
307
+            }
308
+
309
+            // We need these properties to notify client
310
+            return mapi_getprops($newMessage, [PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID]);
311
+        }
312
+
313
+        /**
314
+         * processOccurrenceItem, adds an item to a list of occurrences, but only if the
315
+         * resulting occurrence starts or ends in the interval <$start, $end>.
316
+         *
317
+         * @param array $items    reference to the array to be added to
318
+         * @param date  $start    start of timeframe in GMT TIME
319
+         * @param date  $end      end of timeframe in GMT TIME
320
+         * @param date  $basedate (hour/sec/min assumed to be 00:00:00) in LOCAL TIME OF THE OCCURRENCE
321
+         * @param mixed $now
322
+         */
323
+        public function processOccurrenceItem(&$items, $start, $end, $now) {
324
+            if ($now <= $start) {
325
+                return;
326
+            }
327
+            $newItem = [];
328
+            $newItem[$this->proptags['startdate']] = $now;
329
+
330
+            // If startdate and enddate are set on task, then slide enddate according to duration
331
+            if (isset($this->messageprops[$this->proptags["startdate"]], $this->messageprops[$this->proptags["duedate"]])) {
332
+                $newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']] + ($this->messageprops[$this->proptags["duedate"]] - $this->messageprops[$this->proptags["startdate"]]);
333
+            }
334
+            else {
335
+                $newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']];
336
+            }
337
+            $items[] = $newItem;
338
+        }
339
+
340
+        /**
341
+         * Function which marks existing occurrence to 'Complete'.
342
+         *
343
+         *@param array $recur array action from client
344
+         *
345
+         *@return array of properties of regenerated task else false
346
+         */
347
+        public function markOccurrenceComplete(&$recur) {
348
+            // Fix timezone object
349
+            $this->tz = false;
350
+            $this->action = &$recur;
351
+            $dead_occurrence = isset($this->messageprops[$this->proptags['dead_occurrence']]) ? $this->messageprops[$this->proptags['dead_occurrence']] : false;
352
+
353
+            if (!$dead_occurrence) {
354
+                return $this->moveToNextOccurrence();
355
+            }
356
+
357
+            return false;
358
+        }
359
+
360
+        /**
361
+         * Function which sets reminder on recurring task after existing occurrence has been deleted or marked complete.
362
+         *
363
+         *@param array $nextOccurrence properties of next occurrence
364
+         */
365
+        public function setReminder($nextOccurrence) {
366
+            $props = [];
367
+            if ($nextOccurrence) {
368
+                // Check if reminder is reset. Default is 'false'
369
+                $reset_reminder = isset($this->messageprops[$this->proptags['reset_reminder']]) ? $this->messageprops[$this->proptags['reset_reminder']] : false;
370
+                $reminder = $this->messageprops[$this->proptags['reminder']];
371
+
372
+                // Either reminder was already set OR reminder was set but was dismissed bty user
373
+                if ($reminder || $reset_reminder) {
374
+                    // Reminder can be set at any time either before or after the duedate, so get duration between the reminder time and duedate
375
+                    $reminder_time = isset($this->messageprops[$this->proptags['reminder_time']]) ? $this->messageprops[$this->proptags['reminder_time']] : 0;
376
+                    $reminder_difference = isset($this->messageprops[$this->proptags['duedate']]) ? $this->messageprops[$this->proptags['duedate']] : 0;
377
+                    $reminder_difference = $reminder_difference - $reminder_time;
378
+
379
+                    // Apply duration to next calculated duedate
380
+                    $next_reminder_time = $nextOccurrence[$this->proptags['duedate']] - $reminder_difference;
381
+
382
+                    $props[$this->proptags['reminder_time']] = $next_reminder_time;
383
+                    $props[$this->proptags['flagdueby']] = $next_reminder_time;
384
+                    $this->action['reminder'] = $props[$this->proptags['reminder']] = true;
385
+                }
386
+            }
387
+            else {
388
+                // Didn't get next occurrence, probably this is the last occurrence
389
+                $props[$this->proptags['reminder']] = false;
390
+                $props[$this->proptags['reset_reminder']] = false;
391
+            }
392
+
393
+            if (!empty($props)) {
394
+                mapi_setprops($this->message, $props);
395
+            }
396
+        }
397
+
398
+        /**
399
+         * Function which recurring task to next occurrence.
400
+         * It simply doesn't regenerate task.
401
+         *
402
+         * @param array $action
403
+         */
404
+        public function deleteOccurrence($action) {
405
+            $this->tz = false;
406
+            $this->action = $action;
407
+            $result = $this->moveToNextOccurrence();
408
+
409
+            mapi_savechanges($this->message);
410
+
411
+            return $result;
412
+        }
413
+    }
Please login to merge, or discard this patch.
Braces   +3 added lines, -6 removed lines patch added patch discarded remove patch
@@ -170,8 +170,7 @@  discard block
 block discarded – undo
170 170
 					}
171 171
 
172 172
 					$props[$this->proptags["dead_occurrence"]] = false;
173
-				}
174
-				else {
173
+				} else {
175 174
 					if (isset($this->action['deleteOccurrence']) && $this->action['deleteOccurrence']) {
176 175
 						return false;
177 176
 					}
@@ -330,8 +329,7 @@  discard block
 block discarded – undo
330 329
 			// If startdate and enddate are set on task, then slide enddate according to duration
331 330
 			if (isset($this->messageprops[$this->proptags["startdate"]], $this->messageprops[$this->proptags["duedate"]])) {
332 331
 				$newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']] + ($this->messageprops[$this->proptags["duedate"]] - $this->messageprops[$this->proptags["startdate"]]);
333
-			}
334
-			else {
332
+			} else {
335 333
 				$newItem[$this->proptags['duedate']] = $newItem[$this->proptags['startdate']];
336 334
 			}
337 335
 			$items[] = $newItem;
@@ -383,8 +381,7 @@  discard block
 block discarded – undo
383 381
 					$props[$this->proptags['flagdueby']] = $next_reminder_time;
384 382
 					$this->action['reminder'] = $props[$this->proptags['reminder']] = true;
385 383
 				}
386
-			}
387
-			else {
384
+			} else {
388 385
 				// Didn't get next occurrence, probably this is the last occurrence
389 386
 				$props[$this->proptags['reminder']] = false;
390 387
 				$props[$this->proptags['reset_reminder']] = false;
Please login to merge, or discard this patch.
mapi/class.recurrence.php 4 patches
Indentation   +1232 added lines, -1232 removed lines patch added patch discarded remove patch
@@ -5,14 +5,14 @@  discard block
 block discarded – undo
5 5
  * SPDX-FileCopyrightText: Copyright 2020 grommunio GmbH
6 6
  */
7 7
 
8
-	/**
9
-	 * Recurrence.
10
-	 *
11
-	 * @author Steve Hardy <[email protected]>
12
-	 * @author Michel de Ron <[email protected]>
13
-	 */
14
-	class Recurrence extends BaseRecurrence {
15
-		/*
8
+    /**
9
+     * Recurrence.
10
+     *
11
+     * @author Steve Hardy <[email protected]>
12
+     * @author Michel de Ron <[email protected]>
13
+     */
14
+    class Recurrence extends BaseRecurrence {
15
+        /*
16 16
 		 * ABOUT TIMEZONES
17 17
 		 *
18 18
 		 * Timezones are rather complicated here so here are some rules to think about:
@@ -24,1241 +24,1241 @@  discard block
 block discarded – undo
24 24
 		 *   always in LOCAL time.
25 25
 		 */
26 26
 
27
-		// All properties for a recipient that are interesting
28
-		public $recipprops = [
29
-			PR_ENTRYID,
30
-			PR_SEARCH_KEY,
31
-			PR_DISPLAY_NAME,
32
-			PR_EMAIL_ADDRESS,
33
-			PR_RECIPIENT_ENTRYID,
34
-			PR_RECIPIENT_TYPE,
35
-			PR_SEND_INTERNET_ENCODING,
36
-			PR_SEND_RICH_INFO,
37
-			PR_RECIPIENT_DISPLAY_NAME,
38
-			PR_ADDRTYPE,
39
-			PR_DISPLAY_TYPE,
40
-			PR_DISPLAY_TYPE_EX,
41
-			PR_RECIPIENT_TRACKSTATUS,
42
-			PR_RECIPIENT_TRACKSTATUS_TIME,
43
-			PR_RECIPIENT_FLAGS,
44
-			PR_ROWID,
45
-		];
46
-
47
-		/**
48
-		 * @param resource $store   MAPI Message Store Object
49
-		 * @param resource $message the MAPI (appointment) message
50
-		 */
51
-		public function __construct($store, $message) {
52
-			$properties = [];
53
-			$properties["entryid"] = PR_ENTRYID;
54
-			$properties["parent_entryid"] = PR_PARENT_ENTRYID;
55
-			$properties["message_class"] = PR_MESSAGE_CLASS;
56
-			$properties["icon_index"] = PR_ICON_INDEX;
57
-			$properties["subject"] = PR_SUBJECT;
58
-			$properties["display_to"] = PR_DISPLAY_TO;
59
-			$properties["importance"] = PR_IMPORTANCE;
60
-			$properties["sensitivity"] = PR_SENSITIVITY;
61
-			$properties["startdate"] = "PT_SYSTIME:PSETID_Appointment:0x820d";
62
-			$properties["duedate"] = "PT_SYSTIME:PSETID_Appointment:0x820e";
63
-			$properties["recurring"] = "PT_BOOLEAN:PSETID_Appointment:0x8223";
64
-			$properties["recurring_data"] = "PT_BINARY:PSETID_Appointment:0x8216";
65
-			$properties["busystatus"] = "PT_LONG:PSETID_Appointment:0x8205";
66
-			$properties["label"] = "PT_LONG:PSETID_Appointment:0x8214";
67
-			$properties["alldayevent"] = "PT_BOOLEAN:PSETID_Appointment:0x8215";
68
-			$properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
69
-			$properties["meeting"] = "PT_LONG:PSETID_Appointment:0x8217";
70
-			$properties["startdate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8235";
71
-			$properties["enddate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8236";
72
-			$properties["recurring_pattern"] = "PT_STRING8:PSETID_Appointment:0x8232";
73
-			$properties["location"] = "PT_STRING8:PSETID_Appointment:0x8208";
74
-			$properties["duration"] = "PT_LONG:PSETID_Appointment:0x8213";
75
-			$properties["responsestatus"] = "PT_LONG:PSETID_Appointment:0x8218";
76
-			$properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
77
-			$properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
78
-			$properties["recurrencetype"] = "PT_LONG:PSETID_Appointment:0x8231";
79
-			$properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
80
-			$properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
81
-			$properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
82
-			$properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
83
-			$properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
84
-			$properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
85
-			$properties["basedate"] = "PT_SYSTIME:PSETID_Appointment:0x8228";
86
-			$properties["timezone_data"] = "PT_BINARY:PSETID_Appointment:0x8233";
87
-			$properties["timezone"] = "PT_STRING8:PSETID_Appointment:0x8234";
88
-			$properties["flagdueby"] = "PT_SYSTIME:PSETID_Common:0x8560";
89
-			$properties["side_effects"] = "PT_LONG:PSETID_Common:0x8510";
90
-			$properties["hideattachments"] = "PT_BOOLEAN:PSETID_Common:0x8514";
91
-
92
-			$this->proptags = getPropIdsFromStrings($store, $properties);
93
-
94
-			parent::__construct($store, $message);
95
-		}
96
-
97
-		/**
98
-		 * Create an exception.
99
-		 *
100
-		 * @param array        $exception_props  the exception properties (same properties as normal recurring items)
101
-		 * @param date         $base_date        the base date of the exception (LOCAL time of non-exception occurrence)
102
-		 * @param bool         $delete           true - delete occurrence, false - create new exception or modify existing
103
-		 * @param array        $exception_recips true - delete occurrence, false - create new exception or modify existing
104
-		 * @param mapi_message $copy_attach_from mapi message from which attachments should be copied
105
-		 */
106
-		public function createException($exception_props, $base_date, $delete = false, $exception_recips = [], $copy_attach_from = false) {
107
-			$baseday = $this->dayStartOf($base_date);
108
-			$basetime = $baseday + $this->recur["startocc"] * 60;
109
-
110
-			// Remove any pre-existing exception on this base date
111
-			if ($this->isException($baseday)) {
112
-				$this->deleteException($baseday);
113
-			} // note that deleting an exception is different from creating a deleted exception (deleting an occurrence).
114
-
115
-			if (!$delete) {
116
-				if (isset($exception_props[$this->proptags["startdate"]]) && !$this->isValidExceptionDate($base_date, $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]))) {
117
-					return false;
118
-				}
119
-				// Properties in the attachment are the properties of the base object, plus $exception_props plus the base date
120
-				foreach (["subject", "location", "label", "reminder", "reminder_minutes", "alldayevent", "busystatus"] as $propname) {
121
-					if (isset($this->messageprops[$this->proptags[$propname]])) {
122
-						$props[$this->proptags[$propname]] = $this->messageprops[$this->proptags[$propname]];
123
-					}
124
-				}
125
-
126
-				$props[PR_MESSAGE_CLASS] = "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}";
127
-				unset($exception_props[PR_MESSAGE_CLASS], $exception_props[PR_ICON_INDEX]);
128
-
129
-				$props = $exception_props + $props;
130
-
131
-				// Basedate in the exception attachment is the GMT time at which the original occurrence would have been
132
-				$props[$this->proptags["basedate"]] = $this->toGMT($this->tz, $basetime);
133
-
134
-				if (!isset($exception_props[$this->proptags["startdate"]])) {
135
-					$props[$this->proptags["startdate"]] = $this->getOccurrenceStart($base_date);
136
-				}
137
-				if (!isset($exception_props[$this->proptags["duedate"]])) {
138
-					$props[$this->proptags["duedate"]] = $this->getOccurrenceEnd($base_date);
139
-				}
140
-
141
-				// synchronize commonstart/commonend with startdate/duedate
142
-				if (isset($props[$this->proptags["startdate"]])) {
143
-					$props[$this->proptags["commonstart"]] = $props[$this->proptags["startdate"]];
144
-				}
145
-				if (isset($props[$this->proptags["duedate"]])) {
146
-					$props[$this->proptags["commonend"]] = $props[$this->proptags["duedate"]];
147
-				}
148
-
149
-				// Save the data into an attachment
150
-				$this->createExceptionAttachment($props, $exception_recips, $copy_attach_from);
151
-
152
-				$changed_item = [];
153
-
154
-				$changed_item["basedate"] = $baseday;
155
-				$changed_item["start"] = $this->fromGMT($this->tz, $props[$this->proptags["startdate"]]);
156
-				$changed_item["end"] = $this->fromGMT($this->tz, $props[$this->proptags["duedate"]]);
157
-
158
-				if (array_key_exists($this->proptags["subject"], $exception_props)) {
159
-					$changed_item["subject"] = $exception_props[$this->proptags["subject"]];
160
-				}
161
-				if (array_key_exists($this->proptags["location"], $exception_props)) {
162
-					$changed_item["location"] = $exception_props[$this->proptags["location"]];
163
-				}
164
-				if (array_key_exists($this->proptags["label"], $exception_props)) {
165
-					$changed_item["label"] = $exception_props[$this->proptags["label"]];
166
-				}
167
-				if (array_key_exists($this->proptags["reminder"], $exception_props)) {
168
-					$changed_item["reminder_set"] = $exception_props[$this->proptags["reminder"]];
169
-				}
170
-				if (array_key_exists($this->proptags["reminder_minutes"], $exception_props)) {
171
-					$changed_item["remind_before"] = $exception_props[$this->proptags["reminder_minutes"]];
172
-				}
173
-				if (array_key_exists($this->proptags["alldayevent"], $exception_props)) {
174
-					$changed_item["alldayevent"] = $exception_props[$this->proptags["alldayevent"]];
175
-				}
176
-				if (array_key_exists($this->proptags["busystatus"], $exception_props)) {
177
-					$changed_item["busystatus"] = $exception_props[$this->proptags["busystatus"]];
178
-				}
179
-
180
-				// Add the changed occurrence to the list
181
-				array_push($this->recur["changed_occurrences"], $changed_item);
182
-			}
183
-			else {
184
-				// Delete the occurrence by placing it in the deleted occurrences list
185
-				array_push($this->recur["deleted_occurrences"], $baseday);
186
-			}
187
-
188
-			// Turn on hideattachments, because the attachments in this item are the exceptions
189
-			mapi_setprops($this->message, [$this->proptags["hideattachments"] => true]);
190
-
191
-			// Save recurrence data to message
192
-			$this->saveRecurrence();
193
-
194
-			return true;
195
-		}
196
-
197
-		/**
198
-		 * Modifies an existing exception, but only updates the given properties
199
-		 * NOTE: You can't remove properties from an exception, only add new ones.
200
-		 *
201
-		 * @param mixed $exception_props
202
-		 * @param mixed $base_date
203
-		 * @param mixed $exception_recips
204
-		 * @param mixed $copy_attach_from
205
-		 */
206
-		public function modifyException($exception_props, $base_date, $exception_recips = [], $copy_attach_from = false) {
207
-			if (isset($exception_props[$this->proptags["startdate"]]) && !$this->isValidExceptionDate($base_date, $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]))) {
208
-				return false;
209
-			}
210
-
211
-			$baseday = $this->dayStartOf($base_date);
212
-			$basetime = $baseday + $this->recur["startocc"] * 60;
213
-			$extomodify = false;
214
-
215
-			for ($i = 0, $len = count($this->recur["changed_occurrences"]); $i < $len; ++$i) {
216
-				if ($this->isSameDay($this->recur["changed_occurrences"][$i]["basedate"], $baseday)) {
217
-					$extomodify = &$this->recur["changed_occurrences"][$i];
218
-				}
219
-			}
220
-
221
-			if (!$extomodify) {
222
-				return false;
223
-			}
224
-
225
-			// remove basedate property as we want to preserve the old value
226
-			// client will send basedate with time part as zero, so discard that value
227
-			unset($exception_props[$this->proptags["basedate"]]);
228
-
229
-			if (array_key_exists($this->proptags["startdate"], $exception_props)) {
230
-				$extomodify["start"] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]);
231
-			}
232
-			if (array_key_exists($this->proptags["duedate"], $exception_props)) {
233
-				$extomodify["end"] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]);
234
-			}
235
-			if (array_key_exists($this->proptags["subject"], $exception_props)) {
236
-				$extomodify["subject"] = $exception_props[$this->proptags["subject"]];
237
-			}
238
-			if (array_key_exists($this->proptags["location"], $exception_props)) {
239
-				$extomodify["location"] = $exception_props[$this->proptags["location"]];
240
-			}
241
-			if (array_key_exists($this->proptags["label"], $exception_props)) {
242
-				$extomodify["label"] = $exception_props[$this->proptags["label"]];
243
-			}
244
-			if (array_key_exists($this->proptags["reminder"], $exception_props)) {
245
-				$extomodify["reminder_set"] = $exception_props[$this->proptags["reminder"]];
246
-			}
247
-			if (array_key_exists($this->proptags["reminder_minutes"], $exception_props)) {
248
-				$extomodify["remind_before"] = $exception_props[$this->proptags["reminder_minutes"]];
249
-			}
250
-			if (array_key_exists($this->proptags["alldayevent"], $exception_props)) {
251
-				$extomodify["alldayevent"] = $exception_props[$this->proptags["alldayevent"]];
252
-			}
253
-			if (array_key_exists($this->proptags["busystatus"], $exception_props)) {
254
-				$extomodify["busystatus"] = $exception_props[$this->proptags["busystatus"]];
255
-			}
256
-
257
-			$exception_props[PR_MESSAGE_CLASS] = "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}";
258
-
259
-			// synchronize commonstart/commonend with startdate/duedate
260
-			if (isset($exception_props[$this->proptags["startdate"]])) {
261
-				$exception_props[$this->proptags["commonstart"]] = $exception_props[$this->proptags["startdate"]];
262
-			}
263
-			if (isset($exception_props[$this->proptags["duedate"]])) {
264
-				$exception_props[$this->proptags["commonend"]] = $exception_props[$this->proptags["duedate"]];
265
-			}
266
-
267
-			$attach = $this->getExceptionAttachment($baseday);
268
-			if (!$attach) {
269
-				if ($copy_attach_from) {
270
-					$this->deleteExceptionAttachment($base_date);
271
-					$this->createException($exception_props, $base_date, false, $exception_recips, $copy_attach_from);
272
-				}
273
-				else {
274
-					$this->createExceptionAttachment($exception_props, $exception_recips, $copy_attach_from);
275
-				}
276
-			}
277
-			else {
278
-				$message = mapi_attach_openobj($attach, MAPI_MODIFY);
279
-
280
-				// Set exception properties on embedded message and save
281
-				mapi_setprops($message, $exception_props);
282
-				$this->setExceptionRecipients($message, $exception_recips, false);
283
-				mapi_savechanges($message);
284
-
285
-				// If a new start or duedate is provided, we update the properties 'PR_EXCEPTION_STARTTIME' and 'PR_EXCEPTION_ENDTIME'
286
-				// on the attachment which holds the embedded msg and save everything.
287
-				$props = [];
288
-				if (isset($exception_props[$this->proptags["startdate"]])) {
289
-					$props[PR_EXCEPTION_STARTTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]);
290
-				}
291
-				if (isset($exception_props[$this->proptags["duedate"]])) {
292
-					$props[PR_EXCEPTION_ENDTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]);
293
-				}
294
-				if (!empty($props)) {
295
-					mapi_setprops($attach, $props);
296
-				}
297
-				mapi_savechanges($attach);
298
-			}
299
-
300
-			// Save recurrence data to message
301
-			$this->saveRecurrence();
302
-
303
-			return true;
304
-		}
305
-
306
-		// Checks to see if the following is true:
307
-		// 1) The exception to be created doesn't create two exceptions starting on one day (however, they can END on the same day by modifying duration)
308
-		// 2) The exception to be created doesn't 'jump' over another occurrence (which may be an exception itself!)
309
-		//
310
-		// Both $basedate and $start are in LOCAL time
311
-		public function isValidExceptionDate($basedate, $start) {
312
-			// The way we do this is to look at the days that we're 'moving' the item in the exception. Each
313
-			// of these days may only contain the item that we're modifying. Any other item violates the rules.
314
-
315
-			if ($this->isException($basedate)) {
316
-				// If we're modifying an exception, we want to look at the days that we're 'moving' compared to where
317
-				// the exception used to be.
318
-				$oldexception = $this->getChangeException($basedate);
319
-				$prevday = $this->dayStartOf($oldexception["start"]);
320
-			}
321
-			else {
322
-				// If its a new exception, we want to look at the original placement of this item.
323
-				$prevday = $basedate;
324
-			}
325
-
326
-			$startday = $this->dayStartOf($start);
327
-
328
-			// Get all the occurrences on the days between the basedate (may be reversed)
329
-			if ($prevday < $startday) {
330
-				$items = $this->getItems($this->toGMT($this->tz, $prevday), $this->toGMT($this->tz, $startday + 24 * 60 * 60));
331
-			}
332
-			else {
333
-				$items = $this->getItems($this->toGMT($this->tz, $startday), $this->toGMT($this->tz, $prevday + 24 * 60 * 60));
334
-			}
335
-
336
-			// There should now be exactly one item, namely the item that we are modifying. If there are any other items in the range,
337
-			// then we abort the change, since one of the rules has been violated.
338
-			return count($items) == 1;
339
-		}
340
-
341
-		/**
342
-		 * Check to see if the exception proposed at a certain basedate is allowed concerning reminder times:.
343
-		 *
344
-		 * Both must be true:
345
-		 * - reminder time of this item is not before the starttime of the previous recurring item
346
-		 * - reminder time of the next item is not before the starttime of this item
347
-		 *
348
-		 * @param date   $basedate        the base date of the exception (LOCAL time of non-exception occurrence)
349
-		 * @param string $reminderminutes reminder minutes which is set of the item
350
-		 * @param date   $startdate       the startdate of the selected item
351
-		 * @returns boolean if the reminder minutes value valid (FALSE if either of the rules above are FALSE)
352
-		 */
353
-		public function isValidReminderTime($basedate, $reminderminutes, $startdate) {
354
-			$isreminderrangeset = false;
355
-
356
-			// get all occurrence items before the seleceted items occurrence starttime
357
-			$occitems = $this->getItems($this->messageprops[$this->proptags["startdate"]], $this->toGMT($this->tz, $basedate));
358
-
359
-			if (!empty($occitems)) {
360
-				// as occitems array is sorted in ascending order of startdate, to get the previous occurrence we take the last items in occitems .
361
-				$previousitem_startdate = $occitems[count($occitems) - 1][$this->proptags["startdate"]];
362
-
363
-				// if our reminder is set before or equal to the beginning of the previous occurrence, then that's not allowed
364
-				if ($startdate - ($reminderminutes * 60) <= $previousitem_startdate) {
365
-					return false;
366
-				}
367
-			}
368
-
369
-			// Get the endtime of the current occurrence and find the next two occurrences (including the current occurrence)
370
-			$currentOcc = $this->getItems($this->toGMT($this->tz, $basedate), 0x7FF00000, 2, true);
371
-
372
-			// If there are another two occurrences, then the first is the current occurrence, and the one after that
373
-			// is the next occurrence.
374
-			if (count($currentOcc) > 1) {
375
-				$next = $currentOcc[1];
376
-				// Get reminder time of the next occurrence.
377
-				$nextOccReminderTime = $next[$this->proptags["startdate"]] - ($next[$this->proptags["reminder_minutes"]] * 60);
378
-				// If the reminder time of the next item is before the start of this item, then that's not allowed
379
-				if ($nextOccReminderTime <= $startdate) {
380
-					return false;
381
-				}
382
-			}
383
-
384
-			// All was ok
385
-			return true;
386
-		}
387
-
388
-		public function setRecurrence($tz, $recur) {
389
-			// only reset timezone if specified
390
-			if ($tz) {
391
-				$this->tz = $tz;
392
-			}
393
-
394
-			$this->recur = $recur;
395
-
396
-			if (!isset($this->recur["changed_occurrences"])) {
397
-				$this->recur["changed_occurrences"] = [];
398
-			}
399
-
400
-			if (!isset($this->recur["deleted_occurrences"])) {
401
-				$this->recur["deleted_occurrences"] = [];
402
-			}
403
-
404
-			$this->deleteAttachments();
405
-			$this->saveRecurrence();
406
-
407
-			// if client has not set the recurring_pattern then we should generate it and save it
408
-			$messageProps = mapi_getprops($this->message, [$this->proptags["recurring_pattern"]]);
409
-			if (empty($messageProps[$this->proptags["recurring_pattern"]])) {
410
-				$this->saveRecurrencePattern();
411
-			}
412
-		}
413
-
414
-		// Returns the start or end time of the occurrence on the given base date.
415
-		// This assumes that the basedate you supply is in LOCAL time
416
-		public function getOccurrenceStart($basedate) {
417
-			$daystart = $this->dayStartOf($basedate);
418
-
419
-			return $this->toGMT($this->tz, $daystart + $this->recur["startocc"] * 60);
420
-		}
421
-
422
-		public function getOccurrenceEnd($basedate) {
423
-			$daystart = $this->dayStartOf($basedate);
424
-
425
-			return $this->toGMT($this->tz, $daystart + $this->recur["endocc"] * 60);
426
-		}
427
-
428
-		// Backwards compatible code
429
-		public function getOccurenceStart($basedate) {
430
-			return $this->getOccurrenceStart($basedate);
431
-		}
432
-
433
-		public function getOccurenceEnd($basedate) {
434
-			return $this->getOccurrenceEnd($basedate);
435
-		}
436
-
437
-		/**
438
-		 * This function returns the next remindertime starting from $timestamp
439
-		 * When no next reminder exists, false is returned.
440
-		 *
441
-		 * Note: Before saving this new reminder time (when snoozing), you must check for
442
-		 *       yourself if this reminder time is earlier than your snooze time, else
443
-		 *       use your snooze time and not this reminder time.
444
-		 *
445
-		 * @param mixed $timestamp
446
-		 */
447
-		public function getNextReminderTime($timestamp) {
448
-			/**
449
-			 * Get next item from now until forever, but max 1 item with reminder set
450
-			 * Note 0x7ff00000 instead of 0x7fffffff because of possible overflow failures when converting to GMT....
451
-			 * Here for getting next 10 occurrences assuming that next here we will be able to find
452
-			 * nextreminder occurrence in 10 occureneces.
453
-			 */
454
-			$items = $this->getItems($timestamp, 0x7FF00000, 10, true);
455
-
456
-			// Initially setting nextreminder to false so when no next reminder exists, false is returned.
457
-			$nextreminder = false;
458
-			/*
27
+        // All properties for a recipient that are interesting
28
+        public $recipprops = [
29
+            PR_ENTRYID,
30
+            PR_SEARCH_KEY,
31
+            PR_DISPLAY_NAME,
32
+            PR_EMAIL_ADDRESS,
33
+            PR_RECIPIENT_ENTRYID,
34
+            PR_RECIPIENT_TYPE,
35
+            PR_SEND_INTERNET_ENCODING,
36
+            PR_SEND_RICH_INFO,
37
+            PR_RECIPIENT_DISPLAY_NAME,
38
+            PR_ADDRTYPE,
39
+            PR_DISPLAY_TYPE,
40
+            PR_DISPLAY_TYPE_EX,
41
+            PR_RECIPIENT_TRACKSTATUS,
42
+            PR_RECIPIENT_TRACKSTATUS_TIME,
43
+            PR_RECIPIENT_FLAGS,
44
+            PR_ROWID,
45
+        ];
46
+
47
+        /**
48
+         * @param resource $store   MAPI Message Store Object
49
+         * @param resource $message the MAPI (appointment) message
50
+         */
51
+        public function __construct($store, $message) {
52
+            $properties = [];
53
+            $properties["entryid"] = PR_ENTRYID;
54
+            $properties["parent_entryid"] = PR_PARENT_ENTRYID;
55
+            $properties["message_class"] = PR_MESSAGE_CLASS;
56
+            $properties["icon_index"] = PR_ICON_INDEX;
57
+            $properties["subject"] = PR_SUBJECT;
58
+            $properties["display_to"] = PR_DISPLAY_TO;
59
+            $properties["importance"] = PR_IMPORTANCE;
60
+            $properties["sensitivity"] = PR_SENSITIVITY;
61
+            $properties["startdate"] = "PT_SYSTIME:PSETID_Appointment:0x820d";
62
+            $properties["duedate"] = "PT_SYSTIME:PSETID_Appointment:0x820e";
63
+            $properties["recurring"] = "PT_BOOLEAN:PSETID_Appointment:0x8223";
64
+            $properties["recurring_data"] = "PT_BINARY:PSETID_Appointment:0x8216";
65
+            $properties["busystatus"] = "PT_LONG:PSETID_Appointment:0x8205";
66
+            $properties["label"] = "PT_LONG:PSETID_Appointment:0x8214";
67
+            $properties["alldayevent"] = "PT_BOOLEAN:PSETID_Appointment:0x8215";
68
+            $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
69
+            $properties["meeting"] = "PT_LONG:PSETID_Appointment:0x8217";
70
+            $properties["startdate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8235";
71
+            $properties["enddate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8236";
72
+            $properties["recurring_pattern"] = "PT_STRING8:PSETID_Appointment:0x8232";
73
+            $properties["location"] = "PT_STRING8:PSETID_Appointment:0x8208";
74
+            $properties["duration"] = "PT_LONG:PSETID_Appointment:0x8213";
75
+            $properties["responsestatus"] = "PT_LONG:PSETID_Appointment:0x8218";
76
+            $properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
77
+            $properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
78
+            $properties["recurrencetype"] = "PT_LONG:PSETID_Appointment:0x8231";
79
+            $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
80
+            $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
81
+            $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
82
+            $properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
83
+            $properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
84
+            $properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
85
+            $properties["basedate"] = "PT_SYSTIME:PSETID_Appointment:0x8228";
86
+            $properties["timezone_data"] = "PT_BINARY:PSETID_Appointment:0x8233";
87
+            $properties["timezone"] = "PT_STRING8:PSETID_Appointment:0x8234";
88
+            $properties["flagdueby"] = "PT_SYSTIME:PSETID_Common:0x8560";
89
+            $properties["side_effects"] = "PT_LONG:PSETID_Common:0x8510";
90
+            $properties["hideattachments"] = "PT_BOOLEAN:PSETID_Common:0x8514";
91
+
92
+            $this->proptags = getPropIdsFromStrings($store, $properties);
93
+
94
+            parent::__construct($store, $message);
95
+        }
96
+
97
+        /**
98
+         * Create an exception.
99
+         *
100
+         * @param array        $exception_props  the exception properties (same properties as normal recurring items)
101
+         * @param date         $base_date        the base date of the exception (LOCAL time of non-exception occurrence)
102
+         * @param bool         $delete           true - delete occurrence, false - create new exception or modify existing
103
+         * @param array        $exception_recips true - delete occurrence, false - create new exception or modify existing
104
+         * @param mapi_message $copy_attach_from mapi message from which attachments should be copied
105
+         */
106
+        public function createException($exception_props, $base_date, $delete = false, $exception_recips = [], $copy_attach_from = false) {
107
+            $baseday = $this->dayStartOf($base_date);
108
+            $basetime = $baseday + $this->recur["startocc"] * 60;
109
+
110
+            // Remove any pre-existing exception on this base date
111
+            if ($this->isException($baseday)) {
112
+                $this->deleteException($baseday);
113
+            } // note that deleting an exception is different from creating a deleted exception (deleting an occurrence).
114
+
115
+            if (!$delete) {
116
+                if (isset($exception_props[$this->proptags["startdate"]]) && !$this->isValidExceptionDate($base_date, $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]))) {
117
+                    return false;
118
+                }
119
+                // Properties in the attachment are the properties of the base object, plus $exception_props plus the base date
120
+                foreach (["subject", "location", "label", "reminder", "reminder_minutes", "alldayevent", "busystatus"] as $propname) {
121
+                    if (isset($this->messageprops[$this->proptags[$propname]])) {
122
+                        $props[$this->proptags[$propname]] = $this->messageprops[$this->proptags[$propname]];
123
+                    }
124
+                }
125
+
126
+                $props[PR_MESSAGE_CLASS] = "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}";
127
+                unset($exception_props[PR_MESSAGE_CLASS], $exception_props[PR_ICON_INDEX]);
128
+
129
+                $props = $exception_props + $props;
130
+
131
+                // Basedate in the exception attachment is the GMT time at which the original occurrence would have been
132
+                $props[$this->proptags["basedate"]] = $this->toGMT($this->tz, $basetime);
133
+
134
+                if (!isset($exception_props[$this->proptags["startdate"]])) {
135
+                    $props[$this->proptags["startdate"]] = $this->getOccurrenceStart($base_date);
136
+                }
137
+                if (!isset($exception_props[$this->proptags["duedate"]])) {
138
+                    $props[$this->proptags["duedate"]] = $this->getOccurrenceEnd($base_date);
139
+                }
140
+
141
+                // synchronize commonstart/commonend with startdate/duedate
142
+                if (isset($props[$this->proptags["startdate"]])) {
143
+                    $props[$this->proptags["commonstart"]] = $props[$this->proptags["startdate"]];
144
+                }
145
+                if (isset($props[$this->proptags["duedate"]])) {
146
+                    $props[$this->proptags["commonend"]] = $props[$this->proptags["duedate"]];
147
+                }
148
+
149
+                // Save the data into an attachment
150
+                $this->createExceptionAttachment($props, $exception_recips, $copy_attach_from);
151
+
152
+                $changed_item = [];
153
+
154
+                $changed_item["basedate"] = $baseday;
155
+                $changed_item["start"] = $this->fromGMT($this->tz, $props[$this->proptags["startdate"]]);
156
+                $changed_item["end"] = $this->fromGMT($this->tz, $props[$this->proptags["duedate"]]);
157
+
158
+                if (array_key_exists($this->proptags["subject"], $exception_props)) {
159
+                    $changed_item["subject"] = $exception_props[$this->proptags["subject"]];
160
+                }
161
+                if (array_key_exists($this->proptags["location"], $exception_props)) {
162
+                    $changed_item["location"] = $exception_props[$this->proptags["location"]];
163
+                }
164
+                if (array_key_exists($this->proptags["label"], $exception_props)) {
165
+                    $changed_item["label"] = $exception_props[$this->proptags["label"]];
166
+                }
167
+                if (array_key_exists($this->proptags["reminder"], $exception_props)) {
168
+                    $changed_item["reminder_set"] = $exception_props[$this->proptags["reminder"]];
169
+                }
170
+                if (array_key_exists($this->proptags["reminder_minutes"], $exception_props)) {
171
+                    $changed_item["remind_before"] = $exception_props[$this->proptags["reminder_minutes"]];
172
+                }
173
+                if (array_key_exists($this->proptags["alldayevent"], $exception_props)) {
174
+                    $changed_item["alldayevent"] = $exception_props[$this->proptags["alldayevent"]];
175
+                }
176
+                if (array_key_exists($this->proptags["busystatus"], $exception_props)) {
177
+                    $changed_item["busystatus"] = $exception_props[$this->proptags["busystatus"]];
178
+                }
179
+
180
+                // Add the changed occurrence to the list
181
+                array_push($this->recur["changed_occurrences"], $changed_item);
182
+            }
183
+            else {
184
+                // Delete the occurrence by placing it in the deleted occurrences list
185
+                array_push($this->recur["deleted_occurrences"], $baseday);
186
+            }
187
+
188
+            // Turn on hideattachments, because the attachments in this item are the exceptions
189
+            mapi_setprops($this->message, [$this->proptags["hideattachments"] => true]);
190
+
191
+            // Save recurrence data to message
192
+            $this->saveRecurrence();
193
+
194
+            return true;
195
+        }
196
+
197
+        /**
198
+         * Modifies an existing exception, but only updates the given properties
199
+         * NOTE: You can't remove properties from an exception, only add new ones.
200
+         *
201
+         * @param mixed $exception_props
202
+         * @param mixed $base_date
203
+         * @param mixed $exception_recips
204
+         * @param mixed $copy_attach_from
205
+         */
206
+        public function modifyException($exception_props, $base_date, $exception_recips = [], $copy_attach_from = false) {
207
+            if (isset($exception_props[$this->proptags["startdate"]]) && !$this->isValidExceptionDate($base_date, $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]))) {
208
+                return false;
209
+            }
210
+
211
+            $baseday = $this->dayStartOf($base_date);
212
+            $basetime = $baseday + $this->recur["startocc"] * 60;
213
+            $extomodify = false;
214
+
215
+            for ($i = 0, $len = count($this->recur["changed_occurrences"]); $i < $len; ++$i) {
216
+                if ($this->isSameDay($this->recur["changed_occurrences"][$i]["basedate"], $baseday)) {
217
+                    $extomodify = &$this->recur["changed_occurrences"][$i];
218
+                }
219
+            }
220
+
221
+            if (!$extomodify) {
222
+                return false;
223
+            }
224
+
225
+            // remove basedate property as we want to preserve the old value
226
+            // client will send basedate with time part as zero, so discard that value
227
+            unset($exception_props[$this->proptags["basedate"]]);
228
+
229
+            if (array_key_exists($this->proptags["startdate"], $exception_props)) {
230
+                $extomodify["start"] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]);
231
+            }
232
+            if (array_key_exists($this->proptags["duedate"], $exception_props)) {
233
+                $extomodify["end"] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]);
234
+            }
235
+            if (array_key_exists($this->proptags["subject"], $exception_props)) {
236
+                $extomodify["subject"] = $exception_props[$this->proptags["subject"]];
237
+            }
238
+            if (array_key_exists($this->proptags["location"], $exception_props)) {
239
+                $extomodify["location"] = $exception_props[$this->proptags["location"]];
240
+            }
241
+            if (array_key_exists($this->proptags["label"], $exception_props)) {
242
+                $extomodify["label"] = $exception_props[$this->proptags["label"]];
243
+            }
244
+            if (array_key_exists($this->proptags["reminder"], $exception_props)) {
245
+                $extomodify["reminder_set"] = $exception_props[$this->proptags["reminder"]];
246
+            }
247
+            if (array_key_exists($this->proptags["reminder_minutes"], $exception_props)) {
248
+                $extomodify["remind_before"] = $exception_props[$this->proptags["reminder_minutes"]];
249
+            }
250
+            if (array_key_exists($this->proptags["alldayevent"], $exception_props)) {
251
+                $extomodify["alldayevent"] = $exception_props[$this->proptags["alldayevent"]];
252
+            }
253
+            if (array_key_exists($this->proptags["busystatus"], $exception_props)) {
254
+                $extomodify["busystatus"] = $exception_props[$this->proptags["busystatus"]];
255
+            }
256
+
257
+            $exception_props[PR_MESSAGE_CLASS] = "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}";
258
+
259
+            // synchronize commonstart/commonend with startdate/duedate
260
+            if (isset($exception_props[$this->proptags["startdate"]])) {
261
+                $exception_props[$this->proptags["commonstart"]] = $exception_props[$this->proptags["startdate"]];
262
+            }
263
+            if (isset($exception_props[$this->proptags["duedate"]])) {
264
+                $exception_props[$this->proptags["commonend"]] = $exception_props[$this->proptags["duedate"]];
265
+            }
266
+
267
+            $attach = $this->getExceptionAttachment($baseday);
268
+            if (!$attach) {
269
+                if ($copy_attach_from) {
270
+                    $this->deleteExceptionAttachment($base_date);
271
+                    $this->createException($exception_props, $base_date, false, $exception_recips, $copy_attach_from);
272
+                }
273
+                else {
274
+                    $this->createExceptionAttachment($exception_props, $exception_recips, $copy_attach_from);
275
+                }
276
+            }
277
+            else {
278
+                $message = mapi_attach_openobj($attach, MAPI_MODIFY);
279
+
280
+                // Set exception properties on embedded message and save
281
+                mapi_setprops($message, $exception_props);
282
+                $this->setExceptionRecipients($message, $exception_recips, false);
283
+                mapi_savechanges($message);
284
+
285
+                // If a new start or duedate is provided, we update the properties 'PR_EXCEPTION_STARTTIME' and 'PR_EXCEPTION_ENDTIME'
286
+                // on the attachment which holds the embedded msg and save everything.
287
+                $props = [];
288
+                if (isset($exception_props[$this->proptags["startdate"]])) {
289
+                    $props[PR_EXCEPTION_STARTTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]);
290
+                }
291
+                if (isset($exception_props[$this->proptags["duedate"]])) {
292
+                    $props[PR_EXCEPTION_ENDTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]);
293
+                }
294
+                if (!empty($props)) {
295
+                    mapi_setprops($attach, $props);
296
+                }
297
+                mapi_savechanges($attach);
298
+            }
299
+
300
+            // Save recurrence data to message
301
+            $this->saveRecurrence();
302
+
303
+            return true;
304
+        }
305
+
306
+        // Checks to see if the following is true:
307
+        // 1) The exception to be created doesn't create two exceptions starting on one day (however, they can END on the same day by modifying duration)
308
+        // 2) The exception to be created doesn't 'jump' over another occurrence (which may be an exception itself!)
309
+        //
310
+        // Both $basedate and $start are in LOCAL time
311
+        public function isValidExceptionDate($basedate, $start) {
312
+            // The way we do this is to look at the days that we're 'moving' the item in the exception. Each
313
+            // of these days may only contain the item that we're modifying. Any other item violates the rules.
314
+
315
+            if ($this->isException($basedate)) {
316
+                // If we're modifying an exception, we want to look at the days that we're 'moving' compared to where
317
+                // the exception used to be.
318
+                $oldexception = $this->getChangeException($basedate);
319
+                $prevday = $this->dayStartOf($oldexception["start"]);
320
+            }
321
+            else {
322
+                // If its a new exception, we want to look at the original placement of this item.
323
+                $prevday = $basedate;
324
+            }
325
+
326
+            $startday = $this->dayStartOf($start);
327
+
328
+            // Get all the occurrences on the days between the basedate (may be reversed)
329
+            if ($prevday < $startday) {
330
+                $items = $this->getItems($this->toGMT($this->tz, $prevday), $this->toGMT($this->tz, $startday + 24 * 60 * 60));
331
+            }
332
+            else {
333
+                $items = $this->getItems($this->toGMT($this->tz, $startday), $this->toGMT($this->tz, $prevday + 24 * 60 * 60));
334
+            }
335
+
336
+            // There should now be exactly one item, namely the item that we are modifying. If there are any other items in the range,
337
+            // then we abort the change, since one of the rules has been violated.
338
+            return count($items) == 1;
339
+        }
340
+
341
+        /**
342
+         * Check to see if the exception proposed at a certain basedate is allowed concerning reminder times:.
343
+         *
344
+         * Both must be true:
345
+         * - reminder time of this item is not before the starttime of the previous recurring item
346
+         * - reminder time of the next item is not before the starttime of this item
347
+         *
348
+         * @param date   $basedate        the base date of the exception (LOCAL time of non-exception occurrence)
349
+         * @param string $reminderminutes reminder minutes which is set of the item
350
+         * @param date   $startdate       the startdate of the selected item
351
+         * @returns boolean if the reminder minutes value valid (FALSE if either of the rules above are FALSE)
352
+         */
353
+        public function isValidReminderTime($basedate, $reminderminutes, $startdate) {
354
+            $isreminderrangeset = false;
355
+
356
+            // get all occurrence items before the seleceted items occurrence starttime
357
+            $occitems = $this->getItems($this->messageprops[$this->proptags["startdate"]], $this->toGMT($this->tz, $basedate));
358
+
359
+            if (!empty($occitems)) {
360
+                // as occitems array is sorted in ascending order of startdate, to get the previous occurrence we take the last items in occitems .
361
+                $previousitem_startdate = $occitems[count($occitems) - 1][$this->proptags["startdate"]];
362
+
363
+                // if our reminder is set before or equal to the beginning of the previous occurrence, then that's not allowed
364
+                if ($startdate - ($reminderminutes * 60) <= $previousitem_startdate) {
365
+                    return false;
366
+                }
367
+            }
368
+
369
+            // Get the endtime of the current occurrence and find the next two occurrences (including the current occurrence)
370
+            $currentOcc = $this->getItems($this->toGMT($this->tz, $basedate), 0x7FF00000, 2, true);
371
+
372
+            // If there are another two occurrences, then the first is the current occurrence, and the one after that
373
+            // is the next occurrence.
374
+            if (count($currentOcc) > 1) {
375
+                $next = $currentOcc[1];
376
+                // Get reminder time of the next occurrence.
377
+                $nextOccReminderTime = $next[$this->proptags["startdate"]] - ($next[$this->proptags["reminder_minutes"]] * 60);
378
+                // If the reminder time of the next item is before the start of this item, then that's not allowed
379
+                if ($nextOccReminderTime <= $startdate) {
380
+                    return false;
381
+                }
382
+            }
383
+
384
+            // All was ok
385
+            return true;
386
+        }
387
+
388
+        public function setRecurrence($tz, $recur) {
389
+            // only reset timezone if specified
390
+            if ($tz) {
391
+                $this->tz = $tz;
392
+            }
393
+
394
+            $this->recur = $recur;
395
+
396
+            if (!isset($this->recur["changed_occurrences"])) {
397
+                $this->recur["changed_occurrences"] = [];
398
+            }
399
+
400
+            if (!isset($this->recur["deleted_occurrences"])) {
401
+                $this->recur["deleted_occurrences"] = [];
402
+            }
403
+
404
+            $this->deleteAttachments();
405
+            $this->saveRecurrence();
406
+
407
+            // if client has not set the recurring_pattern then we should generate it and save it
408
+            $messageProps = mapi_getprops($this->message, [$this->proptags["recurring_pattern"]]);
409
+            if (empty($messageProps[$this->proptags["recurring_pattern"]])) {
410
+                $this->saveRecurrencePattern();
411
+            }
412
+        }
413
+
414
+        // Returns the start or end time of the occurrence on the given base date.
415
+        // This assumes that the basedate you supply is in LOCAL time
416
+        public function getOccurrenceStart($basedate) {
417
+            $daystart = $this->dayStartOf($basedate);
418
+
419
+            return $this->toGMT($this->tz, $daystart + $this->recur["startocc"] * 60);
420
+        }
421
+
422
+        public function getOccurrenceEnd($basedate) {
423
+            $daystart = $this->dayStartOf($basedate);
424
+
425
+            return $this->toGMT($this->tz, $daystart + $this->recur["endocc"] * 60);
426
+        }
427
+
428
+        // Backwards compatible code
429
+        public function getOccurenceStart($basedate) {
430
+            return $this->getOccurrenceStart($basedate);
431
+        }
432
+
433
+        public function getOccurenceEnd($basedate) {
434
+            return $this->getOccurrenceEnd($basedate);
435
+        }
436
+
437
+        /**
438
+         * This function returns the next remindertime starting from $timestamp
439
+         * When no next reminder exists, false is returned.
440
+         *
441
+         * Note: Before saving this new reminder time (when snoozing), you must check for
442
+         *       yourself if this reminder time is earlier than your snooze time, else
443
+         *       use your snooze time and not this reminder time.
444
+         *
445
+         * @param mixed $timestamp
446
+         */
447
+        public function getNextReminderTime($timestamp) {
448
+            /**
449
+             * Get next item from now until forever, but max 1 item with reminder set
450
+             * Note 0x7ff00000 instead of 0x7fffffff because of possible overflow failures when converting to GMT....
451
+             * Here for getting next 10 occurrences assuming that next here we will be able to find
452
+             * nextreminder occurrence in 10 occureneces.
453
+             */
454
+            $items = $this->getItems($timestamp, 0x7FF00000, 10, true);
455
+
456
+            // Initially setting nextreminder to false so when no next reminder exists, false is returned.
457
+            $nextreminder = false;
458
+            /*
459 459
 			 * Loop through all reminder which we get in items variable
460 460
 			 * and check whether the remindertime is greater than timestamp.
461 461
 			 * On the first occurrence of greater nextreminder break the loop
462 462
 			 * and return the value to calling function.
463 463
 			 */
464
-			for ($i = 0, $len = count($items); $i < $len; ++$i) {
465
-				$item = $items[$i];
466
-				$tempnextreminder = $item[$this->proptags["startdate"]] - ($item[$this->proptags["reminder_minutes"]] * 60);
467
-
468
-				// If tempnextreminder is greater than timestamp then save it in nextreminder and break from the loop.
469
-				if ($tempnextreminder > $timestamp) {
470
-					$nextreminder = $tempnextreminder;
471
-
472
-					break;
473
-				}
474
-			}
475
-
476
-			return $nextreminder;
477
-		}
478
-
479
-		/**
480
-		 * Note: Static function, more like a utility function.
481
-		 *
482
-		 * Gets all the items (including recurring items) in the specified calendar in the given timeframe. Items are
483
-		 * included as a whole if they overlap the interval <$start, $end> (non-inclusive). This means that if the interval
484
-		 * is <08:00 - 14:00>, the item [6:00 - 8:00> is NOT included, nor is the item [14:00 - 16:00>. However, the item
485
-		 * [7:00 - 9:00> is included as a whole, and is NOT capped to [8:00 - 9:00>.
486
-		 *
487
-		 * @param $store resource The store in which the calendar resides
488
-		 * @param $calendar resource The calendar to get the items from
489
-		 * @param $viewstart int Timestamp of beginning of view window
490
-		 * @param $viewend int Timestamp of end of view window
491
-		 * @param $propsrequested array Array of properties to return
492
-		 * @param $rows array Array of rowdata as if they were returned directly from mapi_table_queryrows. Each recurring item is
493
-		 *                    expanded so that it seems that there are only many single appointments in the table.
494
-		 */
495
-		public static function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested) {
496
-			return getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested);
497
-		}
498
-
499
-		/*
464
+            for ($i = 0, $len = count($items); $i < $len; ++$i) {
465
+                $item = $items[$i];
466
+                $tempnextreminder = $item[$this->proptags["startdate"]] - ($item[$this->proptags["reminder_minutes"]] * 60);
467
+
468
+                // If tempnextreminder is greater than timestamp then save it in nextreminder and break from the loop.
469
+                if ($tempnextreminder > $timestamp) {
470
+                    $nextreminder = $tempnextreminder;
471
+
472
+                    break;
473
+                }
474
+            }
475
+
476
+            return $nextreminder;
477
+        }
478
+
479
+        /**
480
+         * Note: Static function, more like a utility function.
481
+         *
482
+         * Gets all the items (including recurring items) in the specified calendar in the given timeframe. Items are
483
+         * included as a whole if they overlap the interval <$start, $end> (non-inclusive). This means that if the interval
484
+         * is <08:00 - 14:00>, the item [6:00 - 8:00> is NOT included, nor is the item [14:00 - 16:00>. However, the item
485
+         * [7:00 - 9:00> is included as a whole, and is NOT capped to [8:00 - 9:00>.
486
+         *
487
+         * @param $store resource The store in which the calendar resides
488
+         * @param $calendar resource The calendar to get the items from
489
+         * @param $viewstart int Timestamp of beginning of view window
490
+         * @param $viewend int Timestamp of end of view window
491
+         * @param $propsrequested array Array of properties to return
492
+         * @param $rows array Array of rowdata as if they were returned directly from mapi_table_queryrows. Each recurring item is
493
+         *                    expanded so that it seems that there are only many single appointments in the table.
494
+         */
495
+        public static function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested) {
496
+            return getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested);
497
+        }
498
+
499
+        /*
500 500
 		 * CODE BELOW THIS LINE IS FOR INTERNAL USE ONLY
501 501
 		 *****************************************************************************************************************
502 502
 		 */
503 503
 
504
-		/**
505
-		 * Generates and stores recurrence pattern string to recurring_pattern property.
506
-		 */
507
-		public function saveRecurrencePattern() {
508
-			// Start formatting the properties in such a way we can apply
509
-			// them directly into the recurrence pattern.
510
-			$type = $this->recur['type'];
511
-			$everyn = $this->recur['everyn'];
512
-			$start = $this->recur['start'];
513
-			$end = $this->recur['end'];
514
-			$term = $this->recur['term'];
515
-			$numocc = isset($this->recur['numoccur']) ? $this->recur['numoccur'] : false;
516
-			$startocc = $this->recur['startocc'];
517
-			$endocc = $this->recur['endocc'];
518
-			$pattern = '';
519
-			$occSingleDayRank = false;
520
-			$occTimeRange = ($startocc != 0 && $endocc != 0);
521
-
522
-			switch ($type) {
523
-				// Daily
524
-				case 0x0A:
525
-					if ($everyn == 1) {
526
-						$type = dgettext("kopano", "workday");
527
-						$occSingleDayRank = true;
528
-					}
529
-					elseif ($everyn == (24 * 60)) {
530
-						$type = dgettext("kopano", "day");
531
-						$occSingleDayRank = true;
532
-					}
533
-					else {
534
-						$everyn /= (24 * 60);
535
-						$type = dgettext("kopano", "days");
536
-						$occSingleDayRank = false;
537
-					}
538
-					break;
539
-				// Weekly
540
-				case 0x0B:
541
-					if ($everyn == 1) {
542
-						$type = dgettext("kopano", "week");
543
-						$occSingleDayRank = true;
544
-					}
545
-					else {
546
-						$type = dgettext("kopano", "weeks");
547
-						$occSingleDayRank = false;
548
-					}
549
-					break;
550
-				// Monthly
551
-				case 0x0C:
552
-					if ($everyn == 1) {
553
-						$type = dgettext("kopano", "month");
554
-						$occSingleDayRank = true;
555
-					}
556
-					else {
557
-						$type = dgettext("kopano", "months");
558
-						$occSingleDayRank = false;
559
-					}
560
-					break;
561
-				// Yearly
562
-				case 0x0D:
563
-					if ($everyn <= 12) {
564
-						$everyn = 1;
565
-						$type = dgettext("kopano", "year");
566
-						$occSingleDayRank = true;
567
-					}
568
-					else {
569
-						$everyn = $everyn / 12;
570
-						$type = dgettext("kopano", "years");
571
-						$occSingleDayRank = false;
572
-					}
573
-					break;
574
-			}
575
-
576
-			// get timings of the first occurrence
577
-			$firstoccstartdate = isset($startocc) ? $start + (((int) $startocc) * 60) : $start;
578
-			$firstoccenddate = isset($endocc) ? $end + (((int) $endocc) * 60) : $end;
579
-
580
-			$start = gmdate(dgettext("kopano", "d-m-Y"), $firstoccstartdate);
581
-			$end = gmdate(dgettext("kopano", "d-m-Y"), $firstoccenddate);
582
-			$startocc = gmdate(dgettext("kopano", "G:i"), $firstoccstartdate);
583
-			$endocc = gmdate(dgettext("kopano", "G:i"), $firstoccenddate);
584
-
585
-			// Based on the properties, we need to generate the recurrence pattern string.
586
-			// This is obviously very easy since we can simply concatenate a bunch of strings,
587
-			// however this messes up translations for languages which order their words
588
-			// differently.
589
-			// To improve translation quality we create a series of default strings, in which
590
-			// we only have to fill in the correct variables. The base string is thus selected
591
-			// based on the available properties.
592
-			if ($term == 0x23) {
593
-				// Never ends
594
-				if ($occTimeRange) {
595
-					if ($occSingleDayRank) {
596
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s from %s to %s."), $type, $start, $startocc, $endocc);
597
-					}
598
-					else {
599
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s from %s to %s."), $everyn, $type, $start, $startocc, $endocc);
600
-					}
601
-				}
602
-				else {
603
-					if ($occSingleDayRank) {
604
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s."), $type, $start);
605
-					}
606
-					else {
607
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s."), $everyn, $type, $start);
608
-					}
609
-				}
610
-			}
611
-			elseif ($term == 0x22) {
612
-				// After a number of times
613
-				if ($occTimeRange) {
614
-					if ($occSingleDayRank) {
615
-						$pattern = sprintf(dngettext(
616
-							"kopano",
617
-							"Occurs every %s effective %s for %s occurrence from %s to %s.",
618
-							"Occurs every %s effective %s for %s occurrences from %s to %s.",
619
-							$numocc
620
-						), $type, $start, $numocc, $startocc, $endocc);
621
-					}
622
-					else {
623
-						$pattern = sprintf(dngettext(
624
-							"kopano",
625
-							"Occurs every %s %s effective %s for %s occurrence from %s to %s.",
626
-							"Occurs every %s %s effective %s for %s occurrences %s to %s.",
627
-							$numocc
628
-						), $everyn, $type, $start, $numocc, $startocc, $endocc);
629
-					}
630
-				}
631
-				else {
632
-					if ($occSingleDayRank) {
633
-						$pattern = sprintf(dngettext(
634
-							"kopano",
635
-							"Occurs every %s effective %s for %s occurrence.",
636
-							"Occurs every %s effective %s for %s occurrences.",
637
-							$numocc
638
-						), $type, $start, $numocc);
639
-					}
640
-					else {
641
-						$pattern = sprintf(dngettext(
642
-							"kopano",
643
-							"Occurs every %s %s effective %s for %s occurrence.",
644
-							"Occurs every %s %s effective %s for %s occurrences.",
645
-							$numocc
646
-						), $everyn, $type, $start, $numocc);
647
-					}
648
-				}
649
-			}
650
-			elseif ($term == 0x21) {
651
-				// After the given enddate
652
-				if ($occTimeRange) {
653
-					if ($occSingleDayRank) {
654
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s until %s from %s to %s."), $type, $start, $end, $startocc, $endocc);
655
-					}
656
-					else {
657
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s until %s from %s to %s."), $everyn, $type, $start, $end, $startocc, $endocc);
658
-					}
659
-				}
660
-				else {
661
-					if ($occSingleDayRank) {
662
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s until %s."), $type, $start, $end);
663
-					}
664
-					else {
665
-						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s until %s."), $everyn, $type, $start, $end);
666
-					}
667
-				}
668
-			}
669
-			if (!empty($pattern)) {
670
-				mapi_setprops($this->message, [$this->proptags["recurring_pattern"] => $pattern]);
671
-			}
672
-		}
673
-
674
-		/*
504
+        /**
505
+         * Generates and stores recurrence pattern string to recurring_pattern property.
506
+         */
507
+        public function saveRecurrencePattern() {
508
+            // Start formatting the properties in such a way we can apply
509
+            // them directly into the recurrence pattern.
510
+            $type = $this->recur['type'];
511
+            $everyn = $this->recur['everyn'];
512
+            $start = $this->recur['start'];
513
+            $end = $this->recur['end'];
514
+            $term = $this->recur['term'];
515
+            $numocc = isset($this->recur['numoccur']) ? $this->recur['numoccur'] : false;
516
+            $startocc = $this->recur['startocc'];
517
+            $endocc = $this->recur['endocc'];
518
+            $pattern = '';
519
+            $occSingleDayRank = false;
520
+            $occTimeRange = ($startocc != 0 && $endocc != 0);
521
+
522
+            switch ($type) {
523
+                // Daily
524
+                case 0x0A:
525
+                    if ($everyn == 1) {
526
+                        $type = dgettext("kopano", "workday");
527
+                        $occSingleDayRank = true;
528
+                    }
529
+                    elseif ($everyn == (24 * 60)) {
530
+                        $type = dgettext("kopano", "day");
531
+                        $occSingleDayRank = true;
532
+                    }
533
+                    else {
534
+                        $everyn /= (24 * 60);
535
+                        $type = dgettext("kopano", "days");
536
+                        $occSingleDayRank = false;
537
+                    }
538
+                    break;
539
+                // Weekly
540
+                case 0x0B:
541
+                    if ($everyn == 1) {
542
+                        $type = dgettext("kopano", "week");
543
+                        $occSingleDayRank = true;
544
+                    }
545
+                    else {
546
+                        $type = dgettext("kopano", "weeks");
547
+                        $occSingleDayRank = false;
548
+                    }
549
+                    break;
550
+                // Monthly
551
+                case 0x0C:
552
+                    if ($everyn == 1) {
553
+                        $type = dgettext("kopano", "month");
554
+                        $occSingleDayRank = true;
555
+                    }
556
+                    else {
557
+                        $type = dgettext("kopano", "months");
558
+                        $occSingleDayRank = false;
559
+                    }
560
+                    break;
561
+                // Yearly
562
+                case 0x0D:
563
+                    if ($everyn <= 12) {
564
+                        $everyn = 1;
565
+                        $type = dgettext("kopano", "year");
566
+                        $occSingleDayRank = true;
567
+                    }
568
+                    else {
569
+                        $everyn = $everyn / 12;
570
+                        $type = dgettext("kopano", "years");
571
+                        $occSingleDayRank = false;
572
+                    }
573
+                    break;
574
+            }
575
+
576
+            // get timings of the first occurrence
577
+            $firstoccstartdate = isset($startocc) ? $start + (((int) $startocc) * 60) : $start;
578
+            $firstoccenddate = isset($endocc) ? $end + (((int) $endocc) * 60) : $end;
579
+
580
+            $start = gmdate(dgettext("kopano", "d-m-Y"), $firstoccstartdate);
581
+            $end = gmdate(dgettext("kopano", "d-m-Y"), $firstoccenddate);
582
+            $startocc = gmdate(dgettext("kopano", "G:i"), $firstoccstartdate);
583
+            $endocc = gmdate(dgettext("kopano", "G:i"), $firstoccenddate);
584
+
585
+            // Based on the properties, we need to generate the recurrence pattern string.
586
+            // This is obviously very easy since we can simply concatenate a bunch of strings,
587
+            // however this messes up translations for languages which order their words
588
+            // differently.
589
+            // To improve translation quality we create a series of default strings, in which
590
+            // we only have to fill in the correct variables. The base string is thus selected
591
+            // based on the available properties.
592
+            if ($term == 0x23) {
593
+                // Never ends
594
+                if ($occTimeRange) {
595
+                    if ($occSingleDayRank) {
596
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s from %s to %s."), $type, $start, $startocc, $endocc);
597
+                    }
598
+                    else {
599
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s from %s to %s."), $everyn, $type, $start, $startocc, $endocc);
600
+                    }
601
+                }
602
+                else {
603
+                    if ($occSingleDayRank) {
604
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s."), $type, $start);
605
+                    }
606
+                    else {
607
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s."), $everyn, $type, $start);
608
+                    }
609
+                }
610
+            }
611
+            elseif ($term == 0x22) {
612
+                // After a number of times
613
+                if ($occTimeRange) {
614
+                    if ($occSingleDayRank) {
615
+                        $pattern = sprintf(dngettext(
616
+                            "kopano",
617
+                            "Occurs every %s effective %s for %s occurrence from %s to %s.",
618
+                            "Occurs every %s effective %s for %s occurrences from %s to %s.",
619
+                            $numocc
620
+                        ), $type, $start, $numocc, $startocc, $endocc);
621
+                    }
622
+                    else {
623
+                        $pattern = sprintf(dngettext(
624
+                            "kopano",
625
+                            "Occurs every %s %s effective %s for %s occurrence from %s to %s.",
626
+                            "Occurs every %s %s effective %s for %s occurrences %s to %s.",
627
+                            $numocc
628
+                        ), $everyn, $type, $start, $numocc, $startocc, $endocc);
629
+                    }
630
+                }
631
+                else {
632
+                    if ($occSingleDayRank) {
633
+                        $pattern = sprintf(dngettext(
634
+                            "kopano",
635
+                            "Occurs every %s effective %s for %s occurrence.",
636
+                            "Occurs every %s effective %s for %s occurrences.",
637
+                            $numocc
638
+                        ), $type, $start, $numocc);
639
+                    }
640
+                    else {
641
+                        $pattern = sprintf(dngettext(
642
+                            "kopano",
643
+                            "Occurs every %s %s effective %s for %s occurrence.",
644
+                            "Occurs every %s %s effective %s for %s occurrences.",
645
+                            $numocc
646
+                        ), $everyn, $type, $start, $numocc);
647
+                    }
648
+                }
649
+            }
650
+            elseif ($term == 0x21) {
651
+                // After the given enddate
652
+                if ($occTimeRange) {
653
+                    if ($occSingleDayRank) {
654
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s until %s from %s to %s."), $type, $start, $end, $startocc, $endocc);
655
+                    }
656
+                    else {
657
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s until %s from %s to %s."), $everyn, $type, $start, $end, $startocc, $endocc);
658
+                    }
659
+                }
660
+                else {
661
+                    if ($occSingleDayRank) {
662
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s until %s."), $type, $start, $end);
663
+                    }
664
+                    else {
665
+                        $pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s until %s."), $everyn, $type, $start, $end);
666
+                    }
667
+                }
668
+            }
669
+            if (!empty($pattern)) {
670
+                mapi_setprops($this->message, [$this->proptags["recurring_pattern"] => $pattern]);
671
+            }
672
+        }
673
+
674
+        /*
675 675
 		 * Remove an exception by base_date. This is the base date in local daystart time
676 676
 		 */
677
-		public function deleteException($base_date) {
678
-			// Remove all exceptions on $base_date from the deleted and changed occurrences lists
679
-
680
-			// Remove all items in $todelete from deleted_occurrences
681
-			$new = [];
682
-
683
-			foreach ($this->recur["deleted_occurrences"] as $entry) {
684
-				if ($entry != $base_date) {
685
-					$new[] = $entry;
686
-				}
687
-			}
688
-
689
-			$this->recur["deleted_occurrences"] = $new;
690
-
691
-			$new = [];
692
-
693
-			foreach ($this->recur["changed_occurrences"] as $entry) {
694
-				if (!$this->isSameDay($entry["basedate"], $base_date)) {
695
-					$new[] = $entry;
696
-				}
697
-				else {
698
-					$this->deleteExceptionAttachment($this->toGMT($this->tz, $base_date + $this->recur["startocc"] * 60));
699
-				}
700
-			}
701
-
702
-			$this->recur["changed_occurrences"] = $new;
703
-		}
704
-
705
-		/**
706
-		 * Function which saves the exception data in an attachment.
707
-		 *
708
-		 * @param array        $exception_props  the exception data (like any other MAPI appointment)
709
-		 * @param array        $exception_recips list of recipients
710
-		 * @param mapi_message $copy_attach_from mapi message from which attachments should be copied
711
-		 *
712
-		 * @return array properties of the exception
713
-		 */
714
-		public function createExceptionAttachment($exception_props, $exception_recips = [], $copy_attach_from = false) {
715
-			// Create new attachment.
716
-			$attachment = mapi_message_createattach($this->message);
717
-			$props = [];
718
-			$props[PR_ATTACHMENT_FLAGS] = 2;
719
-			$props[PR_ATTACHMENT_HIDDEN] = true;
720
-			$props[PR_ATTACHMENT_LINKID] = 0;
721
-			$props[PR_ATTACH_FLAGS] = 0;
722
-			$props[PR_ATTACH_METHOD] = 5;
723
-			$props[PR_DISPLAY_NAME] = "Exception";
724
-			$props[PR_EXCEPTION_STARTTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]);
725
-			$props[PR_EXCEPTION_ENDTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]);
726
-			mapi_setprops($attachment, $props);
727
-
728
-			$imessage = mapi_attach_openobj($attachment, MAPI_CREATE | MAPI_MODIFY);
729
-
730
-			if ($copy_attach_from) {
731
-				$attachmentTable = mapi_message_getattachmenttable($copy_attach_from);
732
-				if ($attachmentTable) {
733
-					$attachments = mapi_table_queryallrows($attachmentTable, [PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD]);
734
-
735
-					foreach ($attachments as $attach_props) {
736
-						$attach_old = mapi_message_openattach($copy_attach_from, (int) $attach_props[PR_ATTACH_NUM]);
737
-						$attach_newResourceMsg = mapi_message_createattach($imessage);
738
-						mapi_copyto($attach_old, [], [], $attach_newResourceMsg, 0);
739
-						mapi_savechanges($attach_newResourceMsg);
740
-					}
741
-				}
742
-			}
743
-
744
-			$props = $props + $exception_props;
745
-
746
-			// FIXME: the following piece of code is written to fix the creation
747
-			// of an exception. This is only a quickfix as it is not yet possible
748
-			// to change an existing exception.
749
-			// remove mv properties when needed
750
-			foreach ($props as $propTag => $propVal) {
751
-				if (mapi_prop_type($propTag) & MV_FLAG && is_null($propVal)) {
752
-					unset($props[$propTag]);
753
-				}
754
-			}
755
-
756
-			mapi_setprops($imessage, $props);
757
-
758
-			$this->setExceptionRecipients($imessage, $exception_recips, true);
759
-
760
-			mapi_savechanges($imessage);
761
-			mapi_savechanges($attachment);
762
-		}
763
-
764
-		/**
765
-		 * Function which deletes the attachment of an exception.
766
-		 *
767
-		 * @param date $base_date base date of the attachment. Should be in GMT. The attachment
768
-		 *                        actually saves the real time of the original date, so we have
769
-		 *                        to check whether it's on the same day.
770
-		 */
771
-		public function deleteExceptionAttachment($base_date) {
772
-			$attachments = mapi_message_getattachmenttable($this->message);
773
-			$attachTable = mapi_table_queryallrows($attachments, [PR_ATTACH_NUM]);
774
-
775
-			foreach ($attachTable as $attachRow) {
776
-				$tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]);
777
-				$exception = mapi_attach_openobj($tempattach);
778
-
779
-				$data = mapi_message_getprops($exception, [$this->proptags["basedate"]]);
780
-				if ($this->dayStartOf($this->fromGMT($this->tz, $data[$this->proptags["basedate"]])) == $this->dayStartOf($base_date)) {
781
-					mapi_message_deleteattach($this->message, $attachRow[PR_ATTACH_NUM]);
782
-				}
783
-			}
784
-		}
785
-
786
-		/**
787
-		 * Function which deletes all attachments of a message.
788
-		 */
789
-		public function deleteAttachments() {
790
-			$attachments = mapi_message_getattachmenttable($this->message);
791
-			$attachTable = mapi_table_queryallrows($attachments, [PR_ATTACH_NUM, PR_ATTACHMENT_HIDDEN]);
792
-
793
-			foreach ($attachTable as $attachRow) {
794
-				if (isset($attachRow[PR_ATTACHMENT_HIDDEN]) && $attachRow[PR_ATTACHMENT_HIDDEN]) {
795
-					mapi_message_deleteattach($this->message, $attachRow[PR_ATTACH_NUM]);
796
-				}
797
-			}
798
-		}
799
-
800
-		/**
801
-		 * Get an exception attachment based on its basedate.
802
-		 *
803
-		 * @param mixed $base_date
804
-		 */
805
-		public function getExceptionAttachment($base_date) {
806
-			// Retrieve only embedded messages
807
-			$attach_res = [RES_AND,
808
-				[
809
-					[RES_PROPERTY,
810
-						[RELOP => RELOP_EQ,
811
-							ULPROPTAG => PR_ATTACH_METHOD,
812
-							VALUE => [PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG],
813
-						],
814
-					],
815
-				],
816
-			];
817
-			$attachments = mapi_message_getattachmenttable($this->message);
818
-			$attachRows = mapi_table_queryallrows($attachments, [PR_ATTACH_NUM], $attach_res);
819
-
820
-			if (is_array($attachRows)) {
821
-				foreach ($attachRows as $attachRow) {
822
-					$tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]);
823
-					$exception = mapi_attach_openobj($tempattach);
824
-
825
-					$data = mapi_message_getprops($exception, [$this->proptags["basedate"]]);
826
-
827
-					if (isset($data[$this->proptags["basedate"]]) && $this->isSameDay($this->fromGMT($this->tz, $data[$this->proptags["basedate"]]), $base_date)) {
828
-						return $tempattach;
829
-					}
830
-				}
831
-			}
832
-
833
-			return false;
834
-		}
835
-
836
-		/**
837
-		 * processOccurrenceItem, adds an item to a list of occurrences, but only if the following criteria are met:
838
-		 * - The resulting occurrence (or exception) starts or ends in the interval <$start, $end>
839
-		 * - The ocurrence isn't specified as a deleted occurrence.
840
-		 *
841
-		 * @param array $items        reference to the array to be added to
842
-		 * @param date  $start        start of timeframe in GMT TIME
843
-		 * @param date  $end          end of timeframe in GMT TIME
844
-		 * @param date  $basedate     (hour/sec/min assumed to be 00:00:00) in LOCAL TIME OF THE OCCURRENCE
845
-		 * @param int   $startocc     start of occurrence since beginning of day in minutes
846
-		 * @param int   $endocc       end of occurrence since beginning of day in minutes
847
-		 * @param int   $tz           the timezone info for this occurrence ( applied to $basedate / $startocc / $endocc )
848
-		 * @param bool  $reminderonly If TRUE, only add the item if the reminder is set
849
-		 */
850
-		public function processOccurrenceItem(&$items, $start, $end, $basedate, $startocc, $endocc, $tz, $reminderonly) {
851
-			$exception = $this->isException($basedate);
852
-			if ($exception) {
853
-				return false;
854
-			}
855
-			$occstart = $basedate + $startocc * 60;
856
-			$occend = $basedate + $endocc * 60;
857
-
858
-			// Convert to GMT
859
-			$occstart = $this->toGMT($tz, $occstart);
860
-			$occend = $this->toGMT($tz, $occend);
861
-
862
-			/**
863
-			 * FIRST PART : Check range criterium. Exact matches (eg when $occstart == $end), do NOT match since you cannot
864
-			 * see any part of the appointment. Partial overlaps DO match.
865
-			 *
866
-			 * SECOND PART : check if occurrence is not a zero duration occurrence which
867
-			 * starts at 00:00 and ends on 00:00. if it is so, then process
868
-			 * the occurrence and send it in response.
869
-			 */
870
-			if (($occstart >= $end || $occend <= $start) && !($occstart == $occend && $occstart == $start)) {
871
-				return;
872
-			}
873
-
874
-			// Properties for this occurrence are the same as the main object,
875
-			// With these properties overridden
876
-			$newitem = $this->messageprops;
877
-			$newitem[$this->proptags["startdate"]] = $occstart;
878
-			$newitem[$this->proptags["duedate"]] = $occend;
879
-			$newitem[$this->proptags["commonstart"]] = $occstart;
880
-			$newitem[$this->proptags["commonend"]] = $occend;
881
-			$newitem["basedate"] = $basedate;
882
-
883
-			// If reminderonly is set, only add reminders
884
-			if ($reminderonly && (!isset($newitem[$this->proptags["reminder"]]) || $newitem[$this->proptags["reminder"]] == false)) {
885
-				return;
886
-			}
887
-
888
-			$items[] = $newitem;
889
-		}
890
-
891
-		/**
892
-		 * processExceptionItem, adds an all exception item to a list of occurrences, without any constraint on timeframe.
893
-		 *
894
-		 * @param array $items reference to the array to be added to
895
-		 * @param date  $start start of timeframe in GMT TIME
896
-		 * @param date  $end   end of timeframe in GMT TIME
897
-		 */
898
-		public function processExceptionItems(&$items, $start, $end) {
899
-			$limit = 0;
900
-			foreach ($this->recur["changed_occurrences"] as $exception) {
901
-				// Convert to GMT
902
-				$occstart = $this->toGMT($this->tz, $exception["start"]);
903
-				$occend = $this->toGMT($this->tz, $exception["end"]);
904
-
905
-				// Check range criterium. Exact matches (eg when $occstart == $end), do NOT match since you cannot
906
-				// see any part of the appointment. Partial overlaps DO match.
907
-				if ($occstart >= $end || $occend <= $start) {
908
-					continue;
909
-				}
910
-
911
-				array_push($items, $this->getExceptionProperties($exception));
912
-				if ($limit && (count($items) == $limit)) {
913
-					break;
914
-				}
915
-			}
916
-		}
917
-
918
-		/**
919
-		 * Function which verifies if on the given date an exception, delete or change, occurs.
920
-		 *
921
-		 * @param date  $date     the date
922
-		 * @param mixed $basedate
923
-		 *
924
-		 * @return array the exception, true - if an occurrence is deleted on the given date, false - no exception occurs on the given date
925
-		 */
926
-		public function isException($basedate) {
927
-			if ($this->isDeleteException($basedate)) {
928
-				return true;
929
-			}
930
-
931
-			if ($this->getChangeException($basedate) != false) {
932
-				return true;
933
-			}
934
-
935
-			return false;
936
-		}
937
-
938
-		/**
939
-		 * Returns TRUE if there is a DELETE exception on the given base date.
940
-		 *
941
-		 * @param mixed $basedate
942
-		 */
943
-		public function isDeleteException($basedate) {
944
-			// Check if the occurrence is deleted on the specified date
945
-			foreach ($this->recur["deleted_occurrences"] as $deleted) {
946
-				if ($this->isSameDay($deleted, $basedate)) {
947
-					return true;
948
-				}
949
-			}
950
-
951
-			return false;
952
-		}
953
-
954
-		/**
955
-		 * Returns the exception if there is a CHANGE exception on the given base date, or FALSE otherwise.
956
-		 *
957
-		 * @param mixed $basedate
958
-		 */
959
-		public function getChangeException($basedate) {
960
-			// Check if the occurrence is modified on the specified date
961
-			foreach ($this->recur["changed_occurrences"] as $changed) {
962
-				if ($this->isSameDay($changed["basedate"], $basedate)) {
963
-					return $changed;
964
-				}
965
-			}
966
-
967
-			return false;
968
-		}
969
-
970
-		/**
971
-		 * Function to see if two dates are on the same day.
972
-		 *
973
-		 * @param date  $time1 date 1
974
-		 * @param date  $time2 date 2
975
-		 * @param mixed $date1
976
-		 * @param mixed $date2
977
-		 *
978
-		 * @return bool Returns TRUE when both dates are on the same day
979
-		 */
980
-		public function isSameDay($date1, $date2) {
981
-			$time1 = $this->gmtime($date1);
982
-			$time2 = $this->gmtime($date2);
983
-
984
-			return $time1["tm_mon"] == $time2["tm_mon"] && $time1["tm_year"] == $time2["tm_year"] && $time1["tm_mday"] == $time2["tm_mday"];
985
-		}
986
-
987
-		/**
988
-		 * Function to get all properties of a single changed exception.
989
-		 *
990
-		 * @param date  $date      base date of exception
991
-		 * @param mixed $exception
992
-		 *
993
-		 * @return array associative array of properties for the exception, compatible with
994
-		 */
995
-		public function getExceptionProperties($exception) {
996
-			// Exception has same properties as main object, with some properties overridden:
997
-			$item = $this->messageprops;
998
-
999
-			// Special properties
1000
-			$item["exception"] = true;
1001
-			$item["basedate"] = $exception["basedate"]; // note that the basedate is always in local time !
1002
-
1003
-			// MAPI-compatible properties (you can handle an exception as a normal calendar item like this)
1004
-			$item[$this->proptags["startdate"]] = $this->toGMT($this->tz, $exception["start"]);
1005
-			$item[$this->proptags["duedate"]] = $this->toGMT($this->tz, $exception["end"]);
1006
-			$item[$this->proptags["commonstart"]] = $item[$this->proptags["startdate"]];
1007
-			$item[$this->proptags["commonend"]] = $item[$this->proptags["duedate"]];
1008
-
1009
-			if (isset($exception["subject"])) {
1010
-				$item[$this->proptags["subject"]] = $exception["subject"];
1011
-			}
1012
-			if (isset($exception["label"])) {
1013
-				$item[$this->proptags["label"]] = $exception["label"];
1014
-			}
1015
-			if (isset($exception["alldayevent"])) {
1016
-				$item[$this->proptags["alldayevent"]] = $exception["alldayevent"];
1017
-			}
1018
-			if (isset($exception["location"])) {
1019
-				$item[$this->proptags["location"]] = $exception["location"];
1020
-			}
1021
-			if (isset($exception["remind_before"])) {
1022
-				$item[$this->proptags["reminder_minutes"]] = $exception["remind_before"];
1023
-			}
1024
-			if (isset($exception["reminder_set"])) {
1025
-				$item[$this->proptags["reminder"]] = $exception["reminder_set"];
1026
-			}
1027
-			if (isset($exception["busystatus"])) {
1028
-				$item[$this->proptags["busystatus"]] = $exception["busystatus"];
1029
-			}
1030
-
1031
-			return $item;
1032
-		}
1033
-
1034
-		/**
1035
-		 * Function which sets recipients for an exception.
1036
-		 *
1037
-		 * The $exception_recips can be provided in 2 ways:
1038
-		 *  - A delta which indicates which recipients must be added, removed or deleted.
1039
-		 *  - A complete array of the recipients which should be applied to the message.
1040
-		 *
1041
-		 * The first option is preferred as it will require less work to be executed.
1042
-		 *
1043
-		 * @param resource $message          exception attachment of recurring item
1044
-		 * @param array    $exception_recips list of recipients
1045
-		 * @param bool     $copy_orig_recips True to copy all recipients which are on the original
1046
-		 *                                   message to the attachment by default. False if only the $exception_recips changes should
1047
-		 *                                   be applied.
1048
-		 */
1049
-		public function setExceptionRecipients($message, $exception_recips, $copy_orig_recips = true) {
1050
-			if (isset($exception_recips['add']) || isset($exception_recips['remove']) || isset($exception_recips['modify'])) {
1051
-				$this->setDeltaExceptionRecipients($message, $exception_recips, $copy_orig_recips);
1052
-			}
1053
-			else {
1054
-				$this->setAllExceptionRecipients($message, $exception_recips);
1055
-			}
1056
-		}
1057
-
1058
-		/**
1059
-		 * Function which applies the provided delta for recipients changes to the exception.
1060
-		 *
1061
-		 * The $exception_recips should be an array containing the following keys:
1062
-		 *  - "add": this contains an array of recipients which must be added
1063
-		 *  - "remove": This contains an array of recipients which must be removed
1064
-		 *  - "modify": This contains an array of recipients which must be modified
1065
-		 *
1066
-		 * @param resource $message          exception attachment of recurring item
1067
-		 * @param array    $exception_recips list of recipients
1068
-		 * @param bool     $copy_orig_recips True to copy all recipients which are on the original
1069
-		 *                                   message to the attachment by default. False if only the $exception_recips changes should
1070
-		 *                                   be applied.
1071
-		 * @param mixed    $exception
1072
-		 */
1073
-		public function setDeltaExceptionRecipients($exception, $exception_recips, $copy_orig_recips) {
1074
-			// Check if the recipients from the original message should be copied,
1075
-			// if so, open the recipient table of the parent message and apply all
1076
-			// rows on the target recipient.
1077
-			if ($copy_orig_recips === true) {
1078
-				$origTable = mapi_message_getrecipienttable($this->message);
1079
-				$recipientRows = mapi_table_queryallrows($origTable, $this->recipprops);
1080
-				mapi_message_modifyrecipients($exception, MODRECIP_ADD, $recipientRows);
1081
-			}
1082
-
1083
-			// Add organizer to meeting only if it is not organized.
1084
-			$msgprops = mapi_getprops($exception, [PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY, $this->proptags['responsestatus']]);
1085
-			if (isset($msgprops[$this->proptags['responsestatus']]) && $msgprops[$this->proptags['responsestatus']] != olResponseOrganized) {
1086
-				$this->addOrganizer($msgprops, $exception_recips['add']);
1087
-			}
1088
-
1089
-			// Remove all deleted recipients
1090
-			if (isset($exception_recips['remove'])) {
1091
-				foreach ($exception_recips['remove'] as &$recip) {
1092
-					if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recip[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) {
1093
-						$recip[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted;
1094
-					}
1095
-					else {
1096
-						$recip[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1097
-					}
1098
-					$recip[PR_RECIPIENT_TRACKSTATUS] = olResponseNone;		// No Response required
1099
-				}
1100
-				unset($recip);
1101
-				mapi_message_modifyrecipients($exception, MODRECIP_MODIFY, $exception_recips['remove']);
1102
-			}
1103
-
1104
-			// Add all new recipients
1105
-			if (isset($exception_recips['add'])) {
1106
-				mapi_message_modifyrecipients($exception, MODRECIP_ADD, $exception_recips['add']);
1107
-			}
1108
-
1109
-			// Modify the existing recipients
1110
-			if (isset($exception_recips['modify'])) {
1111
-				mapi_message_modifyrecipients($exception, MODRECIP_MODIFY, $exception_recips['modify']);
1112
-			}
1113
-		}
1114
-
1115
-		/**
1116
-		 * Function which applies the provided recipients to the exception, also checks for deleted recipients.
1117
-		 *
1118
-		 * The $exception_recips should be an array containing all recipients which must be applied
1119
-		 * to the exception. This will copy all recipients from the original message and then start filter
1120
-		 * out all recipients which are not provided by the $exception_recips list.
1121
-		 *
1122
-		 * @param resource $message          exception attachment of recurring item
1123
-		 * @param array    $exception_recips list of recipients
1124
-		 */
1125
-		public function setAllExceptionRecipients($message, $exception_recips) {
1126
-			$deletedRecipients = [];
1127
-			$useMessageRecipients = false;
1128
-
1129
-			$recipientTable = mapi_message_getrecipienttable($message);
1130
-			$recipientRows = mapi_table_queryallrows($recipientTable, $this->recipprops);
1131
-
1132
-			if (empty($recipientRows)) {
1133
-				$useMessageRecipients = true;
1134
-				$recipientTable = mapi_message_getrecipienttable($this->message);
1135
-				$recipientRows = mapi_table_queryallrows($recipientTable, $this->recipprops);
1136
-			}
1137
-
1138
-			// Add organizer to meeting only if it is not organized.
1139
-			$msgprops = mapi_getprops($message, [PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY, $this->proptags['responsestatus']]);
1140
-			if (isset($msgprops[$this->proptags['responsestatus']]) && $msgprops[$this->proptags['responsestatus']] != olResponseOrganized) {
1141
-				$this->addOrganizer($msgprops, $exception_recips);
1142
-			}
1143
-
1144
-			if (!empty($exception_recips)) {
1145
-				foreach ($recipientRows as $key => $recipient) {
1146
-					$found = false;
1147
-					foreach ($exception_recips as $excep_recip) {
1148
-						if (isset($recipient[PR_SEARCH_KEY], $excep_recip[PR_SEARCH_KEY]) && $recipient[PR_SEARCH_KEY] == $excep_recip[PR_SEARCH_KEY]) {
1149
-							$found = true;
1150
-						}
1151
-					}
1152
-
1153
-					if (!$found) {
1154
-						$foundInDeletedRecipients = false;
1155
-						// Look if the $recipient is in the list of deleted recipients
1156
-						if (!empty($deletedRecipients)) {
1157
-							foreach ($deletedRecipients as $recip) {
1158
-								if ($recip[PR_SEARCH_KEY] == $recipient[PR_SEARCH_KEY]) {
1159
-									$foundInDeletedRecipients = true;
1160
-
1161
-									break;
1162
-								}
1163
-							}
1164
-						}
1165
-
1166
-						// If recipient is not in list of deleted recipient, add him
1167
-						if (!$foundInDeletedRecipients) {
1168
-							if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recipient[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) {
1169
-								$recipient[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted;
1170
-							}
1171
-							else {
1172
-								$recipient[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1173
-							}
1174
-							$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;	// No Response required
1175
-							$deletedRecipients[] = $recipient;
1176
-						}
1177
-					}
1178
-
1179
-					// When $message contains a non-empty recipienttable, we must delete the recipients
1180
-					// before re-adding them. However, when $message is doesn't contain any recipients,
1181
-					// we are using the recipient table of the original message ($this->message)
1182
-					// rather then $message. In that case, we don't need to remove the recipients
1183
-					// from the $message, as the recipient table is already empty, and
1184
-					// mapi_message_modifyrecipients() will throw an error.
1185
-					if ($useMessageRecipients === false) {
1186
-						mapi_message_modifyrecipients($message, MODRECIP_REMOVE, [$recipient]);
1187
-					}
1188
-				}
1189
-				$exception_recips = array_merge($exception_recips, $deletedRecipients);
1190
-			}
1191
-			else {
1192
-				$exception_recips = $recipientRows;
1193
-			}
1194
-			if (!empty($exception_recips)) {
1195
-				// Set the new list of recipients on the exception message, this also removes the existing recipients
1196
-				mapi_message_modifyrecipients($message, 0, $exception_recips);
1197
-			}
1198
-		}
1199
-
1200
-		/**
1201
-		 * Function returns basedates of all changed occurrences.
1202
-		 *
1203
-		 *@return array array(
1204
-		 * 0 => 123459321
1205
-		 * )
1206
-		 */
1207
-		public function getAllExceptions() {
1208
-			$result = false;
1209
-			if (!empty($this->recur["changed_occurrences"])) {
1210
-				$result = [];
1211
-				foreach ($this->recur["changed_occurrences"] as $exception) {
1212
-					$result[] = $exception["basedate"];
1213
-				}
1214
-
1215
-				return $result;
1216
-			}
1217
-
1218
-			return $result;
1219
-		}
1220
-
1221
-		/**
1222
-		 *  Function which adds organizer to recipient list which is passed.
1223
-		 *  This function also checks if it has organizer.
1224
-		 *
1225
-		 * @param array $messageProps message properties
1226
-		 * @param array $recipients   recipients list of message
1227
-		 * @param bool  $isException  true if we are processing recipient of exception
1228
-		 */
1229
-		public function addOrganizer($messageProps, &$recipients, $isException = false) {
1230
-			$hasOrganizer = false;
1231
-			// Check if meeting already has an organizer.
1232
-			foreach ($recipients as $key => $recipient) {
1233
-				if (isset($recipient[PR_RECIPIENT_FLAGS]) && $recipient[PR_RECIPIENT_FLAGS] == (recipSendable | recipOrganizer)) {
1234
-					$hasOrganizer = true;
1235
-				}
1236
-				elseif ($isException && !isset($recipient[PR_RECIPIENT_FLAGS])) {
1237
-					// Recipients for an occurrence
1238
-					$recipients[$key][PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalResponse;
1239
-				}
1240
-			}
1241
-
1242
-			if (!$hasOrganizer) {
1243
-				// Create organizer.
1244
-				$organizer = [];
1245
-				$organizer[PR_ENTRYID] = $messageProps[PR_SENT_REPRESENTING_ENTRYID];
1246
-				$organizer[PR_DISPLAY_NAME] = $messageProps[PR_SENT_REPRESENTING_NAME];
1247
-				$organizer[PR_EMAIL_ADDRESS] = $messageProps[PR_SENT_REPRESENTING_EMAIL_ADDRESS];
1248
-				$organizer[PR_RECIPIENT_TYPE] = MAPI_TO;
1249
-				$organizer[PR_RECIPIENT_DISPLAY_NAME] = $messageProps[PR_SENT_REPRESENTING_NAME];
1250
-				$organizer[PR_ADDRTYPE] = empty($messageProps[PR_SENT_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $messageProps[PR_SENT_REPRESENTING_ADDRTYPE];
1251
-				$organizer[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
1252
-				$organizer[PR_RECIPIENT_FLAGS] = recipSendable | recipOrganizer;
1253
-				$organizer[PR_SEARCH_KEY] = $messageProps[PR_SENT_REPRESENTING_SEARCH_KEY];
1254
-
1255
-				// Add organizer to recipients list.
1256
-				array_unshift($recipients, $organizer);
1257
-			}
1258
-		}
1259
-	}
1260
-
1261
-	/*
677
+        public function deleteException($base_date) {
678
+            // Remove all exceptions on $base_date from the deleted and changed occurrences lists
679
+
680
+            // Remove all items in $todelete from deleted_occurrences
681
+            $new = [];
682
+
683
+            foreach ($this->recur["deleted_occurrences"] as $entry) {
684
+                if ($entry != $base_date) {
685
+                    $new[] = $entry;
686
+                }
687
+            }
688
+
689
+            $this->recur["deleted_occurrences"] = $new;
690
+
691
+            $new = [];
692
+
693
+            foreach ($this->recur["changed_occurrences"] as $entry) {
694
+                if (!$this->isSameDay($entry["basedate"], $base_date)) {
695
+                    $new[] = $entry;
696
+                }
697
+                else {
698
+                    $this->deleteExceptionAttachment($this->toGMT($this->tz, $base_date + $this->recur["startocc"] * 60));
699
+                }
700
+            }
701
+
702
+            $this->recur["changed_occurrences"] = $new;
703
+        }
704
+
705
+        /**
706
+         * Function which saves the exception data in an attachment.
707
+         *
708
+         * @param array        $exception_props  the exception data (like any other MAPI appointment)
709
+         * @param array        $exception_recips list of recipients
710
+         * @param mapi_message $copy_attach_from mapi message from which attachments should be copied
711
+         *
712
+         * @return array properties of the exception
713
+         */
714
+        public function createExceptionAttachment($exception_props, $exception_recips = [], $copy_attach_from = false) {
715
+            // Create new attachment.
716
+            $attachment = mapi_message_createattach($this->message);
717
+            $props = [];
718
+            $props[PR_ATTACHMENT_FLAGS] = 2;
719
+            $props[PR_ATTACHMENT_HIDDEN] = true;
720
+            $props[PR_ATTACHMENT_LINKID] = 0;
721
+            $props[PR_ATTACH_FLAGS] = 0;
722
+            $props[PR_ATTACH_METHOD] = 5;
723
+            $props[PR_DISPLAY_NAME] = "Exception";
724
+            $props[PR_EXCEPTION_STARTTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]);
725
+            $props[PR_EXCEPTION_ENDTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]);
726
+            mapi_setprops($attachment, $props);
727
+
728
+            $imessage = mapi_attach_openobj($attachment, MAPI_CREATE | MAPI_MODIFY);
729
+
730
+            if ($copy_attach_from) {
731
+                $attachmentTable = mapi_message_getattachmenttable($copy_attach_from);
732
+                if ($attachmentTable) {
733
+                    $attachments = mapi_table_queryallrows($attachmentTable, [PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD]);
734
+
735
+                    foreach ($attachments as $attach_props) {
736
+                        $attach_old = mapi_message_openattach($copy_attach_from, (int) $attach_props[PR_ATTACH_NUM]);
737
+                        $attach_newResourceMsg = mapi_message_createattach($imessage);
738
+                        mapi_copyto($attach_old, [], [], $attach_newResourceMsg, 0);
739
+                        mapi_savechanges($attach_newResourceMsg);
740
+                    }
741
+                }
742
+            }
743
+
744
+            $props = $props + $exception_props;
745
+
746
+            // FIXME: the following piece of code is written to fix the creation
747
+            // of an exception. This is only a quickfix as it is not yet possible
748
+            // to change an existing exception.
749
+            // remove mv properties when needed
750
+            foreach ($props as $propTag => $propVal) {
751
+                if (mapi_prop_type($propTag) & MV_FLAG && is_null($propVal)) {
752
+                    unset($props[$propTag]);
753
+                }
754
+            }
755
+
756
+            mapi_setprops($imessage, $props);
757
+
758
+            $this->setExceptionRecipients($imessage, $exception_recips, true);
759
+
760
+            mapi_savechanges($imessage);
761
+            mapi_savechanges($attachment);
762
+        }
763
+
764
+        /**
765
+         * Function which deletes the attachment of an exception.
766
+         *
767
+         * @param date $base_date base date of the attachment. Should be in GMT. The attachment
768
+         *                        actually saves the real time of the original date, so we have
769
+         *                        to check whether it's on the same day.
770
+         */
771
+        public function deleteExceptionAttachment($base_date) {
772
+            $attachments = mapi_message_getattachmenttable($this->message);
773
+            $attachTable = mapi_table_queryallrows($attachments, [PR_ATTACH_NUM]);
774
+
775
+            foreach ($attachTable as $attachRow) {
776
+                $tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]);
777
+                $exception = mapi_attach_openobj($tempattach);
778
+
779
+                $data = mapi_message_getprops($exception, [$this->proptags["basedate"]]);
780
+                if ($this->dayStartOf($this->fromGMT($this->tz, $data[$this->proptags["basedate"]])) == $this->dayStartOf($base_date)) {
781
+                    mapi_message_deleteattach($this->message, $attachRow[PR_ATTACH_NUM]);
782
+                }
783
+            }
784
+        }
785
+
786
+        /**
787
+         * Function which deletes all attachments of a message.
788
+         */
789
+        public function deleteAttachments() {
790
+            $attachments = mapi_message_getattachmenttable($this->message);
791
+            $attachTable = mapi_table_queryallrows($attachments, [PR_ATTACH_NUM, PR_ATTACHMENT_HIDDEN]);
792
+
793
+            foreach ($attachTable as $attachRow) {
794
+                if (isset($attachRow[PR_ATTACHMENT_HIDDEN]) && $attachRow[PR_ATTACHMENT_HIDDEN]) {
795
+                    mapi_message_deleteattach($this->message, $attachRow[PR_ATTACH_NUM]);
796
+                }
797
+            }
798
+        }
799
+
800
+        /**
801
+         * Get an exception attachment based on its basedate.
802
+         *
803
+         * @param mixed $base_date
804
+         */
805
+        public function getExceptionAttachment($base_date) {
806
+            // Retrieve only embedded messages
807
+            $attach_res = [RES_AND,
808
+                [
809
+                    [RES_PROPERTY,
810
+                        [RELOP => RELOP_EQ,
811
+                            ULPROPTAG => PR_ATTACH_METHOD,
812
+                            VALUE => [PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG],
813
+                        ],
814
+                    ],
815
+                ],
816
+            ];
817
+            $attachments = mapi_message_getattachmenttable($this->message);
818
+            $attachRows = mapi_table_queryallrows($attachments, [PR_ATTACH_NUM], $attach_res);
819
+
820
+            if (is_array($attachRows)) {
821
+                foreach ($attachRows as $attachRow) {
822
+                    $tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]);
823
+                    $exception = mapi_attach_openobj($tempattach);
824
+
825
+                    $data = mapi_message_getprops($exception, [$this->proptags["basedate"]]);
826
+
827
+                    if (isset($data[$this->proptags["basedate"]]) && $this->isSameDay($this->fromGMT($this->tz, $data[$this->proptags["basedate"]]), $base_date)) {
828
+                        return $tempattach;
829
+                    }
830
+                }
831
+            }
832
+
833
+            return false;
834
+        }
835
+
836
+        /**
837
+         * processOccurrenceItem, adds an item to a list of occurrences, but only if the following criteria are met:
838
+         * - The resulting occurrence (or exception) starts or ends in the interval <$start, $end>
839
+         * - The ocurrence isn't specified as a deleted occurrence.
840
+         *
841
+         * @param array $items        reference to the array to be added to
842
+         * @param date  $start        start of timeframe in GMT TIME
843
+         * @param date  $end          end of timeframe in GMT TIME
844
+         * @param date  $basedate     (hour/sec/min assumed to be 00:00:00) in LOCAL TIME OF THE OCCURRENCE
845
+         * @param int   $startocc     start of occurrence since beginning of day in minutes
846
+         * @param int   $endocc       end of occurrence since beginning of day in minutes
847
+         * @param int   $tz           the timezone info for this occurrence ( applied to $basedate / $startocc / $endocc )
848
+         * @param bool  $reminderonly If TRUE, only add the item if the reminder is set
849
+         */
850
+        public function processOccurrenceItem(&$items, $start, $end, $basedate, $startocc, $endocc, $tz, $reminderonly) {
851
+            $exception = $this->isException($basedate);
852
+            if ($exception) {
853
+                return false;
854
+            }
855
+            $occstart = $basedate + $startocc * 60;
856
+            $occend = $basedate + $endocc * 60;
857
+
858
+            // Convert to GMT
859
+            $occstart = $this->toGMT($tz, $occstart);
860
+            $occend = $this->toGMT($tz, $occend);
861
+
862
+            /**
863
+             * FIRST PART : Check range criterium. Exact matches (eg when $occstart == $end), do NOT match since you cannot
864
+             * see any part of the appointment. Partial overlaps DO match.
865
+             *
866
+             * SECOND PART : check if occurrence is not a zero duration occurrence which
867
+             * starts at 00:00 and ends on 00:00. if it is so, then process
868
+             * the occurrence and send it in response.
869
+             */
870
+            if (($occstart >= $end || $occend <= $start) && !($occstart == $occend && $occstart == $start)) {
871
+                return;
872
+            }
873
+
874
+            // Properties for this occurrence are the same as the main object,
875
+            // With these properties overridden
876
+            $newitem = $this->messageprops;
877
+            $newitem[$this->proptags["startdate"]] = $occstart;
878
+            $newitem[$this->proptags["duedate"]] = $occend;
879
+            $newitem[$this->proptags["commonstart"]] = $occstart;
880
+            $newitem[$this->proptags["commonend"]] = $occend;
881
+            $newitem["basedate"] = $basedate;
882
+
883
+            // If reminderonly is set, only add reminders
884
+            if ($reminderonly && (!isset($newitem[$this->proptags["reminder"]]) || $newitem[$this->proptags["reminder"]] == false)) {
885
+                return;
886
+            }
887
+
888
+            $items[] = $newitem;
889
+        }
890
+
891
+        /**
892
+         * processExceptionItem, adds an all exception item to a list of occurrences, without any constraint on timeframe.
893
+         *
894
+         * @param array $items reference to the array to be added to
895
+         * @param date  $start start of timeframe in GMT TIME
896
+         * @param date  $end   end of timeframe in GMT TIME
897
+         */
898
+        public function processExceptionItems(&$items, $start, $end) {
899
+            $limit = 0;
900
+            foreach ($this->recur["changed_occurrences"] as $exception) {
901
+                // Convert to GMT
902
+                $occstart = $this->toGMT($this->tz, $exception["start"]);
903
+                $occend = $this->toGMT($this->tz, $exception["end"]);
904
+
905
+                // Check range criterium. Exact matches (eg when $occstart == $end), do NOT match since you cannot
906
+                // see any part of the appointment. Partial overlaps DO match.
907
+                if ($occstart >= $end || $occend <= $start) {
908
+                    continue;
909
+                }
910
+
911
+                array_push($items, $this->getExceptionProperties($exception));
912
+                if ($limit && (count($items) == $limit)) {
913
+                    break;
914
+                }
915
+            }
916
+        }
917
+
918
+        /**
919
+         * Function which verifies if on the given date an exception, delete or change, occurs.
920
+         *
921
+         * @param date  $date     the date
922
+         * @param mixed $basedate
923
+         *
924
+         * @return array the exception, true - if an occurrence is deleted on the given date, false - no exception occurs on the given date
925
+         */
926
+        public function isException($basedate) {
927
+            if ($this->isDeleteException($basedate)) {
928
+                return true;
929
+            }
930
+
931
+            if ($this->getChangeException($basedate) != false) {
932
+                return true;
933
+            }
934
+
935
+            return false;
936
+        }
937
+
938
+        /**
939
+         * Returns TRUE if there is a DELETE exception on the given base date.
940
+         *
941
+         * @param mixed $basedate
942
+         */
943
+        public function isDeleteException($basedate) {
944
+            // Check if the occurrence is deleted on the specified date
945
+            foreach ($this->recur["deleted_occurrences"] as $deleted) {
946
+                if ($this->isSameDay($deleted, $basedate)) {
947
+                    return true;
948
+                }
949
+            }
950
+
951
+            return false;
952
+        }
953
+
954
+        /**
955
+         * Returns the exception if there is a CHANGE exception on the given base date, or FALSE otherwise.
956
+         *
957
+         * @param mixed $basedate
958
+         */
959
+        public function getChangeException($basedate) {
960
+            // Check if the occurrence is modified on the specified date
961
+            foreach ($this->recur["changed_occurrences"] as $changed) {
962
+                if ($this->isSameDay($changed["basedate"], $basedate)) {
963
+                    return $changed;
964
+                }
965
+            }
966
+
967
+            return false;
968
+        }
969
+
970
+        /**
971
+         * Function to see if two dates are on the same day.
972
+         *
973
+         * @param date  $time1 date 1
974
+         * @param date  $time2 date 2
975
+         * @param mixed $date1
976
+         * @param mixed $date2
977
+         *
978
+         * @return bool Returns TRUE when both dates are on the same day
979
+         */
980
+        public function isSameDay($date1, $date2) {
981
+            $time1 = $this->gmtime($date1);
982
+            $time2 = $this->gmtime($date2);
983
+
984
+            return $time1["tm_mon"] == $time2["tm_mon"] && $time1["tm_year"] == $time2["tm_year"] && $time1["tm_mday"] == $time2["tm_mday"];
985
+        }
986
+
987
+        /**
988
+         * Function to get all properties of a single changed exception.
989
+         *
990
+         * @param date  $date      base date of exception
991
+         * @param mixed $exception
992
+         *
993
+         * @return array associative array of properties for the exception, compatible with
994
+         */
995
+        public function getExceptionProperties($exception) {
996
+            // Exception has same properties as main object, with some properties overridden:
997
+            $item = $this->messageprops;
998
+
999
+            // Special properties
1000
+            $item["exception"] = true;
1001
+            $item["basedate"] = $exception["basedate"]; // note that the basedate is always in local time !
1002
+
1003
+            // MAPI-compatible properties (you can handle an exception as a normal calendar item like this)
1004
+            $item[$this->proptags["startdate"]] = $this->toGMT($this->tz, $exception["start"]);
1005
+            $item[$this->proptags["duedate"]] = $this->toGMT($this->tz, $exception["end"]);
1006
+            $item[$this->proptags["commonstart"]] = $item[$this->proptags["startdate"]];
1007
+            $item[$this->proptags["commonend"]] = $item[$this->proptags["duedate"]];
1008
+
1009
+            if (isset($exception["subject"])) {
1010
+                $item[$this->proptags["subject"]] = $exception["subject"];
1011
+            }
1012
+            if (isset($exception["label"])) {
1013
+                $item[$this->proptags["label"]] = $exception["label"];
1014
+            }
1015
+            if (isset($exception["alldayevent"])) {
1016
+                $item[$this->proptags["alldayevent"]] = $exception["alldayevent"];
1017
+            }
1018
+            if (isset($exception["location"])) {
1019
+                $item[$this->proptags["location"]] = $exception["location"];
1020
+            }
1021
+            if (isset($exception["remind_before"])) {
1022
+                $item[$this->proptags["reminder_minutes"]] = $exception["remind_before"];
1023
+            }
1024
+            if (isset($exception["reminder_set"])) {
1025
+                $item[$this->proptags["reminder"]] = $exception["reminder_set"];
1026
+            }
1027
+            if (isset($exception["busystatus"])) {
1028
+                $item[$this->proptags["busystatus"]] = $exception["busystatus"];
1029
+            }
1030
+
1031
+            return $item;
1032
+        }
1033
+
1034
+        /**
1035
+         * Function which sets recipients for an exception.
1036
+         *
1037
+         * The $exception_recips can be provided in 2 ways:
1038
+         *  - A delta which indicates which recipients must be added, removed or deleted.
1039
+         *  - A complete array of the recipients which should be applied to the message.
1040
+         *
1041
+         * The first option is preferred as it will require less work to be executed.
1042
+         *
1043
+         * @param resource $message          exception attachment of recurring item
1044
+         * @param array    $exception_recips list of recipients
1045
+         * @param bool     $copy_orig_recips True to copy all recipients which are on the original
1046
+         *                                   message to the attachment by default. False if only the $exception_recips changes should
1047
+         *                                   be applied.
1048
+         */
1049
+        public function setExceptionRecipients($message, $exception_recips, $copy_orig_recips = true) {
1050
+            if (isset($exception_recips['add']) || isset($exception_recips['remove']) || isset($exception_recips['modify'])) {
1051
+                $this->setDeltaExceptionRecipients($message, $exception_recips, $copy_orig_recips);
1052
+            }
1053
+            else {
1054
+                $this->setAllExceptionRecipients($message, $exception_recips);
1055
+            }
1056
+        }
1057
+
1058
+        /**
1059
+         * Function which applies the provided delta for recipients changes to the exception.
1060
+         *
1061
+         * The $exception_recips should be an array containing the following keys:
1062
+         *  - "add": this contains an array of recipients which must be added
1063
+         *  - "remove": This contains an array of recipients which must be removed
1064
+         *  - "modify": This contains an array of recipients which must be modified
1065
+         *
1066
+         * @param resource $message          exception attachment of recurring item
1067
+         * @param array    $exception_recips list of recipients
1068
+         * @param bool     $copy_orig_recips True to copy all recipients which are on the original
1069
+         *                                   message to the attachment by default. False if only the $exception_recips changes should
1070
+         *                                   be applied.
1071
+         * @param mixed    $exception
1072
+         */
1073
+        public function setDeltaExceptionRecipients($exception, $exception_recips, $copy_orig_recips) {
1074
+            // Check if the recipients from the original message should be copied,
1075
+            // if so, open the recipient table of the parent message and apply all
1076
+            // rows on the target recipient.
1077
+            if ($copy_orig_recips === true) {
1078
+                $origTable = mapi_message_getrecipienttable($this->message);
1079
+                $recipientRows = mapi_table_queryallrows($origTable, $this->recipprops);
1080
+                mapi_message_modifyrecipients($exception, MODRECIP_ADD, $recipientRows);
1081
+            }
1082
+
1083
+            // Add organizer to meeting only if it is not organized.
1084
+            $msgprops = mapi_getprops($exception, [PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY, $this->proptags['responsestatus']]);
1085
+            if (isset($msgprops[$this->proptags['responsestatus']]) && $msgprops[$this->proptags['responsestatus']] != olResponseOrganized) {
1086
+                $this->addOrganizer($msgprops, $exception_recips['add']);
1087
+            }
1088
+
1089
+            // Remove all deleted recipients
1090
+            if (isset($exception_recips['remove'])) {
1091
+                foreach ($exception_recips['remove'] as &$recip) {
1092
+                    if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recip[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) {
1093
+                        $recip[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted;
1094
+                    }
1095
+                    else {
1096
+                        $recip[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1097
+                    }
1098
+                    $recip[PR_RECIPIENT_TRACKSTATUS] = olResponseNone;		// No Response required
1099
+                }
1100
+                unset($recip);
1101
+                mapi_message_modifyrecipients($exception, MODRECIP_MODIFY, $exception_recips['remove']);
1102
+            }
1103
+
1104
+            // Add all new recipients
1105
+            if (isset($exception_recips['add'])) {
1106
+                mapi_message_modifyrecipients($exception, MODRECIP_ADD, $exception_recips['add']);
1107
+            }
1108
+
1109
+            // Modify the existing recipients
1110
+            if (isset($exception_recips['modify'])) {
1111
+                mapi_message_modifyrecipients($exception, MODRECIP_MODIFY, $exception_recips['modify']);
1112
+            }
1113
+        }
1114
+
1115
+        /**
1116
+         * Function which applies the provided recipients to the exception, also checks for deleted recipients.
1117
+         *
1118
+         * The $exception_recips should be an array containing all recipients which must be applied
1119
+         * to the exception. This will copy all recipients from the original message and then start filter
1120
+         * out all recipients which are not provided by the $exception_recips list.
1121
+         *
1122
+         * @param resource $message          exception attachment of recurring item
1123
+         * @param array    $exception_recips list of recipients
1124
+         */
1125
+        public function setAllExceptionRecipients($message, $exception_recips) {
1126
+            $deletedRecipients = [];
1127
+            $useMessageRecipients = false;
1128
+
1129
+            $recipientTable = mapi_message_getrecipienttable($message);
1130
+            $recipientRows = mapi_table_queryallrows($recipientTable, $this->recipprops);
1131
+
1132
+            if (empty($recipientRows)) {
1133
+                $useMessageRecipients = true;
1134
+                $recipientTable = mapi_message_getrecipienttable($this->message);
1135
+                $recipientRows = mapi_table_queryallrows($recipientTable, $this->recipprops);
1136
+            }
1137
+
1138
+            // Add organizer to meeting only if it is not organized.
1139
+            $msgprops = mapi_getprops($message, [PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_SEARCH_KEY, $this->proptags['responsestatus']]);
1140
+            if (isset($msgprops[$this->proptags['responsestatus']]) && $msgprops[$this->proptags['responsestatus']] != olResponseOrganized) {
1141
+                $this->addOrganizer($msgprops, $exception_recips);
1142
+            }
1143
+
1144
+            if (!empty($exception_recips)) {
1145
+                foreach ($recipientRows as $key => $recipient) {
1146
+                    $found = false;
1147
+                    foreach ($exception_recips as $excep_recip) {
1148
+                        if (isset($recipient[PR_SEARCH_KEY], $excep_recip[PR_SEARCH_KEY]) && $recipient[PR_SEARCH_KEY] == $excep_recip[PR_SEARCH_KEY]) {
1149
+                            $found = true;
1150
+                        }
1151
+                    }
1152
+
1153
+                    if (!$found) {
1154
+                        $foundInDeletedRecipients = false;
1155
+                        // Look if the $recipient is in the list of deleted recipients
1156
+                        if (!empty($deletedRecipients)) {
1157
+                            foreach ($deletedRecipients as $recip) {
1158
+                                if ($recip[PR_SEARCH_KEY] == $recipient[PR_SEARCH_KEY]) {
1159
+                                    $foundInDeletedRecipients = true;
1160
+
1161
+                                    break;
1162
+                                }
1163
+                            }
1164
+                        }
1165
+
1166
+                        // If recipient is not in list of deleted recipient, add him
1167
+                        if (!$foundInDeletedRecipients) {
1168
+                            if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recipient[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) {
1169
+                                $recipient[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted;
1170
+                            }
1171
+                            else {
1172
+                                $recipient[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1173
+                            }
1174
+                            $recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;	// No Response required
1175
+                            $deletedRecipients[] = $recipient;
1176
+                        }
1177
+                    }
1178
+
1179
+                    // When $message contains a non-empty recipienttable, we must delete the recipients
1180
+                    // before re-adding them. However, when $message is doesn't contain any recipients,
1181
+                    // we are using the recipient table of the original message ($this->message)
1182
+                    // rather then $message. In that case, we don't need to remove the recipients
1183
+                    // from the $message, as the recipient table is already empty, and
1184
+                    // mapi_message_modifyrecipients() will throw an error.
1185
+                    if ($useMessageRecipients === false) {
1186
+                        mapi_message_modifyrecipients($message, MODRECIP_REMOVE, [$recipient]);
1187
+                    }
1188
+                }
1189
+                $exception_recips = array_merge($exception_recips, $deletedRecipients);
1190
+            }
1191
+            else {
1192
+                $exception_recips = $recipientRows;
1193
+            }
1194
+            if (!empty($exception_recips)) {
1195
+                // Set the new list of recipients on the exception message, this also removes the existing recipients
1196
+                mapi_message_modifyrecipients($message, 0, $exception_recips);
1197
+            }
1198
+        }
1199
+
1200
+        /**
1201
+         * Function returns basedates of all changed occurrences.
1202
+         *
1203
+         *@return array array(
1204
+         * 0 => 123459321
1205
+         * )
1206
+         */
1207
+        public function getAllExceptions() {
1208
+            $result = false;
1209
+            if (!empty($this->recur["changed_occurrences"])) {
1210
+                $result = [];
1211
+                foreach ($this->recur["changed_occurrences"] as $exception) {
1212
+                    $result[] = $exception["basedate"];
1213
+                }
1214
+
1215
+                return $result;
1216
+            }
1217
+
1218
+            return $result;
1219
+        }
1220
+
1221
+        /**
1222
+         *  Function which adds organizer to recipient list which is passed.
1223
+         *  This function also checks if it has organizer.
1224
+         *
1225
+         * @param array $messageProps message properties
1226
+         * @param array $recipients   recipients list of message
1227
+         * @param bool  $isException  true if we are processing recipient of exception
1228
+         */
1229
+        public function addOrganizer($messageProps, &$recipients, $isException = false) {
1230
+            $hasOrganizer = false;
1231
+            // Check if meeting already has an organizer.
1232
+            foreach ($recipients as $key => $recipient) {
1233
+                if (isset($recipient[PR_RECIPIENT_FLAGS]) && $recipient[PR_RECIPIENT_FLAGS] == (recipSendable | recipOrganizer)) {
1234
+                    $hasOrganizer = true;
1235
+                }
1236
+                elseif ($isException && !isset($recipient[PR_RECIPIENT_FLAGS])) {
1237
+                    // Recipients for an occurrence
1238
+                    $recipients[$key][PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalResponse;
1239
+                }
1240
+            }
1241
+
1242
+            if (!$hasOrganizer) {
1243
+                // Create organizer.
1244
+                $organizer = [];
1245
+                $organizer[PR_ENTRYID] = $messageProps[PR_SENT_REPRESENTING_ENTRYID];
1246
+                $organizer[PR_DISPLAY_NAME] = $messageProps[PR_SENT_REPRESENTING_NAME];
1247
+                $organizer[PR_EMAIL_ADDRESS] = $messageProps[PR_SENT_REPRESENTING_EMAIL_ADDRESS];
1248
+                $organizer[PR_RECIPIENT_TYPE] = MAPI_TO;
1249
+                $organizer[PR_RECIPIENT_DISPLAY_NAME] = $messageProps[PR_SENT_REPRESENTING_NAME];
1250
+                $organizer[PR_ADDRTYPE] = empty($messageProps[PR_SENT_REPRESENTING_ADDRTYPE]) ? 'SMTP' : $messageProps[PR_SENT_REPRESENTING_ADDRTYPE];
1251
+                $organizer[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;
1252
+                $organizer[PR_RECIPIENT_FLAGS] = recipSendable | recipOrganizer;
1253
+                $organizer[PR_SEARCH_KEY] = $messageProps[PR_SENT_REPRESENTING_SEARCH_KEY];
1254
+
1255
+                // Add organizer to recipients list.
1256
+                array_unshift($recipients, $organizer);
1257
+            }
1258
+        }
1259
+    }
1260
+
1261
+    /*
1262 1262
 
1263 1263
 	From http://www.ohelp-one.com/new-6765483-3268.html:
1264 1264
 
Please login to merge, or discard this patch.
Switch Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -521,56 +521,56 @@
 block discarded – undo
521 521
 
522 522
 			switch ($type) {
523 523
 				// Daily
524
-				case 0x0A:
525
-					if ($everyn == 1) {
526
-						$type = dgettext("kopano", "workday");
527
-						$occSingleDayRank = true;
528
-					}
529
-					elseif ($everyn == (24 * 60)) {
530
-						$type = dgettext("kopano", "day");
531
-						$occSingleDayRank = true;
532
-					}
533
-					else {
534
-						$everyn /= (24 * 60);
535
-						$type = dgettext("kopano", "days");
536
-						$occSingleDayRank = false;
537
-					}
538
-					break;
539
-				// Weekly
540
-				case 0x0B:
541
-					if ($everyn == 1) {
542
-						$type = dgettext("kopano", "week");
543
-						$occSingleDayRank = true;
544
-					}
545
-					else {
546
-						$type = dgettext("kopano", "weeks");
547
-						$occSingleDayRank = false;
548
-					}
549
-					break;
550
-				// Monthly
551
-				case 0x0C:
552
-					if ($everyn == 1) {
553
-						$type = dgettext("kopano", "month");
554
-						$occSingleDayRank = true;
555
-					}
556
-					else {
557
-						$type = dgettext("kopano", "months");
558
-						$occSingleDayRank = false;
559
-					}
560
-					break;
561
-				// Yearly
562
-				case 0x0D:
563
-					if ($everyn <= 12) {
564
-						$everyn = 1;
565
-						$type = dgettext("kopano", "year");
566
-						$occSingleDayRank = true;
567
-					}
568
-					else {
569
-						$everyn = $everyn / 12;
570
-						$type = dgettext("kopano", "years");
571
-						$occSingleDayRank = false;
572
-					}
573
-					break;
524
+			case 0x0A:
525
+				if ($everyn == 1) {
526
+					$type = dgettext("kopano", "workday");
527
+					$occSingleDayRank = true;
528
+				}
529
+				elseif ($everyn == (24 * 60)) {
530
+					$type = dgettext("kopano", "day");
531
+					$occSingleDayRank = true;
532
+				}
533
+				else {
534
+					$everyn /= (24 * 60);
535
+					$type = dgettext("kopano", "days");
536
+					$occSingleDayRank = false;
537
+				}
538
+				break;
539
+			// Weekly
540
+			case 0x0B:
541
+				if ($everyn == 1) {
542
+					$type = dgettext("kopano", "week");
543
+					$occSingleDayRank = true;
544
+				}
545
+				else {
546
+					$type = dgettext("kopano", "weeks");
547
+					$occSingleDayRank = false;
548
+				}
549
+				break;
550
+			// Monthly
551
+			case 0x0C:
552
+				if ($everyn == 1) {
553
+					$type = dgettext("kopano", "month");
554
+					$occSingleDayRank = true;
555
+				}
556
+				else {
557
+					$type = dgettext("kopano", "months");
558
+					$occSingleDayRank = false;
559
+				}
560
+				break;
561
+			// Yearly
562
+			case 0x0D:
563
+				if ($everyn <= 12) {
564
+					$everyn = 1;
565
+					$type = dgettext("kopano", "year");
566
+					$occSingleDayRank = true;
567
+				}
568
+				else {
569
+					$everyn = $everyn / 12;
570
+					$type = dgettext("kopano", "years");
571
+					$occSingleDayRank = false;
572
+				}
573
+				break;
574 574
 			}
575 575
 
576 576
 			// get timings of the first occurrence
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
 					else {
1096 1096
 						$recip[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1097 1097
 					}
1098
-					$recip[PR_RECIPIENT_TRACKSTATUS] = olResponseNone;		// No Response required
1098
+					$recip[PR_RECIPIENT_TRACKSTATUS] = olResponseNone; // No Response required
1099 1099
 				}
1100 1100
 				unset($recip);
1101 1101
 				mapi_message_modifyrecipients($exception, MODRECIP_MODIFY, $exception_recips['remove']);
@@ -1171,7 +1171,7 @@  discard block
 block discarded – undo
1171 1171
 							else {
1172 1172
 								$recipient[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1173 1173
 							}
1174
-							$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;	// No Response required
1174
+							$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone; // No Response required
1175 1175
 							$deletedRecipients[] = $recipient;
1176 1176
 						}
1177 1177
 					}
Please login to merge, or discard this patch.
Braces   +27 added lines, -54 removed lines patch added patch discarded remove patch
@@ -179,8 +179,7 @@  discard block
 block discarded – undo
179 179
 
180 180
 				// Add the changed occurrence to the list
181 181
 				array_push($this->recur["changed_occurrences"], $changed_item);
182
-			}
183
-			else {
182
+			} else {
184 183
 				// Delete the occurrence by placing it in the deleted occurrences list
185 184
 				array_push($this->recur["deleted_occurrences"], $baseday);
186 185
 			}
@@ -269,12 +268,10 @@  discard block
 block discarded – undo
269 268
 				if ($copy_attach_from) {
270 269
 					$this->deleteExceptionAttachment($base_date);
271 270
 					$this->createException($exception_props, $base_date, false, $exception_recips, $copy_attach_from);
272
-				}
273
-				else {
271
+				} else {
274 272
 					$this->createExceptionAttachment($exception_props, $exception_recips, $copy_attach_from);
275 273
 				}
276
-			}
277
-			else {
274
+			} else {
278 275
 				$message = mapi_attach_openobj($attach, MAPI_MODIFY);
279 276
 
280 277
 				// Set exception properties on embedded message and save
@@ -317,8 +314,7 @@  discard block
 block discarded – undo
317 314
 				// the exception used to be.
318 315
 				$oldexception = $this->getChangeException($basedate);
319 316
 				$prevday = $this->dayStartOf($oldexception["start"]);
320
-			}
321
-			else {
317
+			} else {
322 318
 				// If its a new exception, we want to look at the original placement of this item.
323 319
 				$prevday = $basedate;
324 320
 			}
@@ -328,8 +324,7 @@  discard block
 block discarded – undo
328 324
 			// Get all the occurrences on the days between the basedate (may be reversed)
329 325
 			if ($prevday < $startday) {
330 326
 				$items = $this->getItems($this->toGMT($this->tz, $prevday), $this->toGMT($this->tz, $startday + 24 * 60 * 60));
331
-			}
332
-			else {
327
+			} else {
333 328
 				$items = $this->getItems($this->toGMT($this->tz, $startday), $this->toGMT($this->tz, $prevday + 24 * 60 * 60));
334 329
 			}
335 330
 
@@ -525,12 +520,10 @@  discard block
 block discarded – undo
525 520
 					if ($everyn == 1) {
526 521
 						$type = dgettext("kopano", "workday");
527 522
 						$occSingleDayRank = true;
528
-					}
529
-					elseif ($everyn == (24 * 60)) {
523
+					} elseif ($everyn == (24 * 60)) {
530 524
 						$type = dgettext("kopano", "day");
531 525
 						$occSingleDayRank = true;
532
-					}
533
-					else {
526
+					} else {
534 527
 						$everyn /= (24 * 60);
535 528
 						$type = dgettext("kopano", "days");
536 529
 						$occSingleDayRank = false;
@@ -541,8 +534,7 @@  discard block
 block discarded – undo
541 534
 					if ($everyn == 1) {
542 535
 						$type = dgettext("kopano", "week");
543 536
 						$occSingleDayRank = true;
544
-					}
545
-					else {
537
+					} else {
546 538
 						$type = dgettext("kopano", "weeks");
547 539
 						$occSingleDayRank = false;
548 540
 					}
@@ -552,8 +544,7 @@  discard block
 block discarded – undo
552 544
 					if ($everyn == 1) {
553 545
 						$type = dgettext("kopano", "month");
554 546
 						$occSingleDayRank = true;
555
-					}
556
-					else {
547
+					} else {
557 548
 						$type = dgettext("kopano", "months");
558 549
 						$occSingleDayRank = false;
559 550
 					}
@@ -564,8 +555,7 @@  discard block
 block discarded – undo
564 555
 						$everyn = 1;
565 556
 						$type = dgettext("kopano", "year");
566 557
 						$occSingleDayRank = true;
567
-					}
568
-					else {
558
+					} else {
569 559
 						$everyn = $everyn / 12;
570 560
 						$type = dgettext("kopano", "years");
571 561
 						$occSingleDayRank = false;
@@ -594,21 +584,17 @@  discard block
 block discarded – undo
594 584
 				if ($occTimeRange) {
595 585
 					if ($occSingleDayRank) {
596 586
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s from %s to %s."), $type, $start, $startocc, $endocc);
597
-					}
598
-					else {
587
+					} else {
599 588
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s from %s to %s."), $everyn, $type, $start, $startocc, $endocc);
600 589
 					}
601
-				}
602
-				else {
590
+				} else {
603 591
 					if ($occSingleDayRank) {
604 592
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s."), $type, $start);
605
-					}
606
-					else {
593
+					} else {
607 594
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s."), $everyn, $type, $start);
608 595
 					}
609 596
 				}
610
-			}
611
-			elseif ($term == 0x22) {
597
+			} elseif ($term == 0x22) {
612 598
 				// After a number of times
613 599
 				if ($occTimeRange) {
614 600
 					if ($occSingleDayRank) {
@@ -618,8 +604,7 @@  discard block
 block discarded – undo
618 604
 							"Occurs every %s effective %s for %s occurrences from %s to %s.",
619 605
 							$numocc
620 606
 						), $type, $start, $numocc, $startocc, $endocc);
621
-					}
622
-					else {
607
+					} else {
623 608
 						$pattern = sprintf(dngettext(
624 609
 							"kopano",
625 610
 							"Occurs every %s %s effective %s for %s occurrence from %s to %s.",
@@ -627,8 +612,7 @@  discard block
 block discarded – undo
627 612
 							$numocc
628 613
 						), $everyn, $type, $start, $numocc, $startocc, $endocc);
629 614
 					}
630
-				}
631
-				else {
615
+				} else {
632 616
 					if ($occSingleDayRank) {
633 617
 						$pattern = sprintf(dngettext(
634 618
 							"kopano",
@@ -636,8 +620,7 @@  discard block
 block discarded – undo
636 620
 							"Occurs every %s effective %s for %s occurrences.",
637 621
 							$numocc
638 622
 						), $type, $start, $numocc);
639
-					}
640
-					else {
623
+					} else {
641 624
 						$pattern = sprintf(dngettext(
642 625
 							"kopano",
643 626
 							"Occurs every %s %s effective %s for %s occurrence.",
@@ -646,22 +629,18 @@  discard block
 block discarded – undo
646 629
 						), $everyn, $type, $start, $numocc);
647 630
 					}
648 631
 				}
649
-			}
650
-			elseif ($term == 0x21) {
632
+			} elseif ($term == 0x21) {
651 633
 				// After the given enddate
652 634
 				if ($occTimeRange) {
653 635
 					if ($occSingleDayRank) {
654 636
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s until %s from %s to %s."), $type, $start, $end, $startocc, $endocc);
655
-					}
656
-					else {
637
+					} else {
657 638
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s until %s from %s to %s."), $everyn, $type, $start, $end, $startocc, $endocc);
658 639
 					}
659
-				}
660
-				else {
640
+				} else {
661 641
 					if ($occSingleDayRank) {
662 642
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s effective %s until %s."), $type, $start, $end);
663
-					}
664
-					else {
643
+					} else {
665 644
 						$pattern = sprintf(dgettext("kopano", "Occurs every %s %s effective %s until %s."), $everyn, $type, $start, $end);
666 645
 					}
667 646
 				}
@@ -693,8 +672,7 @@  discard block
 block discarded – undo
693 672
 			foreach ($this->recur["changed_occurrences"] as $entry) {
694 673
 				if (!$this->isSameDay($entry["basedate"], $base_date)) {
695 674
 					$new[] = $entry;
696
-				}
697
-				else {
675
+				} else {
698 676
 					$this->deleteExceptionAttachment($this->toGMT($this->tz, $base_date + $this->recur["startocc"] * 60));
699 677
 				}
700 678
 			}
@@ -1049,8 +1027,7 @@  discard block
 block discarded – undo
1049 1027
 		public function setExceptionRecipients($message, $exception_recips, $copy_orig_recips = true) {
1050 1028
 			if (isset($exception_recips['add']) || isset($exception_recips['remove']) || isset($exception_recips['modify'])) {
1051 1029
 				$this->setDeltaExceptionRecipients($message, $exception_recips, $copy_orig_recips);
1052
-			}
1053
-			else {
1030
+			} else {
1054 1031
 				$this->setAllExceptionRecipients($message, $exception_recips);
1055 1032
 			}
1056 1033
 		}
@@ -1091,8 +1068,7 @@  discard block
 block discarded – undo
1091 1068
 				foreach ($exception_recips['remove'] as &$recip) {
1092 1069
 					if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recip[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) {
1093 1070
 						$recip[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted;
1094
-					}
1095
-					else {
1071
+					} else {
1096 1072
 						$recip[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1097 1073
 					}
1098 1074
 					$recip[PR_RECIPIENT_TRACKSTATUS] = olResponseNone;		// No Response required
@@ -1167,8 +1143,7 @@  discard block
 block discarded – undo
1167 1143
 						if (!$foundInDeletedRecipients) {
1168 1144
 							if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recipient[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) {
1169 1145
 								$recipient[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted;
1170
-							}
1171
-							else {
1146
+							} else {
1172 1147
 								$recipient[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable;
1173 1148
 							}
1174 1149
 							$recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone;	// No Response required
@@ -1187,8 +1162,7 @@  discard block
 block discarded – undo
1187 1162
 					}
1188 1163
 				}
1189 1164
 				$exception_recips = array_merge($exception_recips, $deletedRecipients);
1190
-			}
1191
-			else {
1165
+			} else {
1192 1166
 				$exception_recips = $recipientRows;
1193 1167
 			}
1194 1168
 			if (!empty($exception_recips)) {
@@ -1232,8 +1206,7 @@  discard block
 block discarded – undo
1232 1206
 			foreach ($recipients as $key => $recipient) {
1233 1207
 				if (isset($recipient[PR_RECIPIENT_FLAGS]) && $recipient[PR_RECIPIENT_FLAGS] == (recipSendable | recipOrganizer)) {
1234 1208
 					$hasOrganizer = true;
1235
-				}
1236
-				elseif ($isException && !isset($recipient[PR_RECIPIENT_FLAGS])) {
1209
+				} elseif ($isException && !isset($recipient[PR_RECIPIENT_FLAGS])) {
1237 1210
 					// Recipients for an occurrence
1238 1211
 					$recipients[$key][PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalResponse;
1239 1212
 				}
Please login to merge, or discard this patch.
mapi/mapi.util.php 3 patches
Indentation   +254 added lines, -254 removed lines patch added patch discarded remove patch
@@ -22,7 +22,7 @@  discard block
 block discarded – undo
22 22
  * @param mixed $guid
23 23
  */
24 24
 function makeGuid($guid) {
25
-	return pack("vvvv", hexdec(substr($guid, 5, 4)), hexdec(substr($guid, 1, 4)), hexdec(substr($guid, 10, 4)), hexdec(substr($guid, 15, 4))) . hex2bin(substr($guid, 20, 4)) . hex2bin(substr($guid, 25, 12));
25
+    return pack("vvvv", hexdec(substr($guid, 5, 4)), hexdec(substr($guid, 1, 4)), hexdec(substr($guid, 10, 4)), hexdec(substr($guid, 15, 4))) . hex2bin(substr($guid, 20, 4)) . hex2bin(substr($guid, 25, 12));
26 26
 }
27 27
 
28 28
 /**
@@ -33,39 +33,39 @@  discard block
 block discarded – undo
33 33
  *@return string The defined name for the MAPI error code
34 34
  */
35 35
 function get_mapi_error_name($errcode = null) {
36
-	if ($errcode === null) {
37
-		$errcode = mapi_last_hresult();
38
-	}
36
+    if ($errcode === null) {
37
+        $errcode = mapi_last_hresult();
38
+    }
39 39
 
40
-	if ($errcode === 0) {
41
-		return "NOERROR";
42
-	}
40
+    if ($errcode === 0) {
41
+        return "NOERROR";
42
+    }
43 43
 
44
-	// get_defined_constants(true) is preferred, but crashes PHP
45
-	// https://bugs.php.net/bug.php?id=61156
46
-	$allConstants = get_defined_constants();
44
+    // get_defined_constants(true) is preferred, but crashes PHP
45
+    // https://bugs.php.net/bug.php?id=61156
46
+    $allConstants = get_defined_constants();
47 47
 
48
-	foreach ($allConstants as $key => $value) {
49
-		/*
48
+    foreach ($allConstants as $key => $value) {
49
+        /*
50 50
 		 * If PHP encounters a number beyond the bounds of the integer type,
51 51
 		 * it will be interpreted as a float instead, so when comparing these error codes
52 52
 		 * we have to manually typecast value to integer, so float will be converted in integer,
53 53
 		 * but still its out of bound for integer limit so it will be auto adjusted to minus value
54 54
 		 */
55
-		if ($errcode != (int) $value) {
56
-			continue;
57
-		}
58
-		// Check that we have an actual MAPI error or warning definition
59
-		$prefix = substr($key, 0, 7);
60
-		if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") {
61
-			return $key;
62
-		}
63
-	}
64
-
65
-	// error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this)
66
-	$result = unpack("H*", pack("N", $errcode));
67
-
68
-	return "0x" . $result[1];
55
+        if ($errcode != (int) $value) {
56
+            continue;
57
+        }
58
+        // Check that we have an actual MAPI error or warning definition
59
+        $prefix = substr($key, 0, 7);
60
+        if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") {
61
+            return $key;
62
+        }
63
+    }
64
+
65
+    // error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this)
66
+    $result = unpack("H*", pack("N", $errcode));
67
+
68
+    return "0x" . $result[1];
69 69
 }
70 70
 
71 71
 /**
@@ -79,65 +79,65 @@  discard block
 block discarded – undo
79 79
  * @param mixed $mapping
80 80
  */
81 81
 function getPropIdsFromStrings($store, $mapping) {
82
-	$props = [];
83
-
84
-	$ids = ["name" => [], "id" => [], "guid" => [], "type" => []]; // this array stores all the information needed to retrieve a named property
85
-	$num = 0;
86
-
87
-	// caching
88
-	$guids = [];
89
-
90
-	foreach ($mapping as $name => $val) {
91
-		if (!is_string($val)) {
92
-			// not a named property
93
-			$props[$name] = $val;
94
-
95
-			continue;
96
-		}
97
-		$split = explode(":", $val);
98
-		if (count($split) != 3) { // invalid string, ignore
99
-			trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE);
100
-
101
-			continue;
102
-		}
103
-
104
-		if (substr($split[2], 0, 2) == "0x") {
105
-			$id = hexdec(substr($split[2], 2));
106
-		}
107
-		else {
108
-			$id = $split[2];
109
-		}
110
-
111
-		// have we used this guid before?
112
-		if (!defined($split[1])) {
113
-			if (!array_key_exists($split[1], $guids)) {
114
-				$guids[$split[1]] = makeguid($split[1]);
115
-			}
116
-			$guid = $guids[$split[1]];
117
-		}
118
-		else {
119
-			$guid = constant($split[1]);
120
-		}
121
-
122
-		// temp store info about named prop, so we have to call mapi_getidsfromnames just one time
123
-		$ids["name"][$num] = $name;
124
-		$ids["id"][$num] = $id;
125
-		$ids["guid"][$num] = $guid;
126
-		$ids["type"][$num] = $split[0];
127
-		++$num;
128
-	}
129
-
130
-	if (empty($ids["id"])) {
131
-		return $props;
132
-	}
133
-
134
-	// get the ids
135
-	$named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]);
136
-	foreach ($named as $num => $prop) {
137
-		$props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop));
138
-	}
139
-
140
-	return $props;
82
+    $props = [];
83
+
84
+    $ids = ["name" => [], "id" => [], "guid" => [], "type" => []]; // this array stores all the information needed to retrieve a named property
85
+    $num = 0;
86
+
87
+    // caching
88
+    $guids = [];
89
+
90
+    foreach ($mapping as $name => $val) {
91
+        if (!is_string($val)) {
92
+            // not a named property
93
+            $props[$name] = $val;
94
+
95
+            continue;
96
+        }
97
+        $split = explode(":", $val);
98
+        if (count($split) != 3) { // invalid string, ignore
99
+            trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE);
100
+
101
+            continue;
102
+        }
103
+
104
+        if (substr($split[2], 0, 2) == "0x") {
105
+            $id = hexdec(substr($split[2], 2));
106
+        }
107
+        else {
108
+            $id = $split[2];
109
+        }
110
+
111
+        // have we used this guid before?
112
+        if (!defined($split[1])) {
113
+            if (!array_key_exists($split[1], $guids)) {
114
+                $guids[$split[1]] = makeguid($split[1]);
115
+            }
116
+            $guid = $guids[$split[1]];
117
+        }
118
+        else {
119
+            $guid = constant($split[1]);
120
+        }
121
+
122
+        // temp store info about named prop, so we have to call mapi_getidsfromnames just one time
123
+        $ids["name"][$num] = $name;
124
+        $ids["id"][$num] = $id;
125
+        $ids["guid"][$num] = $guid;
126
+        $ids["type"][$num] = $split[0];
127
+        ++$num;
128
+    }
129
+
130
+    if (empty($ids["id"])) {
131
+        return $props;
132
+    }
133
+
134
+    // get the ids
135
+    $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]);
136
+    foreach ($named as $num => $prop) {
137
+        $props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop));
138
+    }
139
+
140
+    return $props;
141 141
 }
142 142
 
143 143
 /**
@@ -153,11 +153,11 @@  discard block
 block discarded – undo
153 153
  * @return mixed Gives back false when there is no error, if there is, gives the error
154 154
  */
155 155
 function propIsError($property, $propArray) {
156
-	if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) {
157
-		return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))];
158
-	}
156
+    if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) {
157
+        return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))];
158
+    }
159 159
 
160
-	return false;
160
+    return false;
161 161
 }
162 162
 
163 163
 /* Macro Functions for PR_DISPLAY_TYPE_EX values */
@@ -167,7 +167,7 @@  discard block
 block discarded – undo
167 167
  * @param mixed $value
168 168
  */
169 169
 function DTE_IS_REMOTE_VALID($value) {
170
-	return (bool) ($value & DTE_FLAG_REMOTE_VALID);
170
+    return (bool) ($value & DTE_FLAG_REMOTE_VALID);
171 171
 }
172 172
 
173 173
 /**
@@ -176,15 +176,15 @@  discard block
 block discarded – undo
176 176
  * @param mixed $value
177 177
  */
178 178
 function DTE_IS_ACL_CAPABLE($value) {
179
-	return (bool) ($value & DTE_FLAG_ACL_CAPABLE);
179
+    return (bool) ($value & DTE_FLAG_ACL_CAPABLE);
180 180
 }
181 181
 
182 182
 function DTE_REMOTE($value) {
183
-	return ($value & DTE_MASK_REMOTE) >> 8;
183
+    return ($value & DTE_MASK_REMOTE) >> 8;
184 184
 }
185 185
 
186 186
 function DTE_LOCAL($value) {
187
-	return $value & DTE_MASK_LOCAL;
187
+    return $value & DTE_MASK_LOCAL;
188 188
 }
189 189
 
190 190
 /**
@@ -204,86 +204,86 @@  discard block
 block discarded – undo
204 204
  *                    expanded so that it seems that there are only many single appointments in the table.
205 205
  */
206 206
 function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested) {
207
-	$result = [];
208
-	$properties = getPropIdsFromStrings($store, ["duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e",
209
-		"startdate" => "PT_SYSTIME:PSETID_Appointment:0x820d",
210
-		"enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236",
211
-		"recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223",
212
-		"recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216",
213
-		"timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233",
214
-		"label" => "PT_LONG:PSETID_Appointment:0x8214",
215
-	]);
216
-
217
-	// Create a restriction that will discard rows of appointments that are definitely not in our
218
-	// requested time frame
219
-
220
-	$table = mapi_folder_getcontentstable($calendar);
221
-
222
-	$restriction =
223
-		// OR
224
-		[RES_OR,
225
-			[
226
-				[RES_AND,    // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd
227
-					[
228
-						[RES_PROPERTY,
229
-							[RELOP => RELOP_GT,
230
-								ULPROPTAG => $properties["duedate"],
231
-								VALUE => $viewstart,
232
-							],
233
-						],
234
-						[RES_PROPERTY,
235
-							[RELOP => RELOP_LT,
236
-								ULPROPTAG => $properties["startdate"],
237
-								VALUE => $viewend,
238
-							],
239
-						],
240
-					],
241
-				],
242
-				// OR
243
-				[RES_PROPERTY,
244
-					[RELOP => RELOP_EQ,
245
-						ULPROPTAG => $properties["recurring"],
246
-						VALUE => true,
247
-					],
248
-				],
249
-			], // EXISTS OR
250
-		];        // global OR
251
-
252
-	// Get requested properties, plus whatever we need
253
-	$proplist = [PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]];
254
-	$proplist = array_merge($proplist, $propsrequested);
255
-	$propslist = array_unique($proplist);
256
-
257
-	$rows = mapi_table_queryallrows($table, $proplist, $restriction);
258
-
259
-	// $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output.
260
-
261
-	foreach ($rows as $row) {
262
-		$items = [];
263
-
264
-		if (isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) {
265
-			// Recurring item
266
-			$rec = new Recurrence($store, $row);
267
-
268
-			// GetItems guarantees that the item overlaps the interval <$viewstart, $viewend>
269
-			$occurrences = $rec->getItems($viewstart, $viewend);
270
-			foreach ($occurrences as $occurrence) {
271
-				// The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously)
272
-				$item = $occurrence + $row;
273
-				array_push($items, $item);
274
-			}
275
-		}
276
-		else {
277
-			// Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend>
278
-			array_push($items, $row);
279
-		}
280
-
281
-		$result = array_merge($result, $items);
282
-	}
283
-
284
-	// All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra
285
-	// properties that the caller did not request (recurring, etc). This shouldn't be a problem though.
286
-	return $result;
207
+    $result = [];
208
+    $properties = getPropIdsFromStrings($store, ["duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e",
209
+        "startdate" => "PT_SYSTIME:PSETID_Appointment:0x820d",
210
+        "enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236",
211
+        "recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223",
212
+        "recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216",
213
+        "timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233",
214
+        "label" => "PT_LONG:PSETID_Appointment:0x8214",
215
+    ]);
216
+
217
+    // Create a restriction that will discard rows of appointments that are definitely not in our
218
+    // requested time frame
219
+
220
+    $table = mapi_folder_getcontentstable($calendar);
221
+
222
+    $restriction =
223
+        // OR
224
+        [RES_OR,
225
+            [
226
+                [RES_AND,    // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd
227
+                    [
228
+                        [RES_PROPERTY,
229
+                            [RELOP => RELOP_GT,
230
+                                ULPROPTAG => $properties["duedate"],
231
+                                VALUE => $viewstart,
232
+                            ],
233
+                        ],
234
+                        [RES_PROPERTY,
235
+                            [RELOP => RELOP_LT,
236
+                                ULPROPTAG => $properties["startdate"],
237
+                                VALUE => $viewend,
238
+                            ],
239
+                        ],
240
+                    ],
241
+                ],
242
+                // OR
243
+                [RES_PROPERTY,
244
+                    [RELOP => RELOP_EQ,
245
+                        ULPROPTAG => $properties["recurring"],
246
+                        VALUE => true,
247
+                    ],
248
+                ],
249
+            ], // EXISTS OR
250
+        ];        // global OR
251
+
252
+    // Get requested properties, plus whatever we need
253
+    $proplist = [PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]];
254
+    $proplist = array_merge($proplist, $propsrequested);
255
+    $propslist = array_unique($proplist);
256
+
257
+    $rows = mapi_table_queryallrows($table, $proplist, $restriction);
258
+
259
+    // $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output.
260
+
261
+    foreach ($rows as $row) {
262
+        $items = [];
263
+
264
+        if (isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) {
265
+            // Recurring item
266
+            $rec = new Recurrence($store, $row);
267
+
268
+            // GetItems guarantees that the item overlaps the interval <$viewstart, $viewend>
269
+            $occurrences = $rec->getItems($viewstart, $viewend);
270
+            foreach ($occurrences as $occurrence) {
271
+                // The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously)
272
+                $item = $occurrence + $row;
273
+                array_push($items, $item);
274
+            }
275
+        }
276
+        else {
277
+            // Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend>
278
+            array_push($items, $row);
279
+        }
280
+
281
+        $result = array_merge($result, $items);
282
+    }
283
+
284
+    // All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra
285
+    // properties that the caller did not request (recurring, etc). This shouldn't be a problem though.
286
+    return $result;
287 287
 }
288 288
 
289 289
 /**
@@ -292,14 +292,14 @@  discard block
 block discarded – undo
292 292
  * @param mixed $store
293 293
  */
294 294
 function getCalendar($store) {
295
-	$inbox = mapi_msgstore_getreceivefolder($store);
296
-	$inboxprops = mapi_getprops($inbox, [PR_IPM_APPOINTMENT_ENTRYID]);
295
+    $inbox = mapi_msgstore_getreceivefolder($store);
296
+    $inboxprops = mapi_getprops($inbox, [PR_IPM_APPOINTMENT_ENTRYID]);
297 297
 
298
-	if (!isset($inboxprops[PR_IPM_APPOINTMENT_ENTRYID])) {
299
-		return false;
300
-	}
298
+    if (!isset($inboxprops[PR_IPM_APPOINTMENT_ENTRYID])) {
299
+        return false;
300
+    }
301 301
 
302
-	return mapi_msgstore_openentry($store, $inboxprops[PR_IPM_APPOINTMENT_ENTRYID]);
302
+    return mapi_msgstore_openentry($store, $inboxprops[PR_IPM_APPOINTMENT_ENTRYID]);
303 303
 }
304 304
 
305 305
 /**
@@ -308,97 +308,97 @@  discard block
 block discarded – undo
308 308
  * @param mixed $session
309 309
  */
310 310
 function getDefaultStore($session) {
311
-	$msgstorestable = mapi_getmsgstorestable($session);
311
+    $msgstorestable = mapi_getmsgstorestable($session);
312 312
 
313
-	$msgstores = mapi_table_queryallrows($msgstorestable, [PR_DEFAULT_STORE, PR_ENTRYID]);
313
+    $msgstores = mapi_table_queryallrows($msgstorestable, [PR_DEFAULT_STORE, PR_ENTRYID]);
314 314
 
315
-	foreach ($msgstores as $row) {
316
-		if ($row[PR_DEFAULT_STORE]) {
317
-			$storeentryid = $row[PR_ENTRYID];
315
+    foreach ($msgstores as $row) {
316
+        if ($row[PR_DEFAULT_STORE]) {
317
+            $storeentryid = $row[PR_ENTRYID];
318 318
 
319
-			break;
320
-		}
321
-	}
319
+            break;
320
+        }
321
+    }
322 322
 
323
-	if (!$storeentryid) {
324
-		echo "Can't find default store\n";
323
+    if (!$storeentryid) {
324
+        echo "Can't find default store\n";
325 325
 
326
-		return false;
327
-	}
326
+        return false;
327
+    }
328 328
 
329
-	return mapi_openmsgstore($session, $storeentryid);
329
+    return mapi_openmsgstore($session, $storeentryid);
330 330
 }
331 331
 
332 332
 function forceUTF8($category) {
333
-	$old_locale = setlocale($category, "");
334
-	if (!isset($old_locale) || !$old_locale) {
335
-		echo "Unable to initialize locale\n";
336
-
337
-		exit(1);
338
-	}
339
-	$dot = strpos($old_locale, ".");
340
-	if ($dot) {
341
-		if (strrchr($old_locale, ".") == ".UTF-8" || strrchr($old_locale, ".") == ".utf8") {
342
-			return true;
343
-		}
344
-		$old_locale = substr($old_locale, 0, $dot);
345
-	}
346
-	$new_locale = $old_locale . ".UTF-8";
347
-	$old_locale = setlocale($category, $new_locale);
348
-	if (!$old_locale) {
349
-		$new_locale = "en_US.UTF-8";
350
-		$old_locale = setlocale($category, $new_locale);
351
-	}
352
-	if (!$old_locale) {
353
-		echo "Unable to set locale {$new_locale}\n";
354
-
355
-		exit(1);
356
-	}
357
-
358
-	return true;
333
+    $old_locale = setlocale($category, "");
334
+    if (!isset($old_locale) || !$old_locale) {
335
+        echo "Unable to initialize locale\n";
336
+
337
+        exit(1);
338
+    }
339
+    $dot = strpos($old_locale, ".");
340
+    if ($dot) {
341
+        if (strrchr($old_locale, ".") == ".UTF-8" || strrchr($old_locale, ".") == ".utf8") {
342
+            return true;
343
+        }
344
+        $old_locale = substr($old_locale, 0, $dot);
345
+    }
346
+    $new_locale = $old_locale . ".UTF-8";
347
+    $old_locale = setlocale($category, $new_locale);
348
+    if (!$old_locale) {
349
+        $new_locale = "en_US.UTF-8";
350
+        $old_locale = setlocale($category, $new_locale);
351
+    }
352
+    if (!$old_locale) {
353
+        echo "Unable to set locale {$new_locale}\n";
354
+
355
+        exit(1);
356
+    }
357
+
358
+    return true;
359 359
 }
360 360
 
361 361
 if (!function_exists('mapi_zarafa_getuser_by_name')) {
362
-	/**
363
-	 * Retrieve the user information.
364
-	 *
365
-	 * @param MAPIResource $store
366
-	 * @param string       $username
367
-	 *
368
-	 * @returns array
369
-	 */
370
-	function mapi_zarafa_getuser_by_name($store, $username) {
371
-		$userInfo = get_user_info_by_name($username);
372
-
373
-		if (!is_array($userInfo)) {
374
-			return false;
375
-		}
376
-
377
-		return [
378
-			'userid' => $userInfo['uid'],
379
-			'username' => $username,
380
-			'fullname' => $userInfo['real_name'],
381
-			'emailaddress' => $username,
382
-			'admin' => 0,
383
-			'nonactive' => 0,
384
-		];
385
-	}
362
+    /**
363
+     * Retrieve the user information.
364
+     *
365
+     * @param MAPIResource $store
366
+     * @param string       $username
367
+     *
368
+     * @returns array
369
+     */
370
+    function mapi_zarafa_getuser_by_name($store, $username) {
371
+        $userInfo = get_user_info_by_name($username);
372
+
373
+        if (!is_array($userInfo)) {
374
+            return false;
375
+        }
376
+
377
+        return [
378
+            'userid' => $userInfo['uid'],
379
+            'username' => $username,
380
+            'fullname' => $userInfo['real_name'],
381
+            'emailaddress' => $username,
382
+            'admin' => 0,
383
+            'nonactive' => 0,
384
+        ];
385
+    }
386 386
 }
387 387
 
388 388
 function getGoidFromUid($uid) {
389
-	return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000" .
390
-				bin2hex(pack("V", 12 + strlen($uid)) . "vCal-Uid" . pack("V", 1) . $uid));
389
+    return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000" .
390
+                bin2hex(pack("V", 12 + strlen($uid)) . "vCal-Uid" . pack("V", 1) . $uid));
391 391
 }
392 392
 
393 393
 function getUidFromGoid($goid) {
394
-	// check if "vCal-Uid" is somewhere in outlookid case-insensitive
395
-	$uid = stristr($goid, "vCal-Uid");
396
-	if ($uid !== false) {
397
-		// get the length of the ical id - go back 4 position from where "vCal-Uid" was found
398
-		$begin = unpack("V", substr($goid, strlen($uid) * (-1) - 4, 4));
399
-		// remove "vCal-Uid" and packed "1" and use the ical id length
400
-		return substr($uid, 12, ($begin[1] - 12));
401
-	}
402
-
403
-	return null;
394
+    // check if "vCal-Uid" is somewhere in outlookid case-insensitive
395
+    $uid = stristr($goid, "vCal-Uid");
396
+    if ($uid !== false) {
397
+        // get the length of the ical id - go back 4 position from where "vCal-Uid" was found
398
+        $begin = unpack("V", substr($goid, strlen($uid) * (-1) - 4, 4));
399
+        // remove "vCal-Uid" and packed "1" and use the ical id length
400
+        return substr($uid, 12, ($begin[1] - 12));
401
+    }
402
+
403
+    return null;
404 404
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
 		// OR
224 224
 		[RES_OR,
225 225
 			[
226
-				[RES_AND,    // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd
226
+				[RES_AND, // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd
227 227
 					[
228 228
 						[RES_PROPERTY,
229 229
 							[RELOP => RELOP_GT,
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
 					],
248 248
 				],
249 249
 			], // EXISTS OR
250
-		];        // global OR
250
+		]; // global OR
251 251
 
252 252
 	// Get requested properties, plus whatever we need
253 253
 	$proplist = [PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]];
Please login to merge, or discard this patch.
Braces   +3 added lines, -6 removed lines patch added patch discarded remove patch
@@ -103,8 +103,7 @@  discard block
 block discarded – undo
103 103
 
104 104
 		if (substr($split[2], 0, 2) == "0x") {
105 105
 			$id = hexdec(substr($split[2], 2));
106
-		}
107
-		else {
106
+		} else {
108 107
 			$id = $split[2];
109 108
 		}
110 109
 
@@ -114,8 +113,7 @@  discard block
 block discarded – undo
114 113
 				$guids[$split[1]] = makeguid($split[1]);
115 114
 			}
116 115
 			$guid = $guids[$split[1]];
117
-		}
118
-		else {
116
+		} else {
119 117
 			$guid = constant($split[1]);
120 118
 		}
121 119
 
@@ -272,8 +270,7 @@  discard block
 block discarded – undo
272 270
 				$item = $occurrence + $row;
273 271
 				array_push($items, $item);
274 272
 			}
275
-		}
276
-		else {
273
+		} else {
277 274
 			// Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend>
278 275
 			array_push($items, $row);
279 276
 		}
Please login to merge, or discard this patch.
mapi/mapicode.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -27,7 +27,7 @@  discard block
 block discarded – undo
27 27
  * @param mixed $code
28 28
  */
29 29
 function make_mapi_e($code) {
30
-	return (int) mapi_make_scode(1, $code);
30
+    return (int) mapi_make_scode(1, $code);
31 31
 }
32 32
 
33 33
 /**
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
  * @param mixed $code
37 37
  */
38 38
 function make_mapi_s($code) {
39
-	return (int) mapi_make_scode(0, $code);
39
+    return (int) mapi_make_scode(0, $code);
40 40
 }
41 41
 
42 42
 /* From mapicode.h */
Please login to merge, or discard this patch.
mapi/mapidefs.php 1 patch
Spacing   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -16,40 +16,40 @@  discard block
 block discarded – undo
16 16
 
17 17
 /* Object type */
18 18
 
19
-define('MAPI_STORE', 0x00000001);    /* Message Store */
20
-define('MAPI_ADDRBOOK', 0x00000002);    /* Address Book */
21
-define('MAPI_FOLDER', 0x00000003);    /* Folder */
22
-define('MAPI_ABCONT', 0x00000004);    /* Address Book Container */
23
-define('MAPI_MESSAGE', 0x00000005);    /* Message */
24
-define('MAPI_MAILUSER', 0x00000006);    /* Individual Recipient */
25
-define('MAPI_ATTACH', 0x00000007);    /* Attachment */
26
-define('MAPI_DISTLIST', 0x00000008);    /* Distribution List Recipient */
27
-define('MAPI_PROFSECT', 0x00000009);    /* Profile Section */
28
-define('MAPI_STATUS', 0x0000000A);    /* Status Object */
29
-define('MAPI_SESSION', 0x0000000B);    /* Session */
30
-define('MAPI_FORMINFO', 0x0000000C);    /* Form Information */
19
+define('MAPI_STORE', 0x00000001); /* Message Store */
20
+define('MAPI_ADDRBOOK', 0x00000002); /* Address Book */
21
+define('MAPI_FOLDER', 0x00000003); /* Folder */
22
+define('MAPI_ABCONT', 0x00000004); /* Address Book Container */
23
+define('MAPI_MESSAGE', 0x00000005); /* Message */
24
+define('MAPI_MAILUSER', 0x00000006); /* Individual Recipient */
25
+define('MAPI_ATTACH', 0x00000007); /* Attachment */
26
+define('MAPI_DISTLIST', 0x00000008); /* Distribution List Recipient */
27
+define('MAPI_PROFSECT', 0x00000009); /* Profile Section */
28
+define('MAPI_STATUS', 0x0000000A); /* Status Object */
29
+define('MAPI_SESSION', 0x0000000B); /* Session */
30
+define('MAPI_FORMINFO', 0x0000000C); /* Form Information */
31 31
 
32 32
 define('MV_FLAG', 0x1000);
33 33
 define('MV_INSTANCE', 0x2000);
34 34
 define('MVI_FLAG', MV_FLAG | MV_INSTANCE);
35 35
 
36
-define('PT_UNSPECIFIED', 0);    /* (Reserved for interface use) type doesn't matter to caller */
37
-define('PT_NULL', 1);    /* NULL property value */
38
-define('PT_I2', 2);    /* Signed 16-bit value */
39
-define('PT_LONG', 3);    /* Signed 32-bit value */
40
-define('PT_R4', 4);    /* 4-byte floating point */
41
-define('PT_DOUBLE', 5);    /* Floating point double */
42
-define('PT_CURRENCY', 6);    /* Signed 64-bit int (decimal w/    4 digits right of decimal pt) */
43
-define('PT_APPTIME', 7);    /* Application time */
44
-define('PT_ERROR', 10);    /* 32-bit error value */
45
-define('PT_BOOLEAN', 11);    /* 16-bit boolean (non-zero true) */
46
-define('PT_OBJECT', 13);    /* Embedded object in a property */
47
-define('PT_I8', 20);    /* 8-byte signed integer */
48
-define('PT_STRING8', 30);    /* Null terminated 8-bit character string */
49
-define('PT_UNICODE', 31);    /* Null terminated Unicode string */
50
-define('PT_SYSTIME', 64);    /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
51
-define('PT_CLSID', 72);    /* OLE GUID */
52
-define('PT_BINARY', 258);   /* Uninterpreted (counted byte array) */
36
+define('PT_UNSPECIFIED', 0); /* (Reserved for interface use) type doesn't matter to caller */
37
+define('PT_NULL', 1); /* NULL property value */
38
+define('PT_I2', 2); /* Signed 16-bit value */
39
+define('PT_LONG', 3); /* Signed 32-bit value */
40
+define('PT_R4', 4); /* 4-byte floating point */
41
+define('PT_DOUBLE', 5); /* Floating point double */
42
+define('PT_CURRENCY', 6); /* Signed 64-bit int (decimal w/    4 digits right of decimal pt) */
43
+define('PT_APPTIME', 7); /* Application time */
44
+define('PT_ERROR', 10); /* 32-bit error value */
45
+define('PT_BOOLEAN', 11); /* 16-bit boolean (non-zero true) */
46
+define('PT_OBJECT', 13); /* Embedded object in a property */
47
+define('PT_I8', 20); /* 8-byte signed integer */
48
+define('PT_STRING8', 30); /* Null terminated 8-bit character string */
49
+define('PT_UNICODE', 31); /* Null terminated Unicode string */
50
+define('PT_SYSTIME', 64); /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
51
+define('PT_CLSID', 72); /* OLE GUID */
52
+define('PT_BINARY', 258); /* Uninterpreted (counted byte array) */
53 53
 /* Changes are likely to these numbers, and to their structures. */
54 54
 
55 55
 /* Alternate property type names for ease of use */
@@ -190,14 +190,14 @@  discard block
 block discarded – undo
190 190
 
191 191
 /* Values for PR_RESOURCE_TYPE, _METHODS, _FLAGS */
192 192
 
193
-define('MAPI_STORE_PROVIDER', 33);    /* Message Store */
194
-define('MAPI_AB', 34);    /* Address Book */
195
-define('MAPI_AB_PROVIDER', 35);    /* Address Book Provider */
196
-define('MAPI_TRANSPORT_PROVIDER', 36);    /* Transport Provider */
197
-define('MAPI_SPOOLER', 37);    /* Message Spooler */
198
-define('MAPI_PROFILE_PROVIDER', 38);    /* Profile Provider */
199
-define('MAPI_SUBSYSTEM', 39);    /* Overall Subsystem Status */
200
-define('MAPI_HOOK_PROVIDER', 40);    /* Spooler Hook */
193
+define('MAPI_STORE_PROVIDER', 33); /* Message Store */
194
+define('MAPI_AB', 34); /* Address Book */
195
+define('MAPI_AB_PROVIDER', 35); /* Address Book Provider */
196
+define('MAPI_TRANSPORT_PROVIDER', 36); /* Transport Provider */
197
+define('MAPI_SPOOLER', 37); /* Message Spooler */
198
+define('MAPI_PROFILE_PROVIDER', 38); /* Profile Provider */
199
+define('MAPI_SUBSYSTEM', 39); /* Overall Subsystem Status */
200
+define('MAPI_HOOK_PROVIDER', 40); /* Spooler Hook */
201 201
 define('STATUS_VALIDATE_STATE', 0x00000001);
202 202
 define('STATUS_SETTINGS_DIALOG', 0x00000002);
203 203
 define('STATUS_CHANGE_PASSWORD', 0x00000004);
@@ -243,10 +243,10 @@  discard block
 block discarded – undo
243 243
 define('MODRECIP_MODIFY', 0x00000004);
244 244
 define('MODRECIP_REMOVE', 0x00000008);
245 245
 
246
-define('MAPI_ORIG', 0);          /* Recipient is message originator */
247
-define('MAPI_TO', 1);          /* Recipient is a primary recipient */
248
-define('MAPI_CC', 2);          /* Recipient is a copy recipient */
249
-define('MAPI_BCC', 3);          /* Recipient is blind copy recipient */
246
+define('MAPI_ORIG', 0); /* Recipient is message originator */
247
+define('MAPI_TO', 1); /* Recipient is a primary recipient */
248
+define('MAPI_CC', 2); /* Recipient is a copy recipient */
249
+define('MAPI_BCC', 3); /* Recipient is blind copy recipient */
250 250
 
251 251
 /* IAttach Interface ------------------------------------------------------- */
252 252
 
@@ -438,28 +438,28 @@  discard block
 block discarded – undo
438 438
 define('BMR_NEZ', 0x00000001);
439 439
 
440 440
 /* array index values of restrictions -- same values are used in php-ext/main.cpp::PHPArraytoSRestriction() */
441
-define('VALUE', 0);        // propval
442
-define('RELOP', 1);        // compare method
443
-define('FUZZYLEVEL', 2);        // string search flags
444
-define('CB', 3);        // size restriction
445
-define('ULTYPE', 4);        // bit mask restriction type BMR_xxx
446
-define('ULMASK', 5);        // bitmask
447
-define('ULPROPTAG', 6);        // property
448
-define('ULPROPTAG1', 7);        // RES_COMPAREPROPS 1st property
449
-define('ULPROPTAG2', 8);        // RES_COMPAREPROPS 2nd property
450
-define('PROPS', 9);        // RES_COMMENT properties
451
-define('RESTRICTION', 10);        // RES_COMMENT and RES_SUBRESTRICTION restriction
441
+define('VALUE', 0); // propval
442
+define('RELOP', 1); // compare method
443
+define('FUZZYLEVEL', 2); // string search flags
444
+define('CB', 3); // size restriction
445
+define('ULTYPE', 4); // bit mask restriction type BMR_xxx
446
+define('ULMASK', 5); // bitmask
447
+define('ULPROPTAG', 6); // property
448
+define('ULPROPTAG1', 7); // RES_COMPAREPROPS 1st property
449
+define('ULPROPTAG2', 8); // RES_COMPAREPROPS 2nd property
450
+define('PROPS', 9); // RES_COMMENT properties
451
+define('RESTRICTION', 10); // RES_COMMENT and RES_SUBRESTRICTION restriction
452 452
 
453 453
 /* GUIDs for PR_MDB_PROVIDER */
454
-define("KOPANO_SERVICE_GUID", makeGuid("{3C253DCA-D227-443C-94FE-425FAB958C19}"));    // default store
455
-define("KOPANO_STORE_PUBLIC_GUID", makeGuid("{D47F4A09-D3BD-493C-B2FC-3C90BBCB48D4}"));    // public store
456
-define("KOPANO_STORE_DELEGATE_GUID", makeGuid("{7C7C1085-BC6D-4E53-9DAB-8A53F8DEF808}"));    // other store
457
-define("KOPANO_STORE_ARCHIVER_GUID", makeGuid("{BC8953AD-2E3F-4172-9404-896FF459870F}"));    // archive store
454
+define("KOPANO_SERVICE_GUID", makeGuid("{3C253DCA-D227-443C-94FE-425FAB958C19}")); // default store
455
+define("KOPANO_STORE_PUBLIC_GUID", makeGuid("{D47F4A09-D3BD-493C-B2FC-3C90BBCB48D4}")); // public store
456
+define("KOPANO_STORE_DELEGATE_GUID", makeGuid("{7C7C1085-BC6D-4E53-9DAB-8A53F8DEF808}")); // other store
457
+define("KOPANO_STORE_ARCHIVER_GUID", makeGuid("{BC8953AD-2E3F-4172-9404-896FF459870F}")); // archive store
458 458
 /* webapp depends on these yet */
459
-define("ZARAFA_SERVICE_GUID", makeGuid("{3C253DCA-D227-443C-94FE-425FAB958C19}"));    // default store
460
-define("ZARAFA_STORE_PUBLIC_GUID", makeGuid("{D47F4A09-D3BD-493C-B2FC-3C90BBCB48D4}"));    // public store
461
-define("ZARAFA_STORE_DELEGATE_GUID", makeGuid("{7C7C1085-BC6D-4E53-9DAB-8A53F8DEF808}"));    // other store
462
-define('ZARAFA_STORE_ARCHIVER_GUID', makeGuid("{BC8953AD-2E3F-4172-9404-896FF459870F}"));    // archive store
459
+define("ZARAFA_SERVICE_GUID", makeGuid("{3C253DCA-D227-443C-94FE-425FAB958C19}")); // default store
460
+define("ZARAFA_STORE_PUBLIC_GUID", makeGuid("{D47F4A09-D3BD-493C-B2FC-3C90BBCB48D4}")); // public store
461
+define("ZARAFA_STORE_DELEGATE_GUID", makeGuid("{7C7C1085-BC6D-4E53-9DAB-8A53F8DEF808}")); // other store
462
+define('ZARAFA_STORE_ARCHIVER_GUID', makeGuid("{BC8953AD-2E3F-4172-9404-896FF459870F}")); // archive store
463 463
 
464 464
 /* global profile section guid */
465 465
 define('pbGlobalProfileSectionGuid', makeGuid("{C8B0DB13-05AA-1A10-9BB0-00AA002FC45A}"));
@@ -576,11 +576,11 @@  discard block
 block discarded – undo
576 576
 define('SYNC_NO_FOREIGN_KEYS', 0x100);
577 577
 define('SYNC_LIMITED_IMESSAGE', 0x200);
578 578
 define('SYNC_CATCHUP', 0x400);
579
-define('SYNC_NEW_MESSAGE', 0x800);   // only applicable to ImportMessageChange()
580
-define('SYNC_MSG_SELECTIVE', 0x1000);  // Used internally.      Will reject if used by clients.
579
+define('SYNC_NEW_MESSAGE', 0x800); // only applicable to ImportMessageChange()
580
+define('SYNC_MSG_SELECTIVE', 0x1000); // Used internally.      Will reject if used by clients.
581 581
 define('SYNC_BEST_BODY', 0x2000);
582 582
 define('SYNC_IGNORE_SPECIFIED_ON_ASSOCIATED', 0x4000);
583
-define('SYNC_PROGRESS_MODE', 0x8000);  // AirMapi progress mode
583
+define('SYNC_PROGRESS_MODE', 0x8000); // AirMapi progress mode
584 584
 define('SYNC_FXRECOVERMODE', 0x10000);
585 585
 define('SYNC_DEFER_CONFIG', 0x20000);
586 586
 define('SYNC_FORCE_UNICODE', 0x40000); // Forces server to return Unicode properties
@@ -591,23 +591,23 @@  discard block
 block discarded – undo
591 591
 define('TBL_BATCH', 0x00000002); // Batch multiple table commands
592 592
 
593 593
 /* Flags for recipients in exceptions */
594
-define('recipSendable', 0x00000001);	// sendable attendee.
595
-define('recipOrganizer', 0x00000002);	// meeting organizer
596
-define('recipExceptionalResponse', 0x00000010);	// attendee gave a response for the exception
597
-define('recipExceptionalDeleted', 0x00000020);	// recipientRow exists, but it is treated as if the corresponding recipient is deleted from meeting
598
-define('recipOriginal', 0x00000100);	// recipient is an original Attendee
594
+define('recipSendable', 0x00000001); // sendable attendee.
595
+define('recipOrganizer', 0x00000002); // meeting organizer
596
+define('recipExceptionalResponse', 0x00000010); // attendee gave a response for the exception
597
+define('recipExceptionalDeleted', 0x00000020); // recipientRow exists, but it is treated as if the corresponding recipient is deleted from meeting
598
+define('recipOriginal', 0x00000100); // recipient is an original Attendee
599 599
 define('recipReserved', 0x00000200);
600 600
 
601 601
 /* Flags which indicates type of Meeting Object */
602
-define('mtgEmpty', 0x00000000);	// Unspecified.
603
-define('mtgRequest', 0x00000001);	// Initial meeting request.
604
-define('mtgFull', 0x00010000);	// Full update.
605
-define('mtgInfo', 0x00020000);	// Informational update.
606
-define('mtgOutOfDate', 0x00080000);	// A newer Meeting Request object or Meeting Update object was received after this one.
607
-define('mtgDelegatorCopy', 0x00100000);	// This is set on the delegator's copy when a delegate will handle meeting-related objects.
608
-
609
-define('MAPI_ONE_OFF_UNICODE', 0x8000);		// the flag that defines whether the embedded strings are Unicode in one off entryids.
610
-define('MAPI_ONE_OFF_NO_RICH_INFO', 0x0001);		// the flag that specifies whether the recipient gets TNEF or not.
602
+define('mtgEmpty', 0x00000000); // Unspecified.
603
+define('mtgRequest', 0x00000001); // Initial meeting request.
604
+define('mtgFull', 0x00010000); // Full update.
605
+define('mtgInfo', 0x00020000); // Informational update.
606
+define('mtgOutOfDate', 0x00080000); // A newer Meeting Request object or Meeting Update object was received after this one.
607
+define('mtgDelegatorCopy', 0x00100000); // This is set on the delegator's copy when a delegate will handle meeting-related objects.
608
+
609
+define('MAPI_ONE_OFF_UNICODE', 0x8000); // the flag that defines whether the embedded strings are Unicode in one off entryids.
610
+define('MAPI_ONE_OFF_NO_RICH_INFO', 0x0001); // the flag that specifies whether the recipient gets TNEF or not.
611 611
 
612 612
 /* Mask flags for mapi_msgstore_advise */
613 613
 define('fnevCriticalError', 0x00000001);
Please login to merge, or discard this patch.
mapi/class.mapiexception.php 1 patch
Indentation   +51 added lines, -51 removed lines patch added patch discarded remove patch
@@ -5,62 +5,62 @@
 block discarded – undo
5 5
  * SPDX-FileCopyrightText: Copyright 2020 grommunio GmbH
6 6
  */
7 7
 
8
-	/**
9
-	 * MAPIException
10
-	 * if enabled using mapi_enable_exceptions then php-ext can throw exceptions when
11
-	 * any error occurs in mapi calls. this exception will only be thrown when severity bit is set in
12
-	 * error code that means it will be thrown only for mapi errors not for mapi warnings.
13
-	 */
14
-	class MAPIException extends BaseException {
15
-		/**
16
-		 * Function will return display message of exception if its set by the callee.
17
-		 * if it is not set then we are generating some default display messages based
18
-		 * on mapi error code.
19
-		 *
20
-		 * @return string returns error-message that should be sent to client to display
21
-		 */
22
-		public function getDisplayMessage() {
23
-			if (!empty($this->displayMessage)) {
24
-				return $this->displayMessage;
25
-			}
8
+    /**
9
+     * MAPIException
10
+     * if enabled using mapi_enable_exceptions then php-ext can throw exceptions when
11
+     * any error occurs in mapi calls. this exception will only be thrown when severity bit is set in
12
+     * error code that means it will be thrown only for mapi errors not for mapi warnings.
13
+     */
14
+    class MAPIException extends BaseException {
15
+        /**
16
+         * Function will return display message of exception if its set by the callee.
17
+         * if it is not set then we are generating some default display messages based
18
+         * on mapi error code.
19
+         *
20
+         * @return string returns error-message that should be sent to client to display
21
+         */
22
+        public function getDisplayMessage() {
23
+            if (!empty($this->displayMessage)) {
24
+                return $this->displayMessage;
25
+            }
26 26
 
27
-			switch ($this->getCode()) {
28
-			case MAPI_E_NO_ACCESS:
29
-				return dgettext("kopano", "You have insufficient privileges to open this object.");
27
+            switch ($this->getCode()) {
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()));
59
-			}
60
-		}
61
-	}
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
+            }
60
+        }
61
+    }
62 62
 
63
-	// Tell the PHP extension which exception class to instantiate
64
-	if (function_exists('mapi_enable_exceptions')) {
65
-		mapi_enable_exceptions("mapiexception");
66
-	}
63
+    // Tell the PHP extension which exception class to instantiate
64
+    if (function_exists('mapi_enable_exceptions')) {
65
+        mapi_enable_exceptions("mapiexception");
66
+    }
Please login to merge, or discard this patch.