Completed
Pull Request — developer (#4001)
by Thom
542:26 queued 508:45
created
libraries/SabreDAV/CalDAV/Schedule/IMipPlugin.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -155,7 +155,7 @@
 block discarded – undo
155 155
      * @param string $to Recipient email address
156 156
      * @param string $subject Subject of the email
157 157
      * @param string $body iCalendar body
158
-     * @param array $headers List of headers
158
+     * @param string[] $headers List of headers
159 159
      * @return void
160 160
      */
161 161
     protected function mail($to, $subject, $body, array $headers) {
Please login to merge, or discard this patch.
Braces   +6 added lines, -4 removed lines patch added patch discarded remove patch
@@ -99,11 +99,13 @@
 block discarded – undo
99 99
 
100 100
         $summary = $iTipMessage->message->VEVENT->SUMMARY;
101 101
 
102
-        if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto')
103
-            return;
102
+        if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto') {
103
+                    return;
104
+        }
104 105
 
105
-        if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto')
106
-            return;
106
+        if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto') {
107
+                    return;
108
+        }
107 109
 
108 110
         $sender = substr($iTipMessage->sender, 7);
109 111
         $recipient = substr($iTipMessage->recipient, 7);
Please login to merge, or discard this patch.
Indentation   +155 added lines, -155 removed lines patch added patch discarded remove patch
@@ -21,35 +21,35 @@  discard block
 block discarded – undo
21 21
  */
22 22
 class IMipPlugin extends DAV\ServerPlugin {
23 23
 
24
-    /**
25
-     * Email address used in From: header.
26
-     *
27
-     * @var string
28
-     */
29
-    protected $senderEmail;
30
-
31
-    /**
32
-     * ITipMessage
33
-     *
34
-     * @var ITip\Message
35
-     */
36
-    protected $itipMessage;
37
-
38
-    /**
39
-     * Creates the email handler.
40
-     *
41
-     * @param string $senderEmail. The 'senderEmail' is the email that shows up
42
-     *                             in the 'From:' address. This should
43
-     *                             generally be some kind of no-reply email
44
-     *                             address you own.
45
-     */
46
-    public function __construct($senderEmail) {
47
-
48
-        $this->senderEmail = $senderEmail;
49
-
50
-    }
51
-
52
-    /*
24
+	/**
25
+	 * Email address used in From: header.
26
+	 *
27
+	 * @var string
28
+	 */
29
+	protected $senderEmail;
30
+
31
+	/**
32
+	 * ITipMessage
33
+	 *
34
+	 * @var ITip\Message
35
+	 */
36
+	protected $itipMessage;
37
+
38
+	/**
39
+	 * Creates the email handler.
40
+	 *
41
+	 * @param string $senderEmail. The 'senderEmail' is the email that shows up
42
+	 *                             in the 'From:' address. This should
43
+	 *                             generally be some kind of no-reply email
44
+	 *                             address you own.
45
+	 */
46
+	public function __construct($senderEmail) {
47
+
48
+		$this->senderEmail = $senderEmail;
49
+
50
+	}
51
+
52
+	/*
53 53
      * This initializes the plugin.
54 54
      *
55 55
      * This function is called by Sabre\DAV\Server, after
@@ -60,131 +60,131 @@  discard block
 block discarded – undo
60 60
      * @param DAV\Server $server
61 61
      * @return void
62 62
      */
63
-    public function initialize(DAV\Server $server) {
64
-
65
-        $server->on('schedule', [$this, 'schedule'], 120);
66
-
67
-    }
68
-
69
-    /**
70
-     * Returns a plugin name.
71
-     *
72
-     * Using this name other plugins will be able to access other plugins
73
-     * using \Sabre\DAV\Server::getPlugin
74
-     *
75
-     * @return string
76
-     */
77
-    public function getPluginName() {
78
-
79
-        return 'imip';
80
-
81
-    }
82
-
83
-    /**
84
-     * Event handler for the 'schedule' event.
85
-     *
86
-     * @param ITip\Message $iTipMessage
87
-     * @return void
88
-     */
89
-    public function schedule(ITip\Message $iTipMessage) {
90
-
91
-        // Not sending any emails if the system considers the update
92
-        // insignificant.
93
-        if (!$iTipMessage->significantChange) {
94
-            if (!$iTipMessage->scheduleStatus) {
95
-                $iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email';
96
-            }
97
-            return;
98
-        }
99
-
100
-        $summary = $iTipMessage->message->VEVENT->SUMMARY;
101
-
102
-        if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto')
103
-            return;
104
-
105
-        if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto')
106
-            return;
107
-
108
-        $sender = substr($iTipMessage->sender, 7);
109
-        $recipient = substr($iTipMessage->recipient, 7);
110
-
111
-        if ($iTipMessage->senderName) {
112
-            $sender = $iTipMessage->senderName . ' <' . $sender . '>';
113
-        }
114
-        if ($iTipMessage->recipientName) {
115
-            $recipient = $iTipMessage->recipientName . ' <' . $recipient . '>';
116
-        }
117
-
118
-        $subject = 'SabreDAV iTIP message';
119
-        switch (strtoupper($iTipMessage->method)) {
120
-            case 'REPLY' :
121
-                $subject = 'Re: ' . $summary;
122
-                break;
123
-            case 'REQUEST' :
124
-                $subject = $summary;
125
-                break;
126
-            case 'CANCEL' :
127
-                $subject = 'Cancelled: ' . $summary;
128
-                break;
129
-        }
130
-
131
-        $headers = [
132
-            'Reply-To: ' . $sender,
133
-            'From: ' . $this->senderEmail,
134
-            'Content-Type: text/calendar; charset=UTF-8; method=' . $iTipMessage->method,
135
-        ];
136
-        if (DAV\Server::$exposeVersion) {
137
-            $headers[] = 'X-Sabre-Version: ' . DAV\Version::VERSION;
138
-        }
139
-        $this->mail(
140
-            $recipient,
141
-            $subject,
142
-            $iTipMessage->message->serialize(),
143
-            $headers
144
-        );
145
-        $iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip';
146
-
147
-    }
148
-
149
-    // @codeCoverageIgnoreStart
150
-    // This is deemed untestable in a reasonable manner
151
-
152
-    /**
153
-     * This function is responsible for sending the actual email.
154
-     *
155
-     * @param string $to Recipient email address
156
-     * @param string $subject Subject of the email
157
-     * @param string $body iCalendar body
158
-     * @param array $headers List of headers
159
-     * @return void
160
-     */
161
-    protected function mail($to, $subject, $body, array $headers) {
162
-
163
-        mail($to, $subject, $body, implode("\r\n", $headers));
164
-
165
-    }
166
-
167
-    // @codeCoverageIgnoreEnd
168
-
169
-    /**
170
-     * Returns a bunch of meta-data about the plugin.
171
-     *
172
-     * Providing this information is optional, and is mainly displayed by the
173
-     * Browser plugin.
174
-     *
175
-     * The description key in the returned array may contain html and will not
176
-     * be sanitized.
177
-     *
178
-     * @return array
179
-     */
180
-    public function getPluginInfo() {
181
-
182
-        return [
183
-            'name'        => $this->getPluginName(),
184
-            'description' => 'Email delivery (rfc6037) for CalDAV scheduling',
185
-            'link'        => 'http://sabre.io/dav/scheduling/',
186
-        ];
187
-
188
-    }
63
+	public function initialize(DAV\Server $server) {
64
+
65
+		$server->on('schedule', [$this, 'schedule'], 120);
66
+
67
+	}
68
+
69
+	/**
70
+	 * Returns a plugin name.
71
+	 *
72
+	 * Using this name other plugins will be able to access other plugins
73
+	 * using \Sabre\DAV\Server::getPlugin
74
+	 *
75
+	 * @return string
76
+	 */
77
+	public function getPluginName() {
78
+
79
+		return 'imip';
80
+
81
+	}
82
+
83
+	/**
84
+	 * Event handler for the 'schedule' event.
85
+	 *
86
+	 * @param ITip\Message $iTipMessage
87
+	 * @return void
88
+	 */
89
+	public function schedule(ITip\Message $iTipMessage) {
90
+
91
+		// Not sending any emails if the system considers the update
92
+		// insignificant.
93
+		if (!$iTipMessage->significantChange) {
94
+			if (!$iTipMessage->scheduleStatus) {
95
+				$iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email';
96
+			}
97
+			return;
98
+		}
99
+
100
+		$summary = $iTipMessage->message->VEVENT->SUMMARY;
101
+
102
+		if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto')
103
+			return;
104
+
105
+		if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto')
106
+			return;
107
+
108
+		$sender = substr($iTipMessage->sender, 7);
109
+		$recipient = substr($iTipMessage->recipient, 7);
110
+
111
+		if ($iTipMessage->senderName) {
112
+			$sender = $iTipMessage->senderName . ' <' . $sender . '>';
113
+		}
114
+		if ($iTipMessage->recipientName) {
115
+			$recipient = $iTipMessage->recipientName . ' <' . $recipient . '>';
116
+		}
117
+
118
+		$subject = 'SabreDAV iTIP message';
119
+		switch (strtoupper($iTipMessage->method)) {
120
+			case 'REPLY' :
121
+				$subject = 'Re: ' . $summary;
122
+				break;
123
+			case 'REQUEST' :
124
+				$subject = $summary;
125
+				break;
126
+			case 'CANCEL' :
127
+				$subject = 'Cancelled: ' . $summary;
128
+				break;
129
+		}
130
+
131
+		$headers = [
132
+			'Reply-To: ' . $sender,
133
+			'From: ' . $this->senderEmail,
134
+			'Content-Type: text/calendar; charset=UTF-8; method=' . $iTipMessage->method,
135
+		];
136
+		if (DAV\Server::$exposeVersion) {
137
+			$headers[] = 'X-Sabre-Version: ' . DAV\Version::VERSION;
138
+		}
139
+		$this->mail(
140
+			$recipient,
141
+			$subject,
142
+			$iTipMessage->message->serialize(),
143
+			$headers
144
+		);
145
+		$iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip';
146
+
147
+	}
148
+
149
+	// @codeCoverageIgnoreStart
150
+	// This is deemed untestable in a reasonable manner
151
+
152
+	/**
153
+	 * This function is responsible for sending the actual email.
154
+	 *
155
+	 * @param string $to Recipient email address
156
+	 * @param string $subject Subject of the email
157
+	 * @param string $body iCalendar body
158
+	 * @param array $headers List of headers
159
+	 * @return void
160
+	 */
161
+	protected function mail($to, $subject, $body, array $headers) {
162
+
163
+		mail($to, $subject, $body, implode("\r\n", $headers));
164
+
165
+	}
166
+
167
+	// @codeCoverageIgnoreEnd
168
+
169
+	/**
170
+	 * Returns a bunch of meta-data about the plugin.
171
+	 *
172
+	 * Providing this information is optional, and is mainly displayed by the
173
+	 * Browser plugin.
174
+	 *
175
+	 * The description key in the returned array may contain html and will not
176
+	 * be sanitized.
177
+	 *
178
+	 * @return array
179
+	 */
180
+	public function getPluginInfo() {
181
+
182
+		return [
183
+			'name'        => $this->getPluginName(),
184
+			'description' => 'Email delivery (rfc6037) for CalDAV scheduling',
185
+			'link'        => 'http://sabre.io/dav/scheduling/',
186
+		];
187
+
188
+	}
189 189
 
190 190
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Schedule/Inbox.php 2 patches
Unused Use Statements   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -2,10 +2,10 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\CalDAV\Schedule;
4 4
 
5
-use Sabre\DAV;
6 5
 use Sabre\CalDAV;
7
-use Sabre\DAVACL;
8 6
 use Sabre\CalDAV\Backend;
7
+use Sabre\DAV;
8
+use Sabre\DAVACL;
9 9
 use Sabre\VObject;
10 10
 
11 11
 /**
Please login to merge, or discard this patch.
Indentation   +239 added lines, -239 removed lines patch added patch discarded remove patch
@@ -17,244 +17,244 @@
 block discarded – undo
17 17
  */
18 18
 class Inbox extends DAV\Collection implements IInbox {
19 19
 
20
-    /**
21
-     * CalDAV backend
22
-     *
23
-     * @var Backend\BackendInterface
24
-     */
25
-    protected $caldavBackend;
26
-
27
-    /**
28
-     * The principal Uri
29
-     *
30
-     * @var string
31
-     */
32
-    protected $principalUri;
33
-
34
-    /**
35
-     * Constructor
36
-     *
37
-     * @param Backend\SchedulingSupport $caldavBackend
38
-     * @param string $principalUri
39
-     */
40
-    public function __construct(Backend\SchedulingSupport $caldavBackend, $principalUri) {
41
-
42
-        $this->caldavBackend = $caldavBackend;
43
-        $this->principalUri = $principalUri;
44
-
45
-    }
46
-
47
-    /**
48
-     * Returns the name of the node.
49
-     *
50
-     * This is used to generate the url.
51
-     *
52
-     * @return string
53
-     */
54
-    public function getName() {
55
-
56
-        return 'inbox';
57
-
58
-    }
59
-
60
-    /**
61
-     * Returns an array with all the child nodes
62
-     *
63
-     * @return \Sabre\DAV\INode[]
64
-     */
65
-    public function getChildren() {
66
-
67
-        $objs = $this->caldavBackend->getSchedulingObjects($this->principalUri);
68
-        $children = [];
69
-        foreach ($objs as $obj) {
70
-            $obj['principaluri'] = $this->principalUri;
71
-            $children[] = new SchedulingObject($this->caldavBackend, $obj);
72
-        }
73
-        return $children;
74
-
75
-    }
76
-
77
-    /**
78
-     * Creates a new file in the directory
79
-     *
80
-     * Data will either be supplied as a stream resource, or in certain cases
81
-     * as a string. Keep in mind that you may have to support either.
82
-     *
83
-     * After succesful creation of the file, you may choose to return the ETag
84
-     * of the new file here.
85
-     *
86
-     * The returned ETag must be surrounded by double-quotes (The quotes should
87
-     * be part of the actual string).
88
-     *
89
-     * If you cannot accurately determine the ETag, you should not return it.
90
-     * If you don't store the file exactly as-is (you're transforming it
91
-     * somehow) you should also not return an ETag.
92
-     *
93
-     * This means that if a subsequent GET to this new file does not exactly
94
-     * return the same contents of what was submitted here, you are strongly
95
-     * recommended to omit the ETag.
96
-     *
97
-     * @param string $name Name of the file
98
-     * @param resource|string $data Initial payload
99
-     * @return null|string
100
-     */
101
-    public function createFile($name, $data = null) {
102
-
103
-        $this->caldavBackend->createSchedulingObject($this->principalUri, $name, $data);
104
-
105
-    }
106
-
107
-    /**
108
-     * Returns the owner principal
109
-     *
110
-     * This must be a url to a principal, or null if there's no owner
111
-     *
112
-     * @return string|null
113
-     */
114
-    public function getOwner() {
115
-
116
-        return $this->principalUri;
117
-
118
-    }
119
-
120
-    /**
121
-     * Returns a group principal
122
-     *
123
-     * This must be a url to a principal, or null if there's no owner
124
-     *
125
-     * @return string|null
126
-     */
127
-    public function getGroup() {
128
-
129
-        return null;
130
-
131
-    }
132
-
133
-    /**
134
-     * Returns a list of ACE's for this node.
135
-     *
136
-     * Each ACE has the following properties:
137
-     *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
138
-     *     currently the only supported privileges
139
-     *   * 'principal', a url to the principal who owns the node
140
-     *   * 'protected' (optional), indicating that this ACE is not allowed to
141
-     *      be updated.
142
-     *
143
-     * @return array
144
-     */
145
-    public function getACL() {
146
-
147
-        return [
148
-            [
149
-                'privilege' => '{DAV:}read',
150
-                'principal' => '{DAV:}authenticated',
151
-                'protected' => true,
152
-            ],
153
-            [
154
-                'privilege' => '{DAV:}write-properties',
155
-                'principal' => $this->getOwner(),
156
-                'protected' => true,
157
-            ],
158
-            [
159
-                'privilege' => '{DAV:}unbind',
160
-                'principal' => $this->getOwner(),
161
-                'protected' => true,
162
-            ],
163
-            [
164
-                'privilege' => '{DAV:}unbind',
165
-                'principal' => $this->getOwner() . '/calendar-proxy-write',
166
-                'protected' => true,
167
-            ],
168
-            [
169
-                'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-invite',
170
-                'principal' => '{DAV:}authenticated',
171
-                'protected' => true,
172
-            ],
173
-            [
174
-                'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-reply',
175
-                'principal' => '{DAV:}authenticated',
176
-                'protected' => true,
177
-            ],
178
-        ];
179
-
180
-    }
181
-
182
-    /**
183
-     * Updates the ACL
184
-     *
185
-     * This method will receive a list of new ACE's.
186
-     *
187
-     * @param array $acl
188
-     * @return void
189
-     */
190
-    public function setACL(array $acl) {
191
-
192
-        throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
193
-
194
-    }
195
-
196
-    /**
197
-     * Returns the list of supported privileges for this node.
198
-     *
199
-     * The returned data structure is a list of nested privileges.
200
-     * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
201
-     * standard structure.
202
-     *
203
-     * If null is returned from this method, the default privilege set is used,
204
-     * which is fine for most common usecases.
205
-     *
206
-     * @return array|null
207
-     */
208
-    public function getSupportedPrivilegeSet() {
209
-
210
-        $ns = '{' . CalDAV\Plugin::NS_CALDAV . '}';
211
-
212
-        $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
213
-        $default['aggregates'][] = [
214
-            'privilege'  => $ns . 'schedule-deliver',
215
-            'aggregates' => [
216
-               ['privilege' => $ns . 'schedule-deliver-invite'],
217
-               ['privilege' => $ns . 'schedule-deliver-reply'],
218
-            ],
219
-        ];
220
-        return $default;
221
-
222
-    }
223
-
224
-    /**
225
-     * Performs a calendar-query on the contents of this calendar.
226
-     *
227
-     * The calendar-query is defined in RFC4791 : CalDAV. Using the
228
-     * calendar-query it is possible for a client to request a specific set of
229
-     * object, based on contents of iCalendar properties, date-ranges and
230
-     * iCalendar component types (VTODO, VEVENT).
231
-     *
232
-     * This method should just return a list of (relative) urls that match this
233
-     * query.
234
-     *
235
-     * The list of filters are specified as an array. The exact array is
236
-     * documented by \Sabre\CalDAV\CalendarQueryParser.
237
-     *
238
-     * @param array $filters
239
-     * @return array
240
-     */
241
-    public function calendarQuery(array $filters) {
242
-
243
-        $result = [];
244
-        $validator = new CalDAV\CalendarQueryValidator();
245
-
246
-        $objects = $this->caldavBackend->getSchedulingObjects($this->principalUri);
247
-        foreach ($objects as $object) {
248
-            $vObject = VObject\Reader::read($object['calendardata']);
249
-            if ($validator->validate($vObject, $filters)) {
250
-                $result[] = $object['uri'];
251
-            }
252
-
253
-            // Destroy circular references to PHP will GC the object.
254
-            $vObject->destroy();
255
-        }
256
-        return $result;
257
-
258
-    }
20
+	/**
21
+	 * CalDAV backend
22
+	 *
23
+	 * @var Backend\BackendInterface
24
+	 */
25
+	protected $caldavBackend;
26
+
27
+	/**
28
+	 * The principal Uri
29
+	 *
30
+	 * @var string
31
+	 */
32
+	protected $principalUri;
33
+
34
+	/**
35
+	 * Constructor
36
+	 *
37
+	 * @param Backend\SchedulingSupport $caldavBackend
38
+	 * @param string $principalUri
39
+	 */
40
+	public function __construct(Backend\SchedulingSupport $caldavBackend, $principalUri) {
41
+
42
+		$this->caldavBackend = $caldavBackend;
43
+		$this->principalUri = $principalUri;
44
+
45
+	}
46
+
47
+	/**
48
+	 * Returns the name of the node.
49
+	 *
50
+	 * This is used to generate the url.
51
+	 *
52
+	 * @return string
53
+	 */
54
+	public function getName() {
55
+
56
+		return 'inbox';
57
+
58
+	}
59
+
60
+	/**
61
+	 * Returns an array with all the child nodes
62
+	 *
63
+	 * @return \Sabre\DAV\INode[]
64
+	 */
65
+	public function getChildren() {
66
+
67
+		$objs = $this->caldavBackend->getSchedulingObjects($this->principalUri);
68
+		$children = [];
69
+		foreach ($objs as $obj) {
70
+			$obj['principaluri'] = $this->principalUri;
71
+			$children[] = new SchedulingObject($this->caldavBackend, $obj);
72
+		}
73
+		return $children;
74
+
75
+	}
76
+
77
+	/**
78
+	 * Creates a new file in the directory
79
+	 *
80
+	 * Data will either be supplied as a stream resource, or in certain cases
81
+	 * as a string. Keep in mind that you may have to support either.
82
+	 *
83
+	 * After succesful creation of the file, you may choose to return the ETag
84
+	 * of the new file here.
85
+	 *
86
+	 * The returned ETag must be surrounded by double-quotes (The quotes should
87
+	 * be part of the actual string).
88
+	 *
89
+	 * If you cannot accurately determine the ETag, you should not return it.
90
+	 * If you don't store the file exactly as-is (you're transforming it
91
+	 * somehow) you should also not return an ETag.
92
+	 *
93
+	 * This means that if a subsequent GET to this new file does not exactly
94
+	 * return the same contents of what was submitted here, you are strongly
95
+	 * recommended to omit the ETag.
96
+	 *
97
+	 * @param string $name Name of the file
98
+	 * @param resource|string $data Initial payload
99
+	 * @return null|string
100
+	 */
101
+	public function createFile($name, $data = null) {
102
+
103
+		$this->caldavBackend->createSchedulingObject($this->principalUri, $name, $data);
104
+
105
+	}
106
+
107
+	/**
108
+	 * Returns the owner principal
109
+	 *
110
+	 * This must be a url to a principal, or null if there's no owner
111
+	 *
112
+	 * @return string|null
113
+	 */
114
+	public function getOwner() {
115
+
116
+		return $this->principalUri;
117
+
118
+	}
119
+
120
+	/**
121
+	 * Returns a group principal
122
+	 *
123
+	 * This must be a url to a principal, or null if there's no owner
124
+	 *
125
+	 * @return string|null
126
+	 */
127
+	public function getGroup() {
128
+
129
+		return null;
130
+
131
+	}
132
+
133
+	/**
134
+	 * Returns a list of ACE's for this node.
135
+	 *
136
+	 * Each ACE has the following properties:
137
+	 *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
138
+	 *     currently the only supported privileges
139
+	 *   * 'principal', a url to the principal who owns the node
140
+	 *   * 'protected' (optional), indicating that this ACE is not allowed to
141
+	 *      be updated.
142
+	 *
143
+	 * @return array
144
+	 */
145
+	public function getACL() {
146
+
147
+		return [
148
+			[
149
+				'privilege' => '{DAV:}read',
150
+				'principal' => '{DAV:}authenticated',
151
+				'protected' => true,
152
+			],
153
+			[
154
+				'privilege' => '{DAV:}write-properties',
155
+				'principal' => $this->getOwner(),
156
+				'protected' => true,
157
+			],
158
+			[
159
+				'privilege' => '{DAV:}unbind',
160
+				'principal' => $this->getOwner(),
161
+				'protected' => true,
162
+			],
163
+			[
164
+				'privilege' => '{DAV:}unbind',
165
+				'principal' => $this->getOwner() . '/calendar-proxy-write',
166
+				'protected' => true,
167
+			],
168
+			[
169
+				'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-invite',
170
+				'principal' => '{DAV:}authenticated',
171
+				'protected' => true,
172
+			],
173
+			[
174
+				'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-reply',
175
+				'principal' => '{DAV:}authenticated',
176
+				'protected' => true,
177
+			],
178
+		];
179
+
180
+	}
181
+
182
+	/**
183
+	 * Updates the ACL
184
+	 *
185
+	 * This method will receive a list of new ACE's.
186
+	 *
187
+	 * @param array $acl
188
+	 * @return void
189
+	 */
190
+	public function setACL(array $acl) {
191
+
192
+		throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
193
+
194
+	}
195
+
196
+	/**
197
+	 * Returns the list of supported privileges for this node.
198
+	 *
199
+	 * The returned data structure is a list of nested privileges.
200
+	 * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
201
+	 * standard structure.
202
+	 *
203
+	 * If null is returned from this method, the default privilege set is used,
204
+	 * which is fine for most common usecases.
205
+	 *
206
+	 * @return array|null
207
+	 */
208
+	public function getSupportedPrivilegeSet() {
209
+
210
+		$ns = '{' . CalDAV\Plugin::NS_CALDAV . '}';
211
+
212
+		$default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
213
+		$default['aggregates'][] = [
214
+			'privilege'  => $ns . 'schedule-deliver',
215
+			'aggregates' => [
216
+			   ['privilege' => $ns . 'schedule-deliver-invite'],
217
+			   ['privilege' => $ns . 'schedule-deliver-reply'],
218
+			],
219
+		];
220
+		return $default;
221
+
222
+	}
223
+
224
+	/**
225
+	 * Performs a calendar-query on the contents of this calendar.
226
+	 *
227
+	 * The calendar-query is defined in RFC4791 : CalDAV. Using the
228
+	 * calendar-query it is possible for a client to request a specific set of
229
+	 * object, based on contents of iCalendar properties, date-ranges and
230
+	 * iCalendar component types (VTODO, VEVENT).
231
+	 *
232
+	 * This method should just return a list of (relative) urls that match this
233
+	 * query.
234
+	 *
235
+	 * The list of filters are specified as an array. The exact array is
236
+	 * documented by \Sabre\CalDAV\CalendarQueryParser.
237
+	 *
238
+	 * @param array $filters
239
+	 * @return array
240
+	 */
241
+	public function calendarQuery(array $filters) {
242
+
243
+		$result = [];
244
+		$validator = new CalDAV\CalendarQueryValidator();
245
+
246
+		$objects = $this->caldavBackend->getSchedulingObjects($this->principalUri);
247
+		foreach ($objects as $object) {
248
+			$vObject = VObject\Reader::read($object['calendardata']);
249
+			if ($validator->validate($vObject, $filters)) {
250
+				$result[] = $object['uri'];
251
+			}
252
+
253
+			// Destroy circular references to PHP will GC the object.
254
+			$vObject->destroy();
255
+		}
256
+		return $result;
257
+
258
+	}
259 259
 
260 260
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Schedule/Outbox.php 2 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -2,8 +2,8 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\CalDAV\Schedule;
4 4
 
5
-use Sabre\DAV;
6 5
 use Sabre\CalDAV;
6
+use Sabre\DAV;
7 7
 use Sabre\DAVACL;
8 8
 
9 9
 /**
Please login to merge, or discard this patch.
Indentation   +161 added lines, -161 removed lines patch added patch discarded remove patch
@@ -19,166 +19,166 @@
 block discarded – undo
19 19
  */
20 20
 class Outbox extends DAV\Collection implements IOutbox {
21 21
 
22
-    /**
23
-     * The principal Uri
24
-     *
25
-     * @var string
26
-     */
27
-    protected $principalUri;
28
-
29
-    /**
30
-     * Constructor
31
-     *
32
-     * @param string $principalUri
33
-     */
34
-    public function __construct($principalUri) {
35
-
36
-        $this->principalUri = $principalUri;
37
-
38
-    }
39
-
40
-    /**
41
-     * Returns the name of the node.
42
-     *
43
-     * This is used to generate the url.
44
-     *
45
-     * @return string
46
-     */
47
-    public function getName() {
48
-
49
-        return 'outbox';
50
-
51
-    }
52
-
53
-    /**
54
-     * Returns an array with all the child nodes
55
-     *
56
-     * @return \Sabre\DAV\INode[]
57
-     */
58
-    public function getChildren() {
59
-
60
-        return [];
61
-
62
-    }
63
-
64
-    /**
65
-     * Returns the owner principal
66
-     *
67
-     * This must be a url to a principal, or null if there's no owner
68
-     *
69
-     * @return string|null
70
-     */
71
-    public function getOwner() {
72
-
73
-        return $this->principalUri;
74
-
75
-    }
76
-
77
-    /**
78
-     * Returns a group principal
79
-     *
80
-     * This must be a url to a principal, or null if there's no owner
81
-     *
82
-     * @return string|null
83
-     */
84
-    public function getGroup() {
85
-
86
-        return null;
87
-
88
-    }
89
-
90
-    /**
91
-     * Returns a list of ACE's for this node.
92
-     *
93
-     * Each ACE has the following properties:
94
-     *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
95
-     *     currently the only supported privileges
96
-     *   * 'principal', a url to the principal who owns the node
97
-     *   * 'protected' (optional), indicating that this ACE is not allowed to
98
-     *      be updated.
99
-     *
100
-     * @return array
101
-     */
102
-    public function getACL() {
103
-
104
-        return [
105
-            [
106
-                'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
107
-                'principal' => $this->getOwner(),
108
-                'protected' => true,
109
-            ],
110
-            [
111
-                'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
112
-                'principal' => $this->getOwner(),
113
-                'protected' => true,
114
-            ],
115
-            [
116
-                'privilege' => '{DAV:}read',
117
-                'principal' => $this->getOwner(),
118
-                'protected' => true,
119
-            ],
120
-            [
121
-                'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
122
-                'principal' => $this->getOwner() . '/calendar-proxy-write',
123
-                'protected' => true,
124
-            ],
125
-            [
126
-                'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
127
-                'principal' => $this->getOwner() . '/calendar-proxy-write',
128
-                'protected' => true,
129
-            ],
130
-            [
131
-                'privilege' => '{DAV:}read',
132
-                'principal' => $this->getOwner() . '/calendar-proxy-read',
133
-                'protected' => true,
134
-            ],
135
-            [
136
-                'privilege' => '{DAV:}read',
137
-                'principal' => $this->getOwner() . '/calendar-proxy-write',
138
-                'protected' => true,
139
-            ],
140
-        ];
141
-
142
-    }
143
-
144
-    /**
145
-     * Updates the ACL
146
-     *
147
-     * This method will receive a list of new ACE's.
148
-     *
149
-     * @param array $acl
150
-     * @return void
151
-     */
152
-    public function setACL(array $acl) {
153
-
154
-        throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
155
-
156
-    }
157
-
158
-    /**
159
-     * Returns the list of supported privileges for this node.
160
-     *
161
-     * The returned data structure is a list of nested privileges.
162
-     * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
163
-     * standard structure.
164
-     *
165
-     * If null is returned from this method, the default privilege set is used,
166
-     * which is fine for most common usecases.
167
-     *
168
-     * @return array|null
169
-     */
170
-    public function getSupportedPrivilegeSet() {
171
-
172
-        $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
173
-        $default['aggregates'][] = [
174
-            'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
175
-        ];
176
-        $default['aggregates'][] = [
177
-            'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
178
-        ];
179
-
180
-        return $default;
181
-
182
-    }
22
+	/**
23
+	 * The principal Uri
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $principalUri;
28
+
29
+	/**
30
+	 * Constructor
31
+	 *
32
+	 * @param string $principalUri
33
+	 */
34
+	public function __construct($principalUri) {
35
+
36
+		$this->principalUri = $principalUri;
37
+
38
+	}
39
+
40
+	/**
41
+	 * Returns the name of the node.
42
+	 *
43
+	 * This is used to generate the url.
44
+	 *
45
+	 * @return string
46
+	 */
47
+	public function getName() {
48
+
49
+		return 'outbox';
50
+
51
+	}
52
+
53
+	/**
54
+	 * Returns an array with all the child nodes
55
+	 *
56
+	 * @return \Sabre\DAV\INode[]
57
+	 */
58
+	public function getChildren() {
59
+
60
+		return [];
61
+
62
+	}
63
+
64
+	/**
65
+	 * Returns the owner principal
66
+	 *
67
+	 * This must be a url to a principal, or null if there's no owner
68
+	 *
69
+	 * @return string|null
70
+	 */
71
+	public function getOwner() {
72
+
73
+		return $this->principalUri;
74
+
75
+	}
76
+
77
+	/**
78
+	 * Returns a group principal
79
+	 *
80
+	 * This must be a url to a principal, or null if there's no owner
81
+	 *
82
+	 * @return string|null
83
+	 */
84
+	public function getGroup() {
85
+
86
+		return null;
87
+
88
+	}
89
+
90
+	/**
91
+	 * Returns a list of ACE's for this node.
92
+	 *
93
+	 * Each ACE has the following properties:
94
+	 *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
95
+	 *     currently the only supported privileges
96
+	 *   * 'principal', a url to the principal who owns the node
97
+	 *   * 'protected' (optional), indicating that this ACE is not allowed to
98
+	 *      be updated.
99
+	 *
100
+	 * @return array
101
+	 */
102
+	public function getACL() {
103
+
104
+		return [
105
+			[
106
+				'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
107
+				'principal' => $this->getOwner(),
108
+				'protected' => true,
109
+			],
110
+			[
111
+				'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
112
+				'principal' => $this->getOwner(),
113
+				'protected' => true,
114
+			],
115
+			[
116
+				'privilege' => '{DAV:}read',
117
+				'principal' => $this->getOwner(),
118
+				'protected' => true,
119
+			],
120
+			[
121
+				'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
122
+				'principal' => $this->getOwner() . '/calendar-proxy-write',
123
+				'protected' => true,
124
+			],
125
+			[
126
+				'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
127
+				'principal' => $this->getOwner() . '/calendar-proxy-write',
128
+				'protected' => true,
129
+			],
130
+			[
131
+				'privilege' => '{DAV:}read',
132
+				'principal' => $this->getOwner() . '/calendar-proxy-read',
133
+				'protected' => true,
134
+			],
135
+			[
136
+				'privilege' => '{DAV:}read',
137
+				'principal' => $this->getOwner() . '/calendar-proxy-write',
138
+				'protected' => true,
139
+			],
140
+		];
141
+
142
+	}
143
+
144
+	/**
145
+	 * Updates the ACL
146
+	 *
147
+	 * This method will receive a list of new ACE's.
148
+	 *
149
+	 * @param array $acl
150
+	 * @return void
151
+	 */
152
+	public function setACL(array $acl) {
153
+
154
+		throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
155
+
156
+	}
157
+
158
+	/**
159
+	 * Returns the list of supported privileges for this node.
160
+	 *
161
+	 * The returned data structure is a list of nested privileges.
162
+	 * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
163
+	 * standard structure.
164
+	 *
165
+	 * If null is returned from this method, the default privilege set is used,
166
+	 * which is fine for most common usecases.
167
+	 *
168
+	 * @return array|null
169
+	 */
170
+	public function getSupportedPrivilegeSet() {
171
+
172
+		$default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
173
+		$default['aggregates'][] = [
174
+			'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
175
+		];
176
+		$default['aggregates'][] = [
177
+			'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
178
+		];
179
+
180
+		return $default;
181
+
182
+	}
183 183
 
184 184
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Schedule/Plugin.php 5 patches
Unused Use Statements   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -3,27 +3,27 @@
 block discarded – undo
3 3
 namespace Sabre\CalDAV\Schedule;
4 4
 
5 5
 use DateTimeZone;
6
-use Sabre\DAV\Server;
7
-use Sabre\DAV\ServerPlugin;
6
+use Sabre\CalDAV\ICalendar;
7
+use Sabre\CalDAV\ICalendarObject;
8
+use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
9
+use Sabre\DAVACL;
10
+use Sabre\DAV\Exception\BadRequest;
11
+use Sabre\DAV\Exception\Forbidden;
12
+use Sabre\DAV\Exception\NotFound;
13
+use Sabre\DAV\Exception\NotImplemented;
14
+use Sabre\DAV\INode;
8 15
 use Sabre\DAV\PropFind;
9 16
 use Sabre\DAV\PropPatch;
10
-use Sabre\DAV\INode;
17
+use Sabre\DAV\Server;
18
+use Sabre\DAV\ServerPlugin;
11 19
 use Sabre\DAV\Xml\Property\Href;
12 20
 use Sabre\HTTP\RequestInterface;
13 21
 use Sabre\HTTP\ResponseInterface;
14 22
 use Sabre\VObject;
15
-use Sabre\VObject\Reader;
16 23
 use Sabre\VObject\Component\VCalendar;
17 24
 use Sabre\VObject\ITip;
18 25
 use Sabre\VObject\ITip\Message;
19
-use Sabre\DAVACL;
20
-use Sabre\CalDAV\ICalendar;
21
-use Sabre\CalDAV\ICalendarObject;
22
-use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
23
-use Sabre\DAV\Exception\NotFound;
24
-use Sabre\DAV\Exception\Forbidden;
25
-use Sabre\DAV\Exception\BadRequest;
26
-use Sabre\DAV\Exception\NotImplemented;
26
+use Sabre\VObject\Reader;
27 27
 
28 28
 /**
29 29
  * CalDAV scheduling plugin.
Please login to merge, or discard this patch.
Indentation   +927 added lines, -927 removed lines patch added patch discarded remove patch
@@ -54,939 +54,939 @@
 block discarded – undo
54 54
  */
55 55
 class Plugin extends ServerPlugin {
56 56
 
57
-    /**
58
-     * This is the official CalDAV namespace
59
-     */
60
-    const NS_CALDAV = 'urn:ietf:params:xml:ns:caldav';
61
-
62
-    /**
63
-     * Reference to main Server object.
64
-     *
65
-     * @var Server
66
-     */
67
-    protected $server;
68
-
69
-    /**
70
-     * Returns a list of features for the DAV: HTTP header.
71
-     *
72
-     * @return array
73
-     */
74
-    public function getFeatures() {
75
-
76
-        return ['calendar-auto-schedule', 'calendar-availability'];
77
-
78
-    }
79
-
80
-    /**
81
-     * Returns the name of the plugin.
82
-     *
83
-     * Using this name other plugins will be able to access other plugins
84
-     * using Server::getPlugin
85
-     *
86
-     * @return string
87
-     */
88
-    public function getPluginName() {
89
-
90
-        return 'caldav-schedule';
91
-
92
-    }
93
-
94
-    /**
95
-     * Initializes the plugin
96
-     *
97
-     * @param Server $server
98
-     * @return void
99
-     */
100
-    public function initialize(Server $server) {
101
-
102
-        $this->server = $server;
103
-        $server->on('method:POST',          [$this, 'httpPost']);
104
-        $server->on('propFind',             [$this, 'propFind']);
105
-        $server->on('propPatch',            [$this, 'propPatch']);
106
-        $server->on('calendarObjectChange', [$this, 'calendarObjectChange']);
107
-        $server->on('beforeUnbind',         [$this, 'beforeUnbind']);
108
-        $server->on('schedule',             [$this, 'scheduleLocalDelivery']);
109
-
110
-        $ns = '{' . self::NS_CALDAV . '}';
111
-
112
-        /**
113
-         * This information ensures that the {DAV:}resourcetype property has
114
-         * the correct values.
115
-         */
116
-        $server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IOutbox'] = $ns . 'schedule-outbox';
117
-        $server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IInbox'] = $ns . 'schedule-inbox';
118
-
119
-        /**
120
-         * Properties we protect are made read-only by the server.
121
-         */
122
-        array_push($server->protectedProperties,
123
-            $ns . 'schedule-inbox-URL',
124
-            $ns . 'schedule-outbox-URL',
125
-            $ns . 'calendar-user-address-set',
126
-            $ns . 'calendar-user-type',
127
-            $ns . 'schedule-default-calendar-URL'
128
-        );
129
-
130
-    }
131
-
132
-    /**
133
-     * Use this method to tell the server this plugin defines additional
134
-     * HTTP methods.
135
-     *
136
-     * This method is passed a uri. It should only return HTTP methods that are
137
-     * available for the specified uri.
138
-     *
139
-     * @param string $uri
140
-     * @return array
141
-     */
142
-    public function getHTTPMethods($uri) {
143
-
144
-        try {
145
-            $node = $this->server->tree->getNodeForPath($uri);
146
-        } catch (NotFound $e) {
147
-            return [];
148
-        }
149
-
150
-        if ($node instanceof IOutbox) {
151
-            return ['POST'];
152
-        }
153
-
154
-        return [];
155
-
156
-    }
157
-
158
-    /**
159
-     * This method handles POST request for the outbox.
160
-     *
161
-     * @param RequestInterface $request
162
-     * @param ResponseInterface $response
163
-     * @return bool
164
-     */
165
-    public function httpPost(RequestInterface $request, ResponseInterface $response) {
166
-
167
-        // Checking if this is a text/calendar content type
168
-        $contentType = $request->getHeader('Content-Type');
169
-        if (strpos($contentType, 'text/calendar') !== 0) {
170
-            return;
171
-        }
172
-
173
-        $path = $request->getPath();
174
-
175
-        // Checking if we're talking to an outbox
176
-        try {
177
-            $node = $this->server->tree->getNodeForPath($path);
178
-        } catch (NotFound $e) {
179
-            return;
180
-        }
181
-        if (!$node instanceof IOutbox)
182
-            return;
183
-
184
-        $this->server->transactionType = 'post-caldav-outbox';
185
-        $this->outboxRequest($node, $request, $response);
186
-
187
-        // Returning false breaks the event chain and tells the server we've
188
-        // handled the request.
189
-        return false;
190
-
191
-    }
192
-
193
-    /**
194
-     * This method handler is invoked during fetching of properties.
195
-     *
196
-     * We use this event to add calendar-auto-schedule-specific properties.
197
-     *
198
-     * @param PropFind $propFind
199
-     * @param INode $node
200
-     * @return void
201
-     */
202
-    public function propFind(PropFind $propFind, INode $node) {
203
-
204
-        if ($node instanceof DAVACL\IPrincipal) {
205
-
206
-            $caldavPlugin = $this->server->getPlugin('caldav');
207
-            $principalUrl = $node->getPrincipalUrl();
208
-
209
-            // schedule-outbox-URL property
210
-            $propFind->handle('{' . self::NS_CALDAV . '}schedule-outbox-URL', function() use ($principalUrl, $caldavPlugin) {
211
-
212
-                $calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
213
-                if (!$calendarHomePath) {
214
-                    return null;
215
-                }
216
-                $outboxPath = $calendarHomePath . '/outbox/';
217
-
218
-                return new Href($outboxPath);
219
-
220
-            });
221
-            // schedule-inbox-URL property
222
-            $propFind->handle('{' . self::NS_CALDAV . '}schedule-inbox-URL', function() use ($principalUrl, $caldavPlugin) {
223
-
224
-                $calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
225
-                if (!$calendarHomePath) {
226
-                    return null;
227
-                }
228
-                $inboxPath = $calendarHomePath . '/inbox/';
229
-
230
-                return new Href($inboxPath);
231
-
232
-            });
233
-
234
-            $propFind->handle('{' . self::NS_CALDAV . '}schedule-default-calendar-URL', function() use ($principalUrl, $caldavPlugin) {
235
-
236
-                // We don't support customizing this property yet, so in the
237
-                // meantime we just grab the first calendar in the home-set.
238
-                $calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
239
-
240
-                if (!$calendarHomePath) {
241
-                    return null;
242
-                }
243
-
244
-                $sccs = '{' . self::NS_CALDAV . '}supported-calendar-component-set';
245
-
246
-                $result = $this->server->getPropertiesForPath($calendarHomePath, [
247
-                    '{DAV:}resourcetype',
248
-                    $sccs,
249
-                ], 1);
250
-
251
-                foreach ($result as $child) {
252
-                    if (!isset($child[200]['{DAV:}resourcetype']) || !$child[200]['{DAV:}resourcetype']->is('{' . self::NS_CALDAV . '}calendar') || $child[200]['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared')) {
253
-                        // Node is either not a calendar or a shared instance.
254
-                        continue;
255
-                    }
256
-                    if (!isset($child[200][$sccs]) || in_array('VEVENT', $child[200][$sccs]->getValue())) {
257
-                        // Either there is no supported-calendar-component-set
258
-                        // (which is fine) or we found one that supports VEVENT.
259
-                        return new Href($child['href']);
260
-                    }
261
-                }
262
-
263
-            });
264
-
265
-            // The server currently reports every principal to be of type
266
-            // 'INDIVIDUAL'
267
-            $propFind->handle('{' . self::NS_CALDAV . '}calendar-user-type', function() {
268
-
269
-                return 'INDIVIDUAL';
270
-
271
-            });
272
-
273
-        }
274
-
275
-        // Mapping the old property to the new property.
276
-        $propFind->handle('{http://calendarserver.org/ns/}calendar-availability', function() use ($propFind, $node) {
277
-
278
-             // In case it wasn't clear, the only difference is that we map the
279
-            // old property to a different namespace.
280
-             $availProp = '{' . self::NS_CALDAV . '}calendar-availability';
281
-             $subPropFind = new PropFind(
282
-                 $propFind->getPath(),
283
-                 [$availProp]
284
-             );
285
-
286
-             $this->server->getPropertiesByNode(
287
-                 $subPropFind,
288
-                 $node
289
-             );
290
-
291
-             $propFind->set(
292
-                 '{http://calendarserver.org/ns/}calendar-availability',
293
-                 $subPropFind->get($availProp),
294
-                 $subPropFind->getStatus($availProp)
295
-             );
296
-
297
-        });
298
-
299
-    }
300
-
301
-    /**
302
-     * This method is called during property updates.
303
-     *
304
-     * @param string $path
305
-     * @param PropPatch $propPatch
306
-     * @return void
307
-     */
308
-    public function propPatch($path, PropPatch $propPatch) {
309
-
310
-        // Mapping the old property to the new property.
311
-        $propPatch->handle('{http://calendarserver.org/ns/}calendar-availability', function($value) use ($path) {
312
-
313
-            $availProp = '{' . self::NS_CALDAV . '}calendar-availability';
314
-            $subPropPatch = new PropPatch([$availProp => $value]);
315
-            $this->server->emit('propPatch', [$path, $subPropPatch]);
316
-            $subPropPatch->commit();
317
-
318
-            return $subPropPatch->getResult()[$availProp];
319
-
320
-        });
321
-
322
-    }
323
-
324
-    /**
325
-     * This method is triggered whenever there was a calendar object gets
326
-     * created or updated.
327
-     *
328
-     * @param RequestInterface $request HTTP request
329
-     * @param ResponseInterface $response HTTP Response
330
-     * @param VCalendar $vCal Parsed iCalendar object
331
-     * @param mixed $calendarPath Path to calendar collection
332
-     * @param mixed $modified The iCalendar object has been touched.
333
-     * @param mixed $isNew Whether this was a new item or we're updating one
334
-     * @return void
335
-     */
336
-    public function calendarObjectChange(RequestInterface $request, ResponseInterface $response, VCalendar $vCal, $calendarPath, &$modified, $isNew) {
337
-
338
-        if (!$this->scheduleReply($this->server->httpRequest)) {
339
-            return;
340
-        }
341
-
342
-        $calendarNode = $this->server->tree->getNodeForPath($calendarPath);
343
-
344
-        $addresses = $this->getAddressesForPrincipal(
345
-            $calendarNode->getOwner()
346
-        );
347
-
348
-        if (!$isNew) {
349
-            $node = $this->server->tree->getNodeForPath($request->getPath());
350
-            $oldObj = Reader::read($node->get());
351
-        } else {
352
-            $oldObj = null;
353
-        }
354
-
355
-        $this->processICalendarChange($oldObj, $vCal, $addresses, [], $modified);
356
-
357
-        if ($oldObj) {
358
-            // Destroy circular references so PHP will GC the object.
359
-            $oldObj->destroy();
360
-        }
361
-
362
-    }
363
-
364
-    /**
365
-     * This method is responsible for delivering the ITip message.
366
-     *
367
-     * @param ITip\Message $itipMessage
368
-     * @return void
369
-     */
370
-    public function deliver(ITip\Message $iTipMessage) {
371
-
372
-        $this->server->emit('schedule', [$iTipMessage]);
373
-        if (!$iTipMessage->scheduleStatus) {
374
-            $iTipMessage->scheduleStatus = '5.2;There was no system capable of delivering the scheduling message';
375
-        }
376
-        // In case the change was considered 'insignificant', we are going to
377
-        // remove any error statuses, if any. See ticket #525.
378
-        list($baseCode) = explode('.', $iTipMessage->scheduleStatus);
379
-        if (!$iTipMessage->significantChange && in_array($baseCode, ['3', '5'])) {
380
-            $iTipMessage->scheduleStatus = null;
381
-        }
382
-
383
-    }
384
-
385
-    /**
386
-     * This method is triggered before a file gets deleted.
387
-     *
388
-     * We use this event to make sure that when this happens, attendees get
389
-     * cancellations, and organizers get 'DECLINED' statuses.
390
-     *
391
-     * @param string $path
392
-     * @return void
393
-     */
394
-    public function beforeUnbind($path) {
395
-
396
-        if ($this->server->httpRequest->getMethod() === 'MOVE') return;
397
-
398
-        $node = $this->server->tree->getNodeForPath($path);
399
-
400
-        if (!$node instanceof ICalendarObject || $node instanceof ISchedulingObject) {
401
-            return;
402
-        }
403
-
404
-        if (!$this->scheduleReply($this->server->httpRequest)) {
405
-            return;
406
-        }
407
-
408
-        $addresses = $this->getAddressesForPrincipal(
409
-            $node->getOwner()
410
-        );
411
-
412
-        $broker = new ITip\Broker();
413
-        $messages = $broker->parseEvent(null, $addresses, $node->get());
414
-
415
-        foreach ($messages as $message) {
416
-            $this->deliver($message);
417
-        }
418
-
419
-    }
420
-
421
-    /**
422
-     * Event handler for the 'schedule' event.
423
-     *
424
-     * This handler attempts to look at local accounts to deliver the
425
-     * scheduling object.
426
-     *
427
-     * @param ITip\Message $iTipMessage
428
-     * @return void
429
-     */
430
-    public function scheduleLocalDelivery(ITip\Message $iTipMessage) {
431
-
432
-        $aclPlugin = $this->server->getPlugin('acl');
433
-
434
-        // Local delivery is not available if the ACL plugin is not loaded.
435
-        if (!$aclPlugin) {
436
-            return;
437
-        }
438
-
439
-        $caldavNS = '{' . self::NS_CALDAV . '}';
440
-
441
-        $principalUri = $aclPlugin->getPrincipalByUri($iTipMessage->recipient);
442
-        if (!$principalUri) {
443
-            $iTipMessage->scheduleStatus = '3.7;Could not find principal.';
444
-            return;
445
-        }
446
-
447
-        // We found a principal URL, now we need to find its inbox.
448
-        // Unfortunately we may not have sufficient privileges to find this, so
449
-        // we are temporarily turning off ACL to let this come through.
450
-        //
451
-        // Once we support PHP 5.5, this should be wrapped in a try..finally
452
-        // block so we can ensure that this privilege gets added again after.
453
-        $this->server->removeListener('propFind', [$aclPlugin, 'propFind']);
454
-
455
-        $result = $this->server->getProperties(
456
-            $principalUri,
457
-            [
458
-                '{DAV:}principal-URL',
459
-                 $caldavNS . 'calendar-home-set',
460
-                 $caldavNS . 'schedule-inbox-URL',
461
-                 $caldavNS . 'schedule-default-calendar-URL',
462
-                '{http://sabredav.org/ns}email-address',
463
-            ]
464
-        );
465
-
466
-        // Re-registering the ACL event
467
-        $this->server->on('propFind', [$aclPlugin, 'propFind'], 20);
468
-
469
-        if (!isset($result[$caldavNS . 'schedule-inbox-URL'])) {
470
-            $iTipMessage->scheduleStatus = '5.2;Could not find local inbox';
471
-            return;
472
-        }
473
-        if (!isset($result[$caldavNS . 'calendar-home-set'])) {
474
-            $iTipMessage->scheduleStatus = '5.2;Could not locate a calendar-home-set';
475
-            return;
476
-        }
477
-        if (!isset($result[$caldavNS . 'schedule-default-calendar-URL'])) {
478
-            $iTipMessage->scheduleStatus = '5.2;Could not find a schedule-default-calendar-URL property';
479
-            return;
480
-        }
481
-
482
-        $calendarPath = $result[$caldavNS . 'schedule-default-calendar-URL']->getHref();
483
-        $homePath = $result[$caldavNS . 'calendar-home-set']->getHref();
484
-        $inboxPath = $result[$caldavNS . 'schedule-inbox-URL']->getHref();
485
-
486
-        if ($iTipMessage->method === 'REPLY') {
487
-            $privilege = 'schedule-deliver-reply';
488
-        } else {
489
-            $privilege = 'schedule-deliver-invite';
490
-        }
491
-
492
-        if (!$aclPlugin->checkPrivileges($inboxPath, $caldavNS . $privilege, DAVACL\Plugin::R_PARENT, false)) {
493
-            $iTipMessage->scheduleStatus = '3.8;organizer did not have the ' . $privilege . ' privilege on the attendees inbox';
494
-            return;
495
-        }
496
-
497
-        // Next, we're going to find out if the item already exits in one of
498
-        // the users' calendars.
499
-        $uid = $iTipMessage->uid;
500
-
501
-        $newFileName = 'sabredav-' . \Sabre\DAV\UUIDUtil::getUUID() . '.ics';
502
-
503
-        $home = $this->server->tree->getNodeForPath($homePath);
504
-        $inbox = $this->server->tree->getNodeForPath($inboxPath);
505
-
506
-        $currentObject = null;
507
-        $objectNode = null;
508
-        $isNewNode = false;
509
-
510
-        $result = $home->getCalendarObjectByUID($uid);
511
-        if ($result) {
512
-            // There was an existing object, we need to update probably.
513
-            $objectPath = $homePath . '/' . $result;
514
-            $objectNode = $this->server->tree->getNodeForPath($objectPath);
515
-            $oldICalendarData = $objectNode->get();
516
-            $currentObject = Reader::read($oldICalendarData);
517
-        } else {
518
-            $isNewNode = true;
519
-        }
520
-
521
-        $broker = new ITip\Broker();
522
-        $newObject = $broker->processMessage($iTipMessage, $currentObject);
523
-
524
-        $inbox->createFile($newFileName, $iTipMessage->message->serialize());
525
-
526
-        if (!$newObject) {
527
-            // We received an iTip message referring to a UID that we don't
528
-            // have in any calendars yet, and processMessage did not give us a
529
-            // calendarobject back.
530
-            //
531
-            // The implication is that processMessage did not understand the
532
-            // iTip message.
533
-            $iTipMessage->scheduleStatus = '5.0;iTip message was not processed by the server, likely because we didn\'t understand it.';
534
-            return;
535
-        }
536
-
537
-        // Note that we are bypassing ACL on purpose by calling this directly.
538
-        // We may need to look a bit deeper into this later. Supporting ACL
539
-        // here would be nice.
540
-        if ($isNewNode) {
541
-            $calendar = $this->server->tree->getNodeForPath($calendarPath);
542
-            $calendar->createFile($newFileName, $newObject->serialize());
543
-        } else {
544
-            // If the message was a reply, we may have to inform other
545
-            // attendees of this attendees status. Therefore we're shooting off
546
-            // another itipMessage.
547
-            if ($iTipMessage->method === 'REPLY') {
548
-                $this->processICalendarChange(
549
-                    $oldICalendarData,
550
-                    $newObject,
551
-                    [$iTipMessage->recipient],
552
-                    [$iTipMessage->sender]
553
-                );
554
-            }
555
-            $objectNode->put($newObject->serialize());
556
-        }
557
-        $iTipMessage->scheduleStatus = '1.2;Message delivered locally';
558
-
559
-    }
560
-
561
-    /**
562
-     * This method looks at an old iCalendar object, a new iCalendar object and
563
-     * starts sending scheduling messages based on the changes.
564
-     *
565
-     * A list of addresses needs to be specified, so the system knows who made
566
-     * the update, because the behavior may be different based on if it's an
567
-     * attendee or an organizer.
568
-     *
569
-     * This method may update $newObject to add any status changes.
570
-     *
571
-     * @param VCalendar|string $oldObject
572
-     * @param VCalendar $newObject
573
-     * @param array $addresses
574
-     * @param array $ignore Any addresses to not send messages to.
575
-     * @param bool $modified A marker to indicate that the original object
576
-     *   modified by this process.
577
-     * @return void
578
-     */
579
-    protected function processICalendarChange($oldObject = null, VCalendar $newObject, array $addresses, array $ignore = [], &$modified = false) {
580
-
581
-        $broker = new ITip\Broker();
582
-        $messages = $broker->parseEvent($newObject, $addresses, $oldObject);
583
-
584
-        if ($messages) $modified = true;
585
-
586
-        foreach ($messages as $message) {
587
-
588
-            if (in_array($message->recipient, $ignore)) {
589
-                continue;
590
-            }
591
-
592
-            $this->deliver($message);
593
-
594
-            if (isset($newObject->VEVENT->ORGANIZER) && ($newObject->VEVENT->ORGANIZER->getNormalizedValue() === $message->recipient)) {
595
-                if ($message->scheduleStatus) {
596
-                    $newObject->VEVENT->ORGANIZER['SCHEDULE-STATUS'] = $message->getScheduleStatus();
597
-                }
598
-                unset($newObject->VEVENT->ORGANIZER['SCHEDULE-FORCE-SEND']);
599
-
600
-            } else {
601
-
602
-                if (isset($newObject->VEVENT->ATTENDEE)) foreach ($newObject->VEVENT->ATTENDEE as $attendee) {
603
-
604
-                    if ($attendee->getNormalizedValue() === $message->recipient) {
605
-                        if ($message->scheduleStatus) {
606
-                            $attendee['SCHEDULE-STATUS'] = $message->getScheduleStatus();
607
-                        }
608
-                        unset($attendee['SCHEDULE-FORCE-SEND']);
609
-                        break;
610
-                    }
611
-
612
-                }
613
-
614
-            }
615
-
616
-        }
617
-
618
-    }
619
-
620
-    /**
621
-     * Returns a list of addresses that are associated with a principal.
622
-     *
623
-     * @param string $principal
624
-     * @return array
625
-     */
626
-    protected function getAddressesForPrincipal($principal) {
627
-
628
-        $CUAS = '{' . self::NS_CALDAV . '}calendar-user-address-set';
629
-
630
-        $properties = $this->server->getProperties(
631
-            $principal,
632
-            [$CUAS]
633
-        );
634
-
635
-        // If we can't find this information, we'll stop processing
636
-        if (!isset($properties[$CUAS])) {
637
-            return;
638
-        }
639
-
640
-        $addresses = $properties[$CUAS]->getHrefs();
641
-        return $addresses;
642
-
643
-    }
644
-
645
-    /**
646
-     * This method handles POST requests to the schedule-outbox.
647
-     *
648
-     * Currently, two types of requests are support:
649
-     *   * FREEBUSY requests from RFC 6638
650
-     *   * Simple iTIP messages from draft-desruisseaux-caldav-sched-04
651
-     *
652
-     * The latter is from an expired early draft of the CalDAV scheduling
653
-     * extensions, but iCal depends on a feature from that spec, so we
654
-     * implement it.
655
-     *
656
-     * @param IOutbox $outboxNode
657
-     * @param RequestInterface $request
658
-     * @param ResponseInterface $response
659
-     * @return void
660
-     */
661
-    public function outboxRequest(IOutbox $outboxNode, RequestInterface $request, ResponseInterface $response) {
662
-
663
-        $outboxPath = $request->getPath();
664
-
665
-        // Parsing the request body
666
-        try {
667
-            $vObject = VObject\Reader::read($request->getBody());
668
-        } catch (VObject\ParseException $e) {
669
-            throw new BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
670
-        }
671
-
672
-        // The incoming iCalendar object must have a METHOD property, and a
673
-        // component. The combination of both determines what type of request
674
-        // this is.
675
-        $componentType = null;
676
-        foreach ($vObject->getComponents() as $component) {
677
-            if ($component->name !== 'VTIMEZONE') {
678
-                $componentType = $component->name;
679
-                break;
680
-            }
681
-        }
682
-        if (is_null($componentType)) {
683
-            throw new BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component');
684
-        }
57
+	/**
58
+	 * This is the official CalDAV namespace
59
+	 */
60
+	const NS_CALDAV = 'urn:ietf:params:xml:ns:caldav';
61
+
62
+	/**
63
+	 * Reference to main Server object.
64
+	 *
65
+	 * @var Server
66
+	 */
67
+	protected $server;
68
+
69
+	/**
70
+	 * Returns a list of features for the DAV: HTTP header.
71
+	 *
72
+	 * @return array
73
+	 */
74
+	public function getFeatures() {
75
+
76
+		return ['calendar-auto-schedule', 'calendar-availability'];
77
+
78
+	}
79
+
80
+	/**
81
+	 * Returns the name of the plugin.
82
+	 *
83
+	 * Using this name other plugins will be able to access other plugins
84
+	 * using Server::getPlugin
85
+	 *
86
+	 * @return string
87
+	 */
88
+	public function getPluginName() {
89
+
90
+		return 'caldav-schedule';
91
+
92
+	}
93
+
94
+	/**
95
+	 * Initializes the plugin
96
+	 *
97
+	 * @param Server $server
98
+	 * @return void
99
+	 */
100
+	public function initialize(Server $server) {
101
+
102
+		$this->server = $server;
103
+		$server->on('method:POST',          [$this, 'httpPost']);
104
+		$server->on('propFind',             [$this, 'propFind']);
105
+		$server->on('propPatch',            [$this, 'propPatch']);
106
+		$server->on('calendarObjectChange', [$this, 'calendarObjectChange']);
107
+		$server->on('beforeUnbind',         [$this, 'beforeUnbind']);
108
+		$server->on('schedule',             [$this, 'scheduleLocalDelivery']);
109
+
110
+		$ns = '{' . self::NS_CALDAV . '}';
111
+
112
+		/**
113
+		 * This information ensures that the {DAV:}resourcetype property has
114
+		 * the correct values.
115
+		 */
116
+		$server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IOutbox'] = $ns . 'schedule-outbox';
117
+		$server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IInbox'] = $ns . 'schedule-inbox';
118
+
119
+		/**
120
+		 * Properties we protect are made read-only by the server.
121
+		 */
122
+		array_push($server->protectedProperties,
123
+			$ns . 'schedule-inbox-URL',
124
+			$ns . 'schedule-outbox-URL',
125
+			$ns . 'calendar-user-address-set',
126
+			$ns . 'calendar-user-type',
127
+			$ns . 'schedule-default-calendar-URL'
128
+		);
129
+
130
+	}
131
+
132
+	/**
133
+	 * Use this method to tell the server this plugin defines additional
134
+	 * HTTP methods.
135
+	 *
136
+	 * This method is passed a uri. It should only return HTTP methods that are
137
+	 * available for the specified uri.
138
+	 *
139
+	 * @param string $uri
140
+	 * @return array
141
+	 */
142
+	public function getHTTPMethods($uri) {
143
+
144
+		try {
145
+			$node = $this->server->tree->getNodeForPath($uri);
146
+		} catch (NotFound $e) {
147
+			return [];
148
+		}
149
+
150
+		if ($node instanceof IOutbox) {
151
+			return ['POST'];
152
+		}
153
+
154
+		return [];
155
+
156
+	}
157
+
158
+	/**
159
+	 * This method handles POST request for the outbox.
160
+	 *
161
+	 * @param RequestInterface $request
162
+	 * @param ResponseInterface $response
163
+	 * @return bool
164
+	 */
165
+	public function httpPost(RequestInterface $request, ResponseInterface $response) {
166
+
167
+		// Checking if this is a text/calendar content type
168
+		$contentType = $request->getHeader('Content-Type');
169
+		if (strpos($contentType, 'text/calendar') !== 0) {
170
+			return;
171
+		}
172
+
173
+		$path = $request->getPath();
174
+
175
+		// Checking if we're talking to an outbox
176
+		try {
177
+			$node = $this->server->tree->getNodeForPath($path);
178
+		} catch (NotFound $e) {
179
+			return;
180
+		}
181
+		if (!$node instanceof IOutbox)
182
+			return;
183
+
184
+		$this->server->transactionType = 'post-caldav-outbox';
185
+		$this->outboxRequest($node, $request, $response);
186
+
187
+		// Returning false breaks the event chain and tells the server we've
188
+		// handled the request.
189
+		return false;
190
+
191
+	}
192
+
193
+	/**
194
+	 * This method handler is invoked during fetching of properties.
195
+	 *
196
+	 * We use this event to add calendar-auto-schedule-specific properties.
197
+	 *
198
+	 * @param PropFind $propFind
199
+	 * @param INode $node
200
+	 * @return void
201
+	 */
202
+	public function propFind(PropFind $propFind, INode $node) {
203
+
204
+		if ($node instanceof DAVACL\IPrincipal) {
205
+
206
+			$caldavPlugin = $this->server->getPlugin('caldav');
207
+			$principalUrl = $node->getPrincipalUrl();
208
+
209
+			// schedule-outbox-URL property
210
+			$propFind->handle('{' . self::NS_CALDAV . '}schedule-outbox-URL', function() use ($principalUrl, $caldavPlugin) {
211
+
212
+				$calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
213
+				if (!$calendarHomePath) {
214
+					return null;
215
+				}
216
+				$outboxPath = $calendarHomePath . '/outbox/';
217
+
218
+				return new Href($outboxPath);
219
+
220
+			});
221
+			// schedule-inbox-URL property
222
+			$propFind->handle('{' . self::NS_CALDAV . '}schedule-inbox-URL', function() use ($principalUrl, $caldavPlugin) {
223
+
224
+				$calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
225
+				if (!$calendarHomePath) {
226
+					return null;
227
+				}
228
+				$inboxPath = $calendarHomePath . '/inbox/';
229
+
230
+				return new Href($inboxPath);
231
+
232
+			});
233
+
234
+			$propFind->handle('{' . self::NS_CALDAV . '}schedule-default-calendar-URL', function() use ($principalUrl, $caldavPlugin) {
235
+
236
+				// We don't support customizing this property yet, so in the
237
+				// meantime we just grab the first calendar in the home-set.
238
+				$calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
239
+
240
+				if (!$calendarHomePath) {
241
+					return null;
242
+				}
243
+
244
+				$sccs = '{' . self::NS_CALDAV . '}supported-calendar-component-set';
245
+
246
+				$result = $this->server->getPropertiesForPath($calendarHomePath, [
247
+					'{DAV:}resourcetype',
248
+					$sccs,
249
+				], 1);
250
+
251
+				foreach ($result as $child) {
252
+					if (!isset($child[200]['{DAV:}resourcetype']) || !$child[200]['{DAV:}resourcetype']->is('{' . self::NS_CALDAV . '}calendar') || $child[200]['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared')) {
253
+						// Node is either not a calendar or a shared instance.
254
+						continue;
255
+					}
256
+					if (!isset($child[200][$sccs]) || in_array('VEVENT', $child[200][$sccs]->getValue())) {
257
+						// Either there is no supported-calendar-component-set
258
+						// (which is fine) or we found one that supports VEVENT.
259
+						return new Href($child['href']);
260
+					}
261
+				}
262
+
263
+			});
264
+
265
+			// The server currently reports every principal to be of type
266
+			// 'INDIVIDUAL'
267
+			$propFind->handle('{' . self::NS_CALDAV . '}calendar-user-type', function() {
268
+
269
+				return 'INDIVIDUAL';
270
+
271
+			});
272
+
273
+		}
274
+
275
+		// Mapping the old property to the new property.
276
+		$propFind->handle('{http://calendarserver.org/ns/}calendar-availability', function() use ($propFind, $node) {
277
+
278
+			 // In case it wasn't clear, the only difference is that we map the
279
+			// old property to a different namespace.
280
+			 $availProp = '{' . self::NS_CALDAV . '}calendar-availability';
281
+			 $subPropFind = new PropFind(
282
+				 $propFind->getPath(),
283
+				 [$availProp]
284
+			 );
285
+
286
+			 $this->server->getPropertiesByNode(
287
+				 $subPropFind,
288
+				 $node
289
+			 );
290
+
291
+			 $propFind->set(
292
+				 '{http://calendarserver.org/ns/}calendar-availability',
293
+				 $subPropFind->get($availProp),
294
+				 $subPropFind->getStatus($availProp)
295
+			 );
296
+
297
+		});
298
+
299
+	}
300
+
301
+	/**
302
+	 * This method is called during property updates.
303
+	 *
304
+	 * @param string $path
305
+	 * @param PropPatch $propPatch
306
+	 * @return void
307
+	 */
308
+	public function propPatch($path, PropPatch $propPatch) {
309
+
310
+		// Mapping the old property to the new property.
311
+		$propPatch->handle('{http://calendarserver.org/ns/}calendar-availability', function($value) use ($path) {
312
+
313
+			$availProp = '{' . self::NS_CALDAV . '}calendar-availability';
314
+			$subPropPatch = new PropPatch([$availProp => $value]);
315
+			$this->server->emit('propPatch', [$path, $subPropPatch]);
316
+			$subPropPatch->commit();
317
+
318
+			return $subPropPatch->getResult()[$availProp];
319
+
320
+		});
321
+
322
+	}
323
+
324
+	/**
325
+	 * This method is triggered whenever there was a calendar object gets
326
+	 * created or updated.
327
+	 *
328
+	 * @param RequestInterface $request HTTP request
329
+	 * @param ResponseInterface $response HTTP Response
330
+	 * @param VCalendar $vCal Parsed iCalendar object
331
+	 * @param mixed $calendarPath Path to calendar collection
332
+	 * @param mixed $modified The iCalendar object has been touched.
333
+	 * @param mixed $isNew Whether this was a new item or we're updating one
334
+	 * @return void
335
+	 */
336
+	public function calendarObjectChange(RequestInterface $request, ResponseInterface $response, VCalendar $vCal, $calendarPath, &$modified, $isNew) {
337
+
338
+		if (!$this->scheduleReply($this->server->httpRequest)) {
339
+			return;
340
+		}
341
+
342
+		$calendarNode = $this->server->tree->getNodeForPath($calendarPath);
343
+
344
+		$addresses = $this->getAddressesForPrincipal(
345
+			$calendarNode->getOwner()
346
+		);
347
+
348
+		if (!$isNew) {
349
+			$node = $this->server->tree->getNodeForPath($request->getPath());
350
+			$oldObj = Reader::read($node->get());
351
+		} else {
352
+			$oldObj = null;
353
+		}
354
+
355
+		$this->processICalendarChange($oldObj, $vCal, $addresses, [], $modified);
356
+
357
+		if ($oldObj) {
358
+			// Destroy circular references so PHP will GC the object.
359
+			$oldObj->destroy();
360
+		}
361
+
362
+	}
363
+
364
+	/**
365
+	 * This method is responsible for delivering the ITip message.
366
+	 *
367
+	 * @param ITip\Message $itipMessage
368
+	 * @return void
369
+	 */
370
+	public function deliver(ITip\Message $iTipMessage) {
371
+
372
+		$this->server->emit('schedule', [$iTipMessage]);
373
+		if (!$iTipMessage->scheduleStatus) {
374
+			$iTipMessage->scheduleStatus = '5.2;There was no system capable of delivering the scheduling message';
375
+		}
376
+		// In case the change was considered 'insignificant', we are going to
377
+		// remove any error statuses, if any. See ticket #525.
378
+		list($baseCode) = explode('.', $iTipMessage->scheduleStatus);
379
+		if (!$iTipMessage->significantChange && in_array($baseCode, ['3', '5'])) {
380
+			$iTipMessage->scheduleStatus = null;
381
+		}
382
+
383
+	}
384
+
385
+	/**
386
+	 * This method is triggered before a file gets deleted.
387
+	 *
388
+	 * We use this event to make sure that when this happens, attendees get
389
+	 * cancellations, and organizers get 'DECLINED' statuses.
390
+	 *
391
+	 * @param string $path
392
+	 * @return void
393
+	 */
394
+	public function beforeUnbind($path) {
395
+
396
+		if ($this->server->httpRequest->getMethod() === 'MOVE') return;
397
+
398
+		$node = $this->server->tree->getNodeForPath($path);
399
+
400
+		if (!$node instanceof ICalendarObject || $node instanceof ISchedulingObject) {
401
+			return;
402
+		}
403
+
404
+		if (!$this->scheduleReply($this->server->httpRequest)) {
405
+			return;
406
+		}
407
+
408
+		$addresses = $this->getAddressesForPrincipal(
409
+			$node->getOwner()
410
+		);
411
+
412
+		$broker = new ITip\Broker();
413
+		$messages = $broker->parseEvent(null, $addresses, $node->get());
414
+
415
+		foreach ($messages as $message) {
416
+			$this->deliver($message);
417
+		}
418
+
419
+	}
420
+
421
+	/**
422
+	 * Event handler for the 'schedule' event.
423
+	 *
424
+	 * This handler attempts to look at local accounts to deliver the
425
+	 * scheduling object.
426
+	 *
427
+	 * @param ITip\Message $iTipMessage
428
+	 * @return void
429
+	 */
430
+	public function scheduleLocalDelivery(ITip\Message $iTipMessage) {
431
+
432
+		$aclPlugin = $this->server->getPlugin('acl');
433
+
434
+		// Local delivery is not available if the ACL plugin is not loaded.
435
+		if (!$aclPlugin) {
436
+			return;
437
+		}
438
+
439
+		$caldavNS = '{' . self::NS_CALDAV . '}';
440
+
441
+		$principalUri = $aclPlugin->getPrincipalByUri($iTipMessage->recipient);
442
+		if (!$principalUri) {
443
+			$iTipMessage->scheduleStatus = '3.7;Could not find principal.';
444
+			return;
445
+		}
446
+
447
+		// We found a principal URL, now we need to find its inbox.
448
+		// Unfortunately we may not have sufficient privileges to find this, so
449
+		// we are temporarily turning off ACL to let this come through.
450
+		//
451
+		// Once we support PHP 5.5, this should be wrapped in a try..finally
452
+		// block so we can ensure that this privilege gets added again after.
453
+		$this->server->removeListener('propFind', [$aclPlugin, 'propFind']);
454
+
455
+		$result = $this->server->getProperties(
456
+			$principalUri,
457
+			[
458
+				'{DAV:}principal-URL',
459
+				 $caldavNS . 'calendar-home-set',
460
+				 $caldavNS . 'schedule-inbox-URL',
461
+				 $caldavNS . 'schedule-default-calendar-URL',
462
+				'{http://sabredav.org/ns}email-address',
463
+			]
464
+		);
465
+
466
+		// Re-registering the ACL event
467
+		$this->server->on('propFind', [$aclPlugin, 'propFind'], 20);
468
+
469
+		if (!isset($result[$caldavNS . 'schedule-inbox-URL'])) {
470
+			$iTipMessage->scheduleStatus = '5.2;Could not find local inbox';
471
+			return;
472
+		}
473
+		if (!isset($result[$caldavNS . 'calendar-home-set'])) {
474
+			$iTipMessage->scheduleStatus = '5.2;Could not locate a calendar-home-set';
475
+			return;
476
+		}
477
+		if (!isset($result[$caldavNS . 'schedule-default-calendar-URL'])) {
478
+			$iTipMessage->scheduleStatus = '5.2;Could not find a schedule-default-calendar-URL property';
479
+			return;
480
+		}
481
+
482
+		$calendarPath = $result[$caldavNS . 'schedule-default-calendar-URL']->getHref();
483
+		$homePath = $result[$caldavNS . 'calendar-home-set']->getHref();
484
+		$inboxPath = $result[$caldavNS . 'schedule-inbox-URL']->getHref();
485
+
486
+		if ($iTipMessage->method === 'REPLY') {
487
+			$privilege = 'schedule-deliver-reply';
488
+		} else {
489
+			$privilege = 'schedule-deliver-invite';
490
+		}
491
+
492
+		if (!$aclPlugin->checkPrivileges($inboxPath, $caldavNS . $privilege, DAVACL\Plugin::R_PARENT, false)) {
493
+			$iTipMessage->scheduleStatus = '3.8;organizer did not have the ' . $privilege . ' privilege on the attendees inbox';
494
+			return;
495
+		}
496
+
497
+		// Next, we're going to find out if the item already exits in one of
498
+		// the users' calendars.
499
+		$uid = $iTipMessage->uid;
500
+
501
+		$newFileName = 'sabredav-' . \Sabre\DAV\UUIDUtil::getUUID() . '.ics';
502
+
503
+		$home = $this->server->tree->getNodeForPath($homePath);
504
+		$inbox = $this->server->tree->getNodeForPath($inboxPath);
505
+
506
+		$currentObject = null;
507
+		$objectNode = null;
508
+		$isNewNode = false;
509
+
510
+		$result = $home->getCalendarObjectByUID($uid);
511
+		if ($result) {
512
+			// There was an existing object, we need to update probably.
513
+			$objectPath = $homePath . '/' . $result;
514
+			$objectNode = $this->server->tree->getNodeForPath($objectPath);
515
+			$oldICalendarData = $objectNode->get();
516
+			$currentObject = Reader::read($oldICalendarData);
517
+		} else {
518
+			$isNewNode = true;
519
+		}
520
+
521
+		$broker = new ITip\Broker();
522
+		$newObject = $broker->processMessage($iTipMessage, $currentObject);
523
+
524
+		$inbox->createFile($newFileName, $iTipMessage->message->serialize());
525
+
526
+		if (!$newObject) {
527
+			// We received an iTip message referring to a UID that we don't
528
+			// have in any calendars yet, and processMessage did not give us a
529
+			// calendarobject back.
530
+			//
531
+			// The implication is that processMessage did not understand the
532
+			// iTip message.
533
+			$iTipMessage->scheduleStatus = '5.0;iTip message was not processed by the server, likely because we didn\'t understand it.';
534
+			return;
535
+		}
536
+
537
+		// Note that we are bypassing ACL on purpose by calling this directly.
538
+		// We may need to look a bit deeper into this later. Supporting ACL
539
+		// here would be nice.
540
+		if ($isNewNode) {
541
+			$calendar = $this->server->tree->getNodeForPath($calendarPath);
542
+			$calendar->createFile($newFileName, $newObject->serialize());
543
+		} else {
544
+			// If the message was a reply, we may have to inform other
545
+			// attendees of this attendees status. Therefore we're shooting off
546
+			// another itipMessage.
547
+			if ($iTipMessage->method === 'REPLY') {
548
+				$this->processICalendarChange(
549
+					$oldICalendarData,
550
+					$newObject,
551
+					[$iTipMessage->recipient],
552
+					[$iTipMessage->sender]
553
+				);
554
+			}
555
+			$objectNode->put($newObject->serialize());
556
+		}
557
+		$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
558
+
559
+	}
560
+
561
+	/**
562
+	 * This method looks at an old iCalendar object, a new iCalendar object and
563
+	 * starts sending scheduling messages based on the changes.
564
+	 *
565
+	 * A list of addresses needs to be specified, so the system knows who made
566
+	 * the update, because the behavior may be different based on if it's an
567
+	 * attendee or an organizer.
568
+	 *
569
+	 * This method may update $newObject to add any status changes.
570
+	 *
571
+	 * @param VCalendar|string $oldObject
572
+	 * @param VCalendar $newObject
573
+	 * @param array $addresses
574
+	 * @param array $ignore Any addresses to not send messages to.
575
+	 * @param bool $modified A marker to indicate that the original object
576
+	 *   modified by this process.
577
+	 * @return void
578
+	 */
579
+	protected function processICalendarChange($oldObject = null, VCalendar $newObject, array $addresses, array $ignore = [], &$modified = false) {
580
+
581
+		$broker = new ITip\Broker();
582
+		$messages = $broker->parseEvent($newObject, $addresses, $oldObject);
583
+
584
+		if ($messages) $modified = true;
585
+
586
+		foreach ($messages as $message) {
587
+
588
+			if (in_array($message->recipient, $ignore)) {
589
+				continue;
590
+			}
591
+
592
+			$this->deliver($message);
593
+
594
+			if (isset($newObject->VEVENT->ORGANIZER) && ($newObject->VEVENT->ORGANIZER->getNormalizedValue() === $message->recipient)) {
595
+				if ($message->scheduleStatus) {
596
+					$newObject->VEVENT->ORGANIZER['SCHEDULE-STATUS'] = $message->getScheduleStatus();
597
+				}
598
+				unset($newObject->VEVENT->ORGANIZER['SCHEDULE-FORCE-SEND']);
599
+
600
+			} else {
601
+
602
+				if (isset($newObject->VEVENT->ATTENDEE)) foreach ($newObject->VEVENT->ATTENDEE as $attendee) {
603
+
604
+					if ($attendee->getNormalizedValue() === $message->recipient) {
605
+						if ($message->scheduleStatus) {
606
+							$attendee['SCHEDULE-STATUS'] = $message->getScheduleStatus();
607
+						}
608
+						unset($attendee['SCHEDULE-FORCE-SEND']);
609
+						break;
610
+					}
611
+
612
+				}
613
+
614
+			}
615
+
616
+		}
617
+
618
+	}
619
+
620
+	/**
621
+	 * Returns a list of addresses that are associated with a principal.
622
+	 *
623
+	 * @param string $principal
624
+	 * @return array
625
+	 */
626
+	protected function getAddressesForPrincipal($principal) {
627
+
628
+		$CUAS = '{' . self::NS_CALDAV . '}calendar-user-address-set';
629
+
630
+		$properties = $this->server->getProperties(
631
+			$principal,
632
+			[$CUAS]
633
+		);
634
+
635
+		// If we can't find this information, we'll stop processing
636
+		if (!isset($properties[$CUAS])) {
637
+			return;
638
+		}
639
+
640
+		$addresses = $properties[$CUAS]->getHrefs();
641
+		return $addresses;
642
+
643
+	}
644
+
645
+	/**
646
+	 * This method handles POST requests to the schedule-outbox.
647
+	 *
648
+	 * Currently, two types of requests are support:
649
+	 *   * FREEBUSY requests from RFC 6638
650
+	 *   * Simple iTIP messages from draft-desruisseaux-caldav-sched-04
651
+	 *
652
+	 * The latter is from an expired early draft of the CalDAV scheduling
653
+	 * extensions, but iCal depends on a feature from that spec, so we
654
+	 * implement it.
655
+	 *
656
+	 * @param IOutbox $outboxNode
657
+	 * @param RequestInterface $request
658
+	 * @param ResponseInterface $response
659
+	 * @return void
660
+	 */
661
+	public function outboxRequest(IOutbox $outboxNode, RequestInterface $request, ResponseInterface $response) {
662
+
663
+		$outboxPath = $request->getPath();
664
+
665
+		// Parsing the request body
666
+		try {
667
+			$vObject = VObject\Reader::read($request->getBody());
668
+		} catch (VObject\ParseException $e) {
669
+			throw new BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
670
+		}
671
+
672
+		// The incoming iCalendar object must have a METHOD property, and a
673
+		// component. The combination of both determines what type of request
674
+		// this is.
675
+		$componentType = null;
676
+		foreach ($vObject->getComponents() as $component) {
677
+			if ($component->name !== 'VTIMEZONE') {
678
+				$componentType = $component->name;
679
+				break;
680
+			}
681
+		}
682
+		if (is_null($componentType)) {
683
+			throw new BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component');
684
+		}
685 685
 
686
-        // Validating the METHOD
687
-        $method = strtoupper((string)$vObject->METHOD);
688
-        if (!$method) {
689
-            throw new BadRequest('A METHOD property must be specified in iTIP messages');
690
-        }
686
+		// Validating the METHOD
687
+		$method = strtoupper((string)$vObject->METHOD);
688
+		if (!$method) {
689
+			throw new BadRequest('A METHOD property must be specified in iTIP messages');
690
+		}
691 691
 
692
-        // So we support one type of request:
693
-        //
694
-        // REQUEST with a VFREEBUSY component
692
+		// So we support one type of request:
693
+		//
694
+		// REQUEST with a VFREEBUSY component
695 695
 
696
-        $acl = $this->server->getPlugin('acl');
696
+		$acl = $this->server->getPlugin('acl');
697 697
 
698
-        if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') {
698
+		if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') {
699 699
 
700
-            $acl && $acl->checkPrivileges($outboxPath, '{' . self::NS_CALDAV . '}schedule-query-freebusy');
701
-            $this->handleFreeBusyRequest($outboxNode, $vObject, $request, $response);
702
-
703
-            // Destroy circular references so PHP can GC the object.
704
-            $vObject->destroy();
705
-            unset($vObject);
700
+			$acl && $acl->checkPrivileges($outboxPath, '{' . self::NS_CALDAV . '}schedule-query-freebusy');
701
+			$this->handleFreeBusyRequest($outboxNode, $vObject, $request, $response);
702
+
703
+			// Destroy circular references so PHP can GC the object.
704
+			$vObject->destroy();
705
+			unset($vObject);
706 706
 
707
-        } else {
707
+		} else {
708 708
 
709
-            throw new NotImplemented('We only support VFREEBUSY (REQUEST) on this endpoint');
709
+			throw new NotImplemented('We only support VFREEBUSY (REQUEST) on this endpoint');
710 710
 
711
-        }
712
-
713
-    }
714
-
715
-    /**
716
-     * This method is responsible for parsing a free-busy query request and
717
-     * returning it's result.
718
-     *
719
-     * @param IOutbox $outbox
720
-     * @param VObject\Component $vObject
721
-     * @param RequestInterface $request
722
-     * @param ResponseInterface $response
723
-     * @return string
724
-     */
725
-    protected function handleFreeBusyRequest(IOutbox $outbox, VObject\Component $vObject, RequestInterface $request, ResponseInterface $response) {
726
-
727
-        $vFreeBusy = $vObject->VFREEBUSY;
728
-        $organizer = $vFreeBusy->organizer;
729
-
730
-        $organizer = (string)$organizer;
731
-
732
-        // Validating if the organizer matches the owner of the inbox.
733
-        $owner = $outbox->getOwner();
734
-
735
-        $caldavNS = '{' . self::NS_CALDAV . '}';
736
-
737
-        $uas = $caldavNS . 'calendar-user-address-set';
738
-        $props = $this->server->getProperties($owner, [$uas]);
739
-
740
-        if (empty($props[$uas]) || !in_array($organizer, $props[$uas]->getHrefs())) {
741
-            throw new Forbidden('The organizer in the request did not match any of the addresses for the owner of this inbox');
742
-        }
743
-
744
-        if (!isset($vFreeBusy->ATTENDEE)) {
745
-            throw new BadRequest('You must at least specify 1 attendee');
746
-        }
747
-
748
-        $attendees = [];
749
-        foreach ($vFreeBusy->ATTENDEE as $attendee) {
750
-            $attendees[] = (string)$attendee;
751
-        }
752
-
753
-
754
-        if (!isset($vFreeBusy->DTSTART) || !isset($vFreeBusy->DTEND)) {
755
-            throw new BadRequest('DTSTART and DTEND must both be specified');
756
-        }
757
-
758
-        $startRange = $vFreeBusy->DTSTART->getDateTime();
759
-        $endRange = $vFreeBusy->DTEND->getDateTime();
760
-
761
-        $results = [];
762
-        foreach ($attendees as $attendee) {
763
-            $results[] = $this->getFreeBusyForEmail($attendee, $startRange, $endRange, $vObject);
764
-        }
765
-
766
-        $dom = new \DOMDocument('1.0', 'utf-8');
767
-        $dom->formatOutput = true;
768
-        $scheduleResponse = $dom->createElement('cal:schedule-response');
769
-        foreach ($this->server->xml->namespaceMap as $namespace => $prefix) {
770
-
771
-            $scheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
772
-
773
-        }
774
-        $dom->appendChild($scheduleResponse);
775
-
776
-        foreach ($results as $result) {
777
-            $xresponse = $dom->createElement('cal:response');
778
-
779
-            $recipient = $dom->createElement('cal:recipient');
780
-            $recipientHref = $dom->createElement('d:href');
781
-
782
-            $recipientHref->appendChild($dom->createTextNode($result['href']));
783
-            $recipient->appendChild($recipientHref);
784
-            $xresponse->appendChild($recipient);
785
-
786
-            $reqStatus = $dom->createElement('cal:request-status');
787
-            $reqStatus->appendChild($dom->createTextNode($result['request-status']));
788
-            $xresponse->appendChild($reqStatus);
789
-
790
-            if (isset($result['calendar-data'])) {
791
-
792
-                $calendardata = $dom->createElement('cal:calendar-data');
793
-                $calendardata->appendChild($dom->createTextNode(str_replace("\r\n", "\n", $result['calendar-data']->serialize())));
794
-                $xresponse->appendChild($calendardata);
795
-
796
-            }
797
-            $scheduleResponse->appendChild($xresponse);
798
-        }
799
-
800
-        $response->setStatus(200);
801
-        $response->setHeader('Content-Type', 'application/xml');
802
-        $response->setBody($dom->saveXML());
803
-
804
-    }
805
-
806
-    /**
807
-     * Returns free-busy information for a specific address. The returned
808
-     * data is an array containing the following properties:
809
-     *
810
-     * calendar-data : A VFREEBUSY VObject
811
-     * request-status : an iTip status code.
812
-     * href: The principal's email address, as requested
813
-     *
814
-     * The following request status codes may be returned:
815
-     *   * 2.0;description
816
-     *   * 3.7;description
817
-     *
818
-     * @param string $email address
819
-     * @param DateTimeInterface $start
820
-     * @param DateTimeInterface $end
821
-     * @param VObject\Component $request
822
-     * @return array
823
-     */
824
-    protected function getFreeBusyForEmail($email, \DateTimeInterface $start, \DateTimeInterface $end, VObject\Component $request) {
825
-
826
-        $caldavNS = '{' . self::NS_CALDAV . '}';
827
-
828
-        $aclPlugin = $this->server->getPlugin('acl');
829
-        if (substr($email, 0, 7) === 'mailto:') $email = substr($email, 7);
830
-
831
-        $result = $aclPlugin->principalSearch(
832
-            ['{http://sabredav.org/ns}email-address' => $email],
833
-            [
834
-                '{DAV:}principal-URL',
835
-                $caldavNS . 'calendar-home-set',
836
-                $caldavNS . 'schedule-inbox-URL',
837
-                '{http://sabredav.org/ns}email-address',
838
-
839
-            ]
840
-        );
841
-
842
-        if (!count($result)) {
843
-            return [
844
-                'request-status' => '3.7;Could not find principal',
845
-                'href'           => 'mailto:' . $email,
846
-            ];
847
-        }
848
-
849
-        if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) {
850
-            return [
851
-                'request-status' => '3.7;No calendar-home-set property found',
852
-                'href'           => 'mailto:' . $email,
853
-            ];
854
-        }
855
-        if (!isset($result[0][200][$caldavNS . 'schedule-inbox-URL'])) {
856
-            return [
857
-                'request-status' => '3.7;No schedule-inbox-URL property found',
858
-                'href'           => 'mailto:' . $email,
859
-            ];
860
-        }
861
-        $homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
862
-        $inboxUrl = $result[0][200][$caldavNS . 'schedule-inbox-URL']->getHref();
863
-
864
-        // Grabbing the calendar list
865
-        $objects = [];
866
-        $calendarTimeZone = new DateTimeZone('UTC');
867
-
868
-        foreach ($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) {
869
-            if (!$node instanceof ICalendar) {
870
-                continue;
871
-            }
872
-
873
-            $sct = $caldavNS . 'schedule-calendar-transp';
874
-            $ctz = $caldavNS . 'calendar-timezone';
875
-            $props = $node->getProperties([$sct, $ctz]);
876
-
877
-            if (isset($props[$sct]) && $props[$sct]->getValue() == ScheduleCalendarTransp::TRANSPARENT) {
878
-                // If a calendar is marked as 'transparent', it means we must
879
-                // ignore it for free-busy purposes.
880
-                continue;
881
-            }
882
-
883
-            $aclPlugin->checkPrivileges($homeSet . $node->getName(), $caldavNS . 'read-free-busy');
884
-
885
-            if (isset($props[$ctz])) {
886
-                $vtimezoneObj = VObject\Reader::read($props[$ctz]);
887
-                $calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
888
-
889
-                // Destroy circular references so PHP can garbage collect the object.
890
-                $vtimezoneObj->destroy();
891
-
892
-            }
893
-
894
-            // Getting the list of object uris within the time-range
895
-            $urls = $node->calendarQuery([
896
-                'name'         => 'VCALENDAR',
897
-                'comp-filters' => [
898
-                    [
899
-                        'name'           => 'VEVENT',
900
-                        'comp-filters'   => [],
901
-                        'prop-filters'   => [],
902
-                        'is-not-defined' => false,
903
-                        'time-range'     => [
904
-                            'start' => $start,
905
-                            'end'   => $end,
906
-                        ],
907
-                    ],
908
-                ],
909
-                'prop-filters'   => [],
910
-                'is-not-defined' => false,
911
-                'time-range'     => null,
912
-            ]);
913
-
914
-            $calObjects = array_map(function($url) use ($node) {
915
-                $obj = $node->getChild($url)->get();
916
-                return $obj;
917
-            }, $urls);
918
-
919
-            $objects = array_merge($objects, $calObjects);
920
-
921
-        }
922
-
923
-        $inboxProps = $this->server->getProperties(
924
-            $inboxUrl,
925
-            $caldavNS . 'calendar-availability'
926
-        );
927
-
928
-        $vcalendar = new VObject\Component\VCalendar();
929
-        $vcalendar->METHOD = 'REPLY';
930
-
931
-        $generator = new VObject\FreeBusyGenerator();
932
-        $generator->setObjects($objects);
933
-        $generator->setTimeRange($start, $end);
934
-        $generator->setBaseObject($vcalendar);
935
-        $generator->setTimeZone($calendarTimeZone);
936
-
937
-        if ($inboxProps) {
938
-            $generator->setVAvailability(
939
-                VObject\Reader::read(
940
-                    $inboxProps[$caldavNS . 'calendar-availability']
941
-                )
942
-            );
943
-        }
944
-
945
-        $result = $generator->getResult();
946
-
947
-        $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
948
-        $vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID;
949
-        $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
950
-
951
-        return [
952
-            'calendar-data'  => $result,
953
-            'request-status' => '2.0;Success',
954
-            'href'           => 'mailto:' . $email,
955
-        ];
956
-    }
957
-
958
-    /**
959
-     * This method checks the 'Schedule-Reply' header
960
-     * and returns false if it's 'F', otherwise true.
961
-     *
962
-     * @param RequestInterface $request
963
-     * @return bool
964
-     */
965
-    private function scheduleReply(RequestInterface $request) {
966
-
967
-        $scheduleReply = $request->getHeader('Schedule-Reply');
968
-        return $scheduleReply !== 'F';
969
-
970
-    }
971
-
972
-    /**
973
-     * Returns a bunch of meta-data about the plugin.
974
-     *
975
-     * Providing this information is optional, and is mainly displayed by the
976
-     * Browser plugin.
977
-     *
978
-     * The description key in the returned array may contain html and will not
979
-     * be sanitized.
980
-     *
981
-     * @return array
982
-     */
983
-    public function getPluginInfo() {
984
-
985
-        return [
986
-            'name'        => $this->getPluginName(),
987
-            'description' => 'Adds calendar-auto-schedule, as defined in rf6868',
988
-            'link'        => 'http://sabre.io/dav/scheduling/',
989
-        ];
990
-
991
-    }
711
+		}
712
+
713
+	}
714
+
715
+	/**
716
+	 * This method is responsible for parsing a free-busy query request and
717
+	 * returning it's result.
718
+	 *
719
+	 * @param IOutbox $outbox
720
+	 * @param VObject\Component $vObject
721
+	 * @param RequestInterface $request
722
+	 * @param ResponseInterface $response
723
+	 * @return string
724
+	 */
725
+	protected function handleFreeBusyRequest(IOutbox $outbox, VObject\Component $vObject, RequestInterface $request, ResponseInterface $response) {
726
+
727
+		$vFreeBusy = $vObject->VFREEBUSY;
728
+		$organizer = $vFreeBusy->organizer;
729
+
730
+		$organizer = (string)$organizer;
731
+
732
+		// Validating if the organizer matches the owner of the inbox.
733
+		$owner = $outbox->getOwner();
734
+
735
+		$caldavNS = '{' . self::NS_CALDAV . '}';
736
+
737
+		$uas = $caldavNS . 'calendar-user-address-set';
738
+		$props = $this->server->getProperties($owner, [$uas]);
739
+
740
+		if (empty($props[$uas]) || !in_array($organizer, $props[$uas]->getHrefs())) {
741
+			throw new Forbidden('The organizer in the request did not match any of the addresses for the owner of this inbox');
742
+		}
743
+
744
+		if (!isset($vFreeBusy->ATTENDEE)) {
745
+			throw new BadRequest('You must at least specify 1 attendee');
746
+		}
747
+
748
+		$attendees = [];
749
+		foreach ($vFreeBusy->ATTENDEE as $attendee) {
750
+			$attendees[] = (string)$attendee;
751
+		}
752
+
753
+
754
+		if (!isset($vFreeBusy->DTSTART) || !isset($vFreeBusy->DTEND)) {
755
+			throw new BadRequest('DTSTART and DTEND must both be specified');
756
+		}
757
+
758
+		$startRange = $vFreeBusy->DTSTART->getDateTime();
759
+		$endRange = $vFreeBusy->DTEND->getDateTime();
760
+
761
+		$results = [];
762
+		foreach ($attendees as $attendee) {
763
+			$results[] = $this->getFreeBusyForEmail($attendee, $startRange, $endRange, $vObject);
764
+		}
765
+
766
+		$dom = new \DOMDocument('1.0', 'utf-8');
767
+		$dom->formatOutput = true;
768
+		$scheduleResponse = $dom->createElement('cal:schedule-response');
769
+		foreach ($this->server->xml->namespaceMap as $namespace => $prefix) {
770
+
771
+			$scheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
772
+
773
+		}
774
+		$dom->appendChild($scheduleResponse);
775
+
776
+		foreach ($results as $result) {
777
+			$xresponse = $dom->createElement('cal:response');
778
+
779
+			$recipient = $dom->createElement('cal:recipient');
780
+			$recipientHref = $dom->createElement('d:href');
781
+
782
+			$recipientHref->appendChild($dom->createTextNode($result['href']));
783
+			$recipient->appendChild($recipientHref);
784
+			$xresponse->appendChild($recipient);
785
+
786
+			$reqStatus = $dom->createElement('cal:request-status');
787
+			$reqStatus->appendChild($dom->createTextNode($result['request-status']));
788
+			$xresponse->appendChild($reqStatus);
789
+
790
+			if (isset($result['calendar-data'])) {
791
+
792
+				$calendardata = $dom->createElement('cal:calendar-data');
793
+				$calendardata->appendChild($dom->createTextNode(str_replace("\r\n", "\n", $result['calendar-data']->serialize())));
794
+				$xresponse->appendChild($calendardata);
795
+
796
+			}
797
+			$scheduleResponse->appendChild($xresponse);
798
+		}
799
+
800
+		$response->setStatus(200);
801
+		$response->setHeader('Content-Type', 'application/xml');
802
+		$response->setBody($dom->saveXML());
803
+
804
+	}
805
+
806
+	/**
807
+	 * Returns free-busy information for a specific address. The returned
808
+	 * data is an array containing the following properties:
809
+	 *
810
+	 * calendar-data : A VFREEBUSY VObject
811
+	 * request-status : an iTip status code.
812
+	 * href: The principal's email address, as requested
813
+	 *
814
+	 * The following request status codes may be returned:
815
+	 *   * 2.0;description
816
+	 *   * 3.7;description
817
+	 *
818
+	 * @param string $email address
819
+	 * @param DateTimeInterface $start
820
+	 * @param DateTimeInterface $end
821
+	 * @param VObject\Component $request
822
+	 * @return array
823
+	 */
824
+	protected function getFreeBusyForEmail($email, \DateTimeInterface $start, \DateTimeInterface $end, VObject\Component $request) {
825
+
826
+		$caldavNS = '{' . self::NS_CALDAV . '}';
827
+
828
+		$aclPlugin = $this->server->getPlugin('acl');
829
+		if (substr($email, 0, 7) === 'mailto:') $email = substr($email, 7);
830
+
831
+		$result = $aclPlugin->principalSearch(
832
+			['{http://sabredav.org/ns}email-address' => $email],
833
+			[
834
+				'{DAV:}principal-URL',
835
+				$caldavNS . 'calendar-home-set',
836
+				$caldavNS . 'schedule-inbox-URL',
837
+				'{http://sabredav.org/ns}email-address',
838
+
839
+			]
840
+		);
841
+
842
+		if (!count($result)) {
843
+			return [
844
+				'request-status' => '3.7;Could not find principal',
845
+				'href'           => 'mailto:' . $email,
846
+			];
847
+		}
848
+
849
+		if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) {
850
+			return [
851
+				'request-status' => '3.7;No calendar-home-set property found',
852
+				'href'           => 'mailto:' . $email,
853
+			];
854
+		}
855
+		if (!isset($result[0][200][$caldavNS . 'schedule-inbox-URL'])) {
856
+			return [
857
+				'request-status' => '3.7;No schedule-inbox-URL property found',
858
+				'href'           => 'mailto:' . $email,
859
+			];
860
+		}
861
+		$homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
862
+		$inboxUrl = $result[0][200][$caldavNS . 'schedule-inbox-URL']->getHref();
863
+
864
+		// Grabbing the calendar list
865
+		$objects = [];
866
+		$calendarTimeZone = new DateTimeZone('UTC');
867
+
868
+		foreach ($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) {
869
+			if (!$node instanceof ICalendar) {
870
+				continue;
871
+			}
872
+
873
+			$sct = $caldavNS . 'schedule-calendar-transp';
874
+			$ctz = $caldavNS . 'calendar-timezone';
875
+			$props = $node->getProperties([$sct, $ctz]);
876
+
877
+			if (isset($props[$sct]) && $props[$sct]->getValue() == ScheduleCalendarTransp::TRANSPARENT) {
878
+				// If a calendar is marked as 'transparent', it means we must
879
+				// ignore it for free-busy purposes.
880
+				continue;
881
+			}
882
+
883
+			$aclPlugin->checkPrivileges($homeSet . $node->getName(), $caldavNS . 'read-free-busy');
884
+
885
+			if (isset($props[$ctz])) {
886
+				$vtimezoneObj = VObject\Reader::read($props[$ctz]);
887
+				$calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
888
+
889
+				// Destroy circular references so PHP can garbage collect the object.
890
+				$vtimezoneObj->destroy();
891
+
892
+			}
893
+
894
+			// Getting the list of object uris within the time-range
895
+			$urls = $node->calendarQuery([
896
+				'name'         => 'VCALENDAR',
897
+				'comp-filters' => [
898
+					[
899
+						'name'           => 'VEVENT',
900
+						'comp-filters'   => [],
901
+						'prop-filters'   => [],
902
+						'is-not-defined' => false,
903
+						'time-range'     => [
904
+							'start' => $start,
905
+							'end'   => $end,
906
+						],
907
+					],
908
+				],
909
+				'prop-filters'   => [],
910
+				'is-not-defined' => false,
911
+				'time-range'     => null,
912
+			]);
913
+
914
+			$calObjects = array_map(function($url) use ($node) {
915
+				$obj = $node->getChild($url)->get();
916
+				return $obj;
917
+			}, $urls);
918
+
919
+			$objects = array_merge($objects, $calObjects);
920
+
921
+		}
922
+
923
+		$inboxProps = $this->server->getProperties(
924
+			$inboxUrl,
925
+			$caldavNS . 'calendar-availability'
926
+		);
927
+
928
+		$vcalendar = new VObject\Component\VCalendar();
929
+		$vcalendar->METHOD = 'REPLY';
930
+
931
+		$generator = new VObject\FreeBusyGenerator();
932
+		$generator->setObjects($objects);
933
+		$generator->setTimeRange($start, $end);
934
+		$generator->setBaseObject($vcalendar);
935
+		$generator->setTimeZone($calendarTimeZone);
936
+
937
+		if ($inboxProps) {
938
+			$generator->setVAvailability(
939
+				VObject\Reader::read(
940
+					$inboxProps[$caldavNS . 'calendar-availability']
941
+				)
942
+			);
943
+		}
944
+
945
+		$result = $generator->getResult();
946
+
947
+		$vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
948
+		$vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID;
949
+		$vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
950
+
951
+		return [
952
+			'calendar-data'  => $result,
953
+			'request-status' => '2.0;Success',
954
+			'href'           => 'mailto:' . $email,
955
+		];
956
+	}
957
+
958
+	/**
959
+	 * This method checks the 'Schedule-Reply' header
960
+	 * and returns false if it's 'F', otherwise true.
961
+	 *
962
+	 * @param RequestInterface $request
963
+	 * @return bool
964
+	 */
965
+	private function scheduleReply(RequestInterface $request) {
966
+
967
+		$scheduleReply = $request->getHeader('Schedule-Reply');
968
+		return $scheduleReply !== 'F';
969
+
970
+	}
971
+
972
+	/**
973
+	 * Returns a bunch of meta-data about the plugin.
974
+	 *
975
+	 * Providing this information is optional, and is mainly displayed by the
976
+	 * Browser plugin.
977
+	 *
978
+	 * The description key in the returned array may contain html and will not
979
+	 * be sanitized.
980
+	 *
981
+	 * @return array
982
+	 */
983
+	public function getPluginInfo() {
984
+
985
+		return [
986
+			'name'        => $this->getPluginName(),
987
+			'description' => 'Adds calendar-auto-schedule, as defined in rf6868',
988
+			'link'        => 'http://sabre.io/dav/scheduling/',
989
+		];
990
+
991
+	}
992 992
 }
Please login to merge, or discard this patch.
Doc Comments   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
     /**
70 70
      * Returns a list of features for the DAV: HTTP header.
71 71
      *
72
-     * @return array
72
+     * @return string[]
73 73
      */
74 74
     public function getFeatures() {
75 75
 
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
      *
161 161
      * @param RequestInterface $request
162 162
      * @param ResponseInterface $response
163
-     * @return bool
163
+     * @return null|false
164 164
      */
165 165
     public function httpPost(RequestInterface $request, ResponseInterface $response) {
166 166
 
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
     /**
365 365
      * This method is responsible for delivering the ITip message.
366 366
      *
367
-     * @param ITip\Message $itipMessage
367
+     * @param ITip\Message $iTipMessage
368 368
      * @return void
369 369
      */
370 370
     public function deliver(ITip\Message $iTipMessage) {
@@ -816,8 +816,8 @@  discard block
 block discarded – undo
816 816
      *   * 3.7;description
817 817
      *
818 818
      * @param string $email address
819
-     * @param DateTimeInterface $start
820
-     * @param DateTimeInterface $end
819
+     * @param \DateTimeInterface $start
820
+     * @param \DateTimeInterface $end
821 821
      * @param VObject\Component $request
822 822
      * @return array
823 823
      */
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -100,12 +100,12 @@  discard block
 block discarded – undo
100 100
     public function initialize(Server $server) {
101 101
 
102 102
         $this->server = $server;
103
-        $server->on('method:POST',          [$this, 'httpPost']);
104
-        $server->on('propFind',             [$this, 'propFind']);
105
-        $server->on('propPatch',            [$this, 'propPatch']);
103
+        $server->on('method:POST', [$this, 'httpPost']);
104
+        $server->on('propFind', [$this, 'propFind']);
105
+        $server->on('propPatch', [$this, 'propPatch']);
106 106
         $server->on('calendarObjectChange', [$this, 'calendarObjectChange']);
107
-        $server->on('beforeUnbind',         [$this, 'beforeUnbind']);
108
-        $server->on('schedule',             [$this, 'scheduleLocalDelivery']);
107
+        $server->on('beforeUnbind', [$this, 'beforeUnbind']);
108
+        $server->on('schedule', [$this, 'scheduleLocalDelivery']);
109 109
 
110 110
         $ns = '{' . self::NS_CALDAV . '}';
111 111
 
@@ -684,7 +684,7 @@  discard block
 block discarded – undo
684 684
         }
685 685
 
686 686
         // Validating the METHOD
687
-        $method = strtoupper((string)$vObject->METHOD);
687
+        $method = strtoupper((string) $vObject->METHOD);
688 688
         if (!$method) {
689 689
             throw new BadRequest('A METHOD property must be specified in iTIP messages');
690 690
         }
@@ -727,7 +727,7 @@  discard block
 block discarded – undo
727 727
         $vFreeBusy = $vObject->VFREEBUSY;
728 728
         $organizer = $vFreeBusy->organizer;
729 729
 
730
-        $organizer = (string)$organizer;
730
+        $organizer = (string) $organizer;
731 731
 
732 732
         // Validating if the organizer matches the owner of the inbox.
733 733
         $owner = $outbox->getOwner();
@@ -747,7 +747,7 @@  discard block
 block discarded – undo
747 747
 
748 748
         $attendees = [];
749 749
         foreach ($vFreeBusy->ATTENDEE as $attendee) {
750
-            $attendees[] = (string)$attendee;
750
+            $attendees[] = (string) $attendee;
751 751
         }
752 752
 
753 753
 
@@ -945,7 +945,7 @@  discard block
 block discarded – undo
945 945
         $result = $generator->getResult();
946 946
 
947 947
         $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
948
-        $vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID;
948
+        $vcalendar->VFREEBUSY->UID = (string) $request->VFREEBUSY->UID;
949 949
         $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
950 950
 
951 951
         return [
Please login to merge, or discard this patch.
Braces   +15 added lines, -6 removed lines patch added patch discarded remove patch
@@ -178,8 +178,9 @@  discard block
 block discarded – undo
178 178
         } catch (NotFound $e) {
179 179
             return;
180 180
         }
181
-        if (!$node instanceof IOutbox)
182
-            return;
181
+        if (!$node instanceof IOutbox) {
182
+                    return;
183
+        }
183 184
 
184 185
         $this->server->transactionType = 'post-caldav-outbox';
185 186
         $this->outboxRequest($node, $request, $response);
@@ -393,7 +394,9 @@  discard block
 block discarded – undo
393 394
      */
394 395
     public function beforeUnbind($path) {
395 396
 
396
-        if ($this->server->httpRequest->getMethod() === 'MOVE') return;
397
+        if ($this->server->httpRequest->getMethod() === 'MOVE') {
398
+        	return;
399
+        }
397 400
 
398 401
         $node = $this->server->tree->getNodeForPath($path);
399 402
 
@@ -581,7 +584,9 @@  discard block
 block discarded – undo
581 584
         $broker = new ITip\Broker();
582 585
         $messages = $broker->parseEvent($newObject, $addresses, $oldObject);
583 586
 
584
-        if ($messages) $modified = true;
587
+        if ($messages) {
588
+        	$modified = true;
589
+        }
585 590
 
586 591
         foreach ($messages as $message) {
587 592
 
@@ -599,11 +604,13 @@  discard block
 block discarded – undo
599 604
 
600 605
             } else {
601 606
 
602
-                if (isset($newObject->VEVENT->ATTENDEE)) foreach ($newObject->VEVENT->ATTENDEE as $attendee) {
607
+                if (isset($newObject->VEVENT->ATTENDEE)) {
608
+                	foreach ($newObject->VEVENT->ATTENDEE as $attendee) {
603 609
 
604 610
                     if ($attendee->getNormalizedValue() === $message->recipient) {
605 611
                         if ($message->scheduleStatus) {
606 612
                             $attendee['SCHEDULE-STATUS'] = $message->getScheduleStatus();
613
+                }
607 614
                         }
608 615
                         unset($attendee['SCHEDULE-FORCE-SEND']);
609 616
                         break;
@@ -826,7 +833,9 @@  discard block
 block discarded – undo
826 833
         $caldavNS = '{' . self::NS_CALDAV . '}';
827 834
 
828 835
         $aclPlugin = $this->server->getPlugin('acl');
829
-        if (substr($email, 0, 7) === 'mailto:') $email = substr($email, 7);
836
+        if (substr($email, 0, 7) === 'mailto:') {
837
+        	$email = substr($email, 7);
838
+        }
830 839
 
831 840
         $result = $aclPlugin->principalSearch(
832 841
             ['{http://sabredav.org/ns}email-address' => $email],
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Subscriptions/Plugin.php 3 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -4,8 +4,8 @@
 block discarded – undo
4 4
 
5 5
 use Sabre\DAV\INode;
6 6
 use Sabre\DAV\PropFind;
7
-use Sabre\DAV\ServerPlugin;
8 7
 use Sabre\DAV\Server;
8
+use Sabre\DAV\ServerPlugin;
9 9
 
10 10
 /**
11 11
  * This plugin adds calendar-subscription support to your CalDAV server.
Please login to merge, or discard this patch.
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -19,102 +19,102 @@
 block discarded – undo
19 19
  */
20 20
 class Plugin extends ServerPlugin {
21 21
 
22
-    /**
23
-     * This initializes the plugin.
24
-     *
25
-     * This function is called by Sabre\DAV\Server, after
26
-     * addPlugin is called.
27
-     *
28
-     * This method should set up the required event subscriptions.
29
-     *
30
-     * @param Server $server
31
-     * @return void
32
-     */
33
-    public function initialize(Server $server) {
34
-
35
-        $server->resourceTypeMapping['Sabre\\CalDAV\\Subscriptions\\ISubscription'] =
36
-            '{http://calendarserver.org/ns/}subscribed';
37
-
38
-        $server->xml->elementMap['{http://calendarserver.org/ns/}source'] =
39
-            'Sabre\\DAV\\Xml\\Property\\Href';
40
-
41
-        $server->on('propFind', [$this, 'propFind'], 150);
42
-
43
-    }
44
-
45
-    /**
46
-     * This method should return a list of server-features.
47
-     *
48
-     * This is for example 'versioning' and is added to the DAV: header
49
-     * in an OPTIONS response.
50
-     *
51
-     * @return array
52
-     */
53
-    public function getFeatures() {
54
-
55
-        return ['calendarserver-subscribed'];
56
-
57
-    }
58
-
59
-    /**
60
-     * Triggered after properties have been fetched.
61
-     *
62
-     * @param PropFind $propFind
63
-     * @param INode $node
64
-     * @return void
65
-     */
66
-    public function propFind(PropFind $propFind, INode $node) {
67
-
68
-        // There's a bunch of properties that must appear as a self-closing
69
-        // xml-element. This event handler ensures that this will be the case.
70
-        $props = [
71
-            '{http://calendarserver.org/ns/}subscribed-strip-alarms',
72
-            '{http://calendarserver.org/ns/}subscribed-strip-attachments',
73
-            '{http://calendarserver.org/ns/}subscribed-strip-todos',
74
-        ];
75
-
76
-        foreach ($props as $prop) {
77
-
78
-            if ($propFind->getStatus($prop) === 200) {
79
-                $propFind->set($prop, '', 200);
80
-            }
81
-
82
-        }
83
-
84
-    }
85
-
86
-    /**
87
-     * Returns a plugin name.
88
-     *
89
-     * Using this name other plugins will be able to access other plugins
90
-     * using \Sabre\DAV\Server::getPlugin
91
-     *
92
-     * @return string
93
-     */
94
-    public function getPluginName() {
95
-
96
-        return 'subscriptions';
97
-
98
-    }
99
-
100
-    /**
101
-     * Returns a bunch of meta-data about the plugin.
102
-     *
103
-     * Providing this information is optional, and is mainly displayed by the
104
-     * Browser plugin.
105
-     *
106
-     * The description key in the returned array may contain html and will not
107
-     * be sanitized.
108
-     *
109
-     * @return array
110
-     */
111
-    public function getPluginInfo() {
112
-
113
-        return [
114
-            'name'        => $this->getPluginName(),
115
-            'description' => 'This plugin allows users to store iCalendar subscriptions in their calendar-home.',
116
-            'link'        => null,
117
-        ];
118
-
119
-    }
22
+	/**
23
+	 * This initializes the plugin.
24
+	 *
25
+	 * This function is called by Sabre\DAV\Server, after
26
+	 * addPlugin is called.
27
+	 *
28
+	 * This method should set up the required event subscriptions.
29
+	 *
30
+	 * @param Server $server
31
+	 * @return void
32
+	 */
33
+	public function initialize(Server $server) {
34
+
35
+		$server->resourceTypeMapping['Sabre\\CalDAV\\Subscriptions\\ISubscription'] =
36
+			'{http://calendarserver.org/ns/}subscribed';
37
+
38
+		$server->xml->elementMap['{http://calendarserver.org/ns/}source'] =
39
+			'Sabre\\DAV\\Xml\\Property\\Href';
40
+
41
+		$server->on('propFind', [$this, 'propFind'], 150);
42
+
43
+	}
44
+
45
+	/**
46
+	 * This method should return a list of server-features.
47
+	 *
48
+	 * This is for example 'versioning' and is added to the DAV: header
49
+	 * in an OPTIONS response.
50
+	 *
51
+	 * @return array
52
+	 */
53
+	public function getFeatures() {
54
+
55
+		return ['calendarserver-subscribed'];
56
+
57
+	}
58
+
59
+	/**
60
+	 * Triggered after properties have been fetched.
61
+	 *
62
+	 * @param PropFind $propFind
63
+	 * @param INode $node
64
+	 * @return void
65
+	 */
66
+	public function propFind(PropFind $propFind, INode $node) {
67
+
68
+		// There's a bunch of properties that must appear as a self-closing
69
+		// xml-element. This event handler ensures that this will be the case.
70
+		$props = [
71
+			'{http://calendarserver.org/ns/}subscribed-strip-alarms',
72
+			'{http://calendarserver.org/ns/}subscribed-strip-attachments',
73
+			'{http://calendarserver.org/ns/}subscribed-strip-todos',
74
+		];
75
+
76
+		foreach ($props as $prop) {
77
+
78
+			if ($propFind->getStatus($prop) === 200) {
79
+				$propFind->set($prop, '', 200);
80
+			}
81
+
82
+		}
83
+
84
+	}
85
+
86
+	/**
87
+	 * Returns a plugin name.
88
+	 *
89
+	 * Using this name other plugins will be able to access other plugins
90
+	 * using \Sabre\DAV\Server::getPlugin
91
+	 *
92
+	 * @return string
93
+	 */
94
+	public function getPluginName() {
95
+
96
+		return 'subscriptions';
97
+
98
+	}
99
+
100
+	/**
101
+	 * Returns a bunch of meta-data about the plugin.
102
+	 *
103
+	 * Providing this information is optional, and is mainly displayed by the
104
+	 * Browser plugin.
105
+	 *
106
+	 * The description key in the returned array may contain html and will not
107
+	 * be sanitized.
108
+	 *
109
+	 * @return array
110
+	 */
111
+	public function getPluginInfo() {
112
+
113
+		return [
114
+			'name'        => $this->getPluginName(),
115
+			'description' => 'This plugin allows users to store iCalendar subscriptions in their calendar-home.',
116
+			'link'        => null,
117
+		];
118
+
119
+	}
120 120
 }
Please login to merge, or discard this patch.
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -48,7 +48,7 @@
 block discarded – undo
48 48
      * This is for example 'versioning' and is added to the DAV: header
49 49
      * in an OPTIONS response.
50 50
      *
51
-     * @return array
51
+     * @return string[]
52 52
      */
53 53
     public function getFeatures() {
54 54
 
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Subscriptions/Subscription.php 3 patches
Unused Use Statements   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -2,12 +2,12 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\CalDAV\Subscriptions;
4 4
 
5
+use Sabre\CalDAV\Backend\SubscriptionSupport;
6
+use Sabre\DAVACL\IACL;
5 7
 use Sabre\DAV\Collection;
6
-use Sabre\DAV\Xml\Property\Href;
7
-use Sabre\DAV\PropPatch;
8 8
 use Sabre\DAV\Exception\MethodNotAllowed;
9
-use Sabre\DAVACL\IACL;
10
-use Sabre\CalDAV\Backend\SubscriptionSupport;
9
+use Sabre\DAV\PropPatch;
10
+use Sabre\DAV\Xml\Property\Href;
11 11
 
12 12
 /**
13 13
  * Subscription Node
Please login to merge, or discard this patch.
Indentation   +250 added lines, -250 removed lines patch added patch discarded remove patch
@@ -20,255 +20,255 @@
 block discarded – undo
20 20
  */
21 21
 class Subscription extends Collection implements ISubscription, IACL {
22 22
 
23
-    /**
24
-     * caldavBackend
25
-     *
26
-     * @var SupportsSubscriptions
27
-     */
28
-    protected $caldavBackend;
29
-
30
-    /**
31
-     * subscriptionInfo
32
-     *
33
-     * @var array
34
-     */
35
-    protected $subscriptionInfo;
36
-
37
-    /**
38
-     * Constructor
39
-     *
40
-     * @param SubscriptionSupport $caldavBackend
41
-     * @param array $calendarInfo
42
-     */
43
-    public function __construct(SubscriptionSupport $caldavBackend, array $subscriptionInfo) {
44
-
45
-        $this->caldavBackend = $caldavBackend;
46
-        $this->subscriptionInfo = $subscriptionInfo;
47
-
48
-        $required = [
49
-            'id',
50
-            'uri',
51
-            'principaluri',
52
-            'source',
53
-            ];
54
-
55
-        foreach ($required as $r) {
56
-            if (!isset($subscriptionInfo[$r])) {
57
-                throw new \InvalidArgumentException('The ' . $r . ' field is required when creating a subscription node');
58
-            }
59
-        }
60
-
61
-    }
62
-
63
-    /**
64
-     * Returns the name of the node.
65
-     *
66
-     * This is used to generate the url.
67
-     *
68
-     * @return string
69
-     */
70
-    public function getName() {
71
-
72
-        return $this->subscriptionInfo['uri'];
73
-
74
-    }
75
-
76
-    /**
77
-     * Returns the last modification time
78
-     *
79
-     * @return int
80
-     */
81
-    public function getLastModified() {
82
-
83
-        if (isset($this->subscriptionInfo['lastmodified'])) {
84
-            return $this->subscriptionInfo['lastmodified'];
85
-        }
86
-
87
-    }
88
-
89
-    /**
90
-     * Deletes the current node
91
-     *
92
-     * @return void
93
-     */
94
-    public function delete() {
95
-
96
-        $this->caldavBackend->deleteSubscription(
97
-            $this->subscriptionInfo['id']
98
-        );
99
-
100
-    }
101
-
102
-    /**
103
-     * Returns an array with all the child nodes
104
-     *
105
-     * @return DAV\INode[]
106
-     */
107
-    public function getChildren() {
108
-
109
-        return [];
110
-
111
-    }
112
-
113
-    /**
114
-     * Updates properties on this node.
115
-     *
116
-     * This method received a PropPatch object, which contains all the
117
-     * information about the update.
118
-     *
119
-     * To update specific properties, call the 'handle' method on this object.
120
-     * Read the PropPatch documentation for more information.
121
-     *
122
-     * @param PropPatch $propPatch
123
-     * @return void
124
-     */
125
-    public function propPatch(PropPatch $propPatch) {
126
-
127
-        return $this->caldavBackend->updateSubscription(
128
-            $this->subscriptionInfo['id'],
129
-            $propPatch
130
-        );
131
-
132
-    }
133
-
134
-    /**
135
-     * Returns a list of properties for this nodes.
136
-     *
137
-     * The properties list is a list of propertynames the client requested,
138
-     * encoded in clark-notation {xmlnamespace}tagname.
139
-     *
140
-     * If the array is empty, it means 'all properties' were requested.
141
-     *
142
-     * Note that it's fine to liberally give properties back, instead of
143
-     * conforming to the list of requested properties.
144
-     * The Server class will filter out the extra.
145
-     *
146
-     * @param array $properties
147
-     * @return void
148
-     */
149
-    public function getProperties($properties) {
150
-
151
-        $r = [];
152
-
153
-        foreach ($properties as $prop) {
154
-
155
-            switch ($prop) {
156
-                case '{http://calendarserver.org/ns/}source' :
157
-                    $r[$prop] = new Href($this->subscriptionInfo['source'], false);
158
-                    break;
159
-                default :
160
-                    if (array_key_exists($prop, $this->subscriptionInfo)) {
161
-                        $r[$prop] = $this->subscriptionInfo[$prop];
162
-                    }
163
-                    break;
164
-            }
165
-
166
-        }
167
-
168
-        return $r;
169
-
170
-    }
171
-
172
-    /**
173
-     * Returns the owner principal.
174
-     *
175
-     * This must be a url to a principal, or null if there's no owner
176
-     *
177
-     * @return string|null
178
-     */
179
-    public function getOwner() {
180
-
181
-        return $this->subscriptionInfo['principaluri'];
182
-
183
-    }
184
-
185
-    /**
186
-     * Returns a group principal.
187
-     *
188
-     * This must be a url to a principal, or null if there's no owner
189
-     *
190
-     * @return string|null
191
-     */
192
-    public function getGroup() {
193
-
194
-        return null;
195
-
196
-    }
197
-
198
-    /**
199
-     * Returns a list of ACE's for this node.
200
-     *
201
-     * Each ACE has the following properties:
202
-     *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
203
-     *     currently the only supported privileges
204
-     *   * 'principal', a url to the principal who owns the node
205
-     *   * 'protected' (optional), indicating that this ACE is not allowed to
206
-     *      be updated.
207
-     *
208
-     * @return array
209
-     */
210
-    public function getACL() {
211
-
212
-        return [
213
-            [
214
-                'privilege' => '{DAV:}read',
215
-                'principal' => $this->getOwner(),
216
-                'protected' => true,
217
-            ],
218
-            [
219
-                'privilege' => '{DAV:}write',
220
-                'principal' => $this->getOwner(),
221
-                'protected' => true,
222
-            ],
223
-            [
224
-                'privilege' => '{DAV:}read',
225
-                'principal' => $this->getOwner() . '/calendar-proxy-write',
226
-                'protected' => true,
227
-            ],
228
-            [
229
-                'privilege' => '{DAV:}write',
230
-                'principal' => $this->getOwner() . '/calendar-proxy-write',
231
-                'protected' => true,
232
-            ],
233
-            [
234
-                'privilege' => '{DAV:}read',
235
-                'principal' => $this->getOwner() . '/calendar-proxy-read',
236
-                'protected' => true,
237
-            ]
238
-        ];
239
-
240
-    }
241
-
242
-    /**
243
-     * Updates the ACL.
244
-     *
245
-     * This method will receive a list of new ACE's.
246
-     *
247
-     * @param array $acl
248
-     * @return void
249
-     */
250
-    public function setACL(array $acl) {
251
-
252
-        throw new MethodNotAllowed('Changing ACL is not yet supported');
253
-
254
-    }
255
-
256
-    /**
257
-     * Returns the list of supported privileges for this node.
258
-     *
259
-     * The returned data structure is a list of nested privileges.
260
-     * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
261
-     * standard structure.
262
-     *
263
-     * If null is returned from this method, the default privilege set is used,
264
-     * which is fine for most common usecases.
265
-     *
266
-     * @return array|null
267
-     */
268
-    public function getSupportedPrivilegeSet() {
269
-
270
-        return null;
271
-
272
-    }
23
+	/**
24
+	 * caldavBackend
25
+	 *
26
+	 * @var SupportsSubscriptions
27
+	 */
28
+	protected $caldavBackend;
29
+
30
+	/**
31
+	 * subscriptionInfo
32
+	 *
33
+	 * @var array
34
+	 */
35
+	protected $subscriptionInfo;
36
+
37
+	/**
38
+	 * Constructor
39
+	 *
40
+	 * @param SubscriptionSupport $caldavBackend
41
+	 * @param array $calendarInfo
42
+	 */
43
+	public function __construct(SubscriptionSupport $caldavBackend, array $subscriptionInfo) {
44
+
45
+		$this->caldavBackend = $caldavBackend;
46
+		$this->subscriptionInfo = $subscriptionInfo;
47
+
48
+		$required = [
49
+			'id',
50
+			'uri',
51
+			'principaluri',
52
+			'source',
53
+			];
54
+
55
+		foreach ($required as $r) {
56
+			if (!isset($subscriptionInfo[$r])) {
57
+				throw new \InvalidArgumentException('The ' . $r . ' field is required when creating a subscription node');
58
+			}
59
+		}
60
+
61
+	}
62
+
63
+	/**
64
+	 * Returns the name of the node.
65
+	 *
66
+	 * This is used to generate the url.
67
+	 *
68
+	 * @return string
69
+	 */
70
+	public function getName() {
71
+
72
+		return $this->subscriptionInfo['uri'];
73
+
74
+	}
75
+
76
+	/**
77
+	 * Returns the last modification time
78
+	 *
79
+	 * @return int
80
+	 */
81
+	public function getLastModified() {
82
+
83
+		if (isset($this->subscriptionInfo['lastmodified'])) {
84
+			return $this->subscriptionInfo['lastmodified'];
85
+		}
86
+
87
+	}
88
+
89
+	/**
90
+	 * Deletes the current node
91
+	 *
92
+	 * @return void
93
+	 */
94
+	public function delete() {
95
+
96
+		$this->caldavBackend->deleteSubscription(
97
+			$this->subscriptionInfo['id']
98
+		);
99
+
100
+	}
101
+
102
+	/**
103
+	 * Returns an array with all the child nodes
104
+	 *
105
+	 * @return DAV\INode[]
106
+	 */
107
+	public function getChildren() {
108
+
109
+		return [];
110
+
111
+	}
112
+
113
+	/**
114
+	 * Updates properties on this node.
115
+	 *
116
+	 * This method received a PropPatch object, which contains all the
117
+	 * information about the update.
118
+	 *
119
+	 * To update specific properties, call the 'handle' method on this object.
120
+	 * Read the PropPatch documentation for more information.
121
+	 *
122
+	 * @param PropPatch $propPatch
123
+	 * @return void
124
+	 */
125
+	public function propPatch(PropPatch $propPatch) {
126
+
127
+		return $this->caldavBackend->updateSubscription(
128
+			$this->subscriptionInfo['id'],
129
+			$propPatch
130
+		);
131
+
132
+	}
133
+
134
+	/**
135
+	 * Returns a list of properties for this nodes.
136
+	 *
137
+	 * The properties list is a list of propertynames the client requested,
138
+	 * encoded in clark-notation {xmlnamespace}tagname.
139
+	 *
140
+	 * If the array is empty, it means 'all properties' were requested.
141
+	 *
142
+	 * Note that it's fine to liberally give properties back, instead of
143
+	 * conforming to the list of requested properties.
144
+	 * The Server class will filter out the extra.
145
+	 *
146
+	 * @param array $properties
147
+	 * @return void
148
+	 */
149
+	public function getProperties($properties) {
150
+
151
+		$r = [];
152
+
153
+		foreach ($properties as $prop) {
154
+
155
+			switch ($prop) {
156
+				case '{http://calendarserver.org/ns/}source' :
157
+					$r[$prop] = new Href($this->subscriptionInfo['source'], false);
158
+					break;
159
+				default :
160
+					if (array_key_exists($prop, $this->subscriptionInfo)) {
161
+						$r[$prop] = $this->subscriptionInfo[$prop];
162
+					}
163
+					break;
164
+			}
165
+
166
+		}
167
+
168
+		return $r;
169
+
170
+	}
171
+
172
+	/**
173
+	 * Returns the owner principal.
174
+	 *
175
+	 * This must be a url to a principal, or null if there's no owner
176
+	 *
177
+	 * @return string|null
178
+	 */
179
+	public function getOwner() {
180
+
181
+		return $this->subscriptionInfo['principaluri'];
182
+
183
+	}
184
+
185
+	/**
186
+	 * Returns a group principal.
187
+	 *
188
+	 * This must be a url to a principal, or null if there's no owner
189
+	 *
190
+	 * @return string|null
191
+	 */
192
+	public function getGroup() {
193
+
194
+		return null;
195
+
196
+	}
197
+
198
+	/**
199
+	 * Returns a list of ACE's for this node.
200
+	 *
201
+	 * Each ACE has the following properties:
202
+	 *   * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
203
+	 *     currently the only supported privileges
204
+	 *   * 'principal', a url to the principal who owns the node
205
+	 *   * 'protected' (optional), indicating that this ACE is not allowed to
206
+	 *      be updated.
207
+	 *
208
+	 * @return array
209
+	 */
210
+	public function getACL() {
211
+
212
+		return [
213
+			[
214
+				'privilege' => '{DAV:}read',
215
+				'principal' => $this->getOwner(),
216
+				'protected' => true,
217
+			],
218
+			[
219
+				'privilege' => '{DAV:}write',
220
+				'principal' => $this->getOwner(),
221
+				'protected' => true,
222
+			],
223
+			[
224
+				'privilege' => '{DAV:}read',
225
+				'principal' => $this->getOwner() . '/calendar-proxy-write',
226
+				'protected' => true,
227
+			],
228
+			[
229
+				'privilege' => '{DAV:}write',
230
+				'principal' => $this->getOwner() . '/calendar-proxy-write',
231
+				'protected' => true,
232
+			],
233
+			[
234
+				'privilege' => '{DAV:}read',
235
+				'principal' => $this->getOwner() . '/calendar-proxy-read',
236
+				'protected' => true,
237
+			]
238
+		];
239
+
240
+	}
241
+
242
+	/**
243
+	 * Updates the ACL.
244
+	 *
245
+	 * This method will receive a list of new ACE's.
246
+	 *
247
+	 * @param array $acl
248
+	 * @return void
249
+	 */
250
+	public function setACL(array $acl) {
251
+
252
+		throw new MethodNotAllowed('Changing ACL is not yet supported');
253
+
254
+	}
255
+
256
+	/**
257
+	 * Returns the list of supported privileges for this node.
258
+	 *
259
+	 * The returned data structure is a list of nested privileges.
260
+	 * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
261
+	 * standard structure.
262
+	 *
263
+	 * If null is returned from this method, the default privilege set is used,
264
+	 * which is fine for most common usecases.
265
+	 *
266
+	 * @return array|null
267
+	 */
268
+	public function getSupportedPrivilegeSet() {
269
+
270
+		return null;
271
+
272
+	}
273 273
 
274 274
 }
Please login to merge, or discard this patch.
Doc Comments   -1 removed lines patch added patch discarded remove patch
@@ -38,7 +38,6 @@
 block discarded – undo
38 38
      * Constructor
39 39
      *
40 40
      * @param SubscriptionSupport $caldavBackend
41
-     * @param array $calendarInfo
42 41
      */
43 42
     public function __construct(SubscriptionSupport $caldavBackend, array $subscriptionInfo) {
44 43
 
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Xml/Filter/CalendarData.php 3 patches
Unused Use Statements   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -2,11 +2,11 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\CalDAV\Xml\Filter;
4 4
 
5
-use Sabre\Xml\Reader;
6
-use Sabre\Xml\XmlDeserializable;
7
-use Sabre\DAV\Exception\BadRequest;
8 5
 use Sabre\CalDAV\Plugin;
6
+use Sabre\DAV\Exception\BadRequest;
9 7
 use Sabre\VObject\DateTimeParser;
8
+use Sabre\Xml\Reader;
9
+use Sabre\Xml\XmlDeserializable;
10 10
 
11 11
 /**
12 12
  * CalendarData parser.
Please login to merge, or discard this patch.
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -27,58 +27,58 @@
 block discarded – undo
27 27
  */
28 28
 class CalendarData implements XmlDeserializable {
29 29
 
30
-    /**
31
-     * The deserialize method is called during xml parsing.
32
-     *
33
-     * This method is called statictly, this is because in theory this method
34
-     * may be used as a type of constructor, or factory method.
35
-     *
36
-     * Often you want to return an instance of the current class, but you are
37
-     * free to return other data as well.
38
-     *
39
-     * You are responsible for advancing the reader to the next element. Not
40
-     * doing anything will result in a never-ending loop.
41
-     *
42
-     * If you just want to skip parsing for this element altogether, you can
43
-     * just call $reader->next();
44
-     *
45
-     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
46
-     * the next element.
47
-     *
48
-     * @param Reader $reader
49
-     * @return mixed
50
-     */
51
-    static function xmlDeserialize(Reader $reader) {
30
+	/**
31
+	 * The deserialize method is called during xml parsing.
32
+	 *
33
+	 * This method is called statictly, this is because in theory this method
34
+	 * may be used as a type of constructor, or factory method.
35
+	 *
36
+	 * Often you want to return an instance of the current class, but you are
37
+	 * free to return other data as well.
38
+	 *
39
+	 * You are responsible for advancing the reader to the next element. Not
40
+	 * doing anything will result in a never-ending loop.
41
+	 *
42
+	 * If you just want to skip parsing for this element altogether, you can
43
+	 * just call $reader->next();
44
+	 *
45
+	 * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
46
+	 * the next element.
47
+	 *
48
+	 * @param Reader $reader
49
+	 * @return mixed
50
+	 */
51
+	static function xmlDeserialize(Reader $reader) {
52 52
 
53
-        $result = [
54
-            'contentType' => $reader->getAttribute('content-type') ?: 'text/calendar',
55
-            'version'     => $reader->getAttribute('version') ?: '2.0',
56
-        ];
53
+		$result = [
54
+			'contentType' => $reader->getAttribute('content-type') ?: 'text/calendar',
55
+			'version'     => $reader->getAttribute('version') ?: '2.0',
56
+		];
57 57
 
58
-        $elems = (array)$reader->parseInnerTree();
59
-        foreach ($elems as $elem) {
58
+		$elems = (array)$reader->parseInnerTree();
59
+		foreach ($elems as $elem) {
60 60
 
61
-            switch ($elem['name']) {
62
-                case '{' . Plugin::NS_CALDAV . '}expand' :
61
+			switch ($elem['name']) {
62
+				case '{' . Plugin::NS_CALDAV . '}expand' :
63 63
 
64
-                    $result['expand'] = [
65
-                        'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
66
-                        'end'   => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
67
-                    ];
64
+					$result['expand'] = [
65
+						'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
66
+						'end'   => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
67
+					];
68 68
 
69
-                    if (!$result['expand']['start'] || !$result['expand']['end']) {
70
-                        throw new BadRequest('The "start" and "end" attributes are required when expanding calendar-data');
71
-                    }
72
-                    if ($result['expand']['end'] <= $result['expand']['start']) {
73
-                        throw new BadRequest('The end-date must be larger than the start-date when expanding calendar-data');
74
-                    }
75
-                    break;
76
-            }
69
+					if (!$result['expand']['start'] || !$result['expand']['end']) {
70
+						throw new BadRequest('The "start" and "end" attributes are required when expanding calendar-data');
71
+					}
72
+					if ($result['expand']['end'] <= $result['expand']['start']) {
73
+						throw new BadRequest('The end-date must be larger than the start-date when expanding calendar-data');
74
+					}
75
+					break;
76
+			}
77 77
 
78
-        }
78
+		}
79 79
 
80
-        return $result;
80
+		return $result;
81 81
 
82
-    }
82
+	}
83 83
 
84 84
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@
 block discarded – undo
55 55
             'version'     => $reader->getAttribute('version') ?: '2.0',
56 56
         ];
57 57
 
58
-        $elems = (array)$reader->parseInnerTree();
58
+        $elems = (array) $reader->parseInnerTree();
59 59
         foreach ($elems as $elem) {
60 60
 
61 61
             switch ($elem['name']) {
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Xml/Filter/CompFilter.php 3 patches
Unused Use Statements   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -2,11 +2,11 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\CalDAV\Xml\Filter;
4 4
 
5
-use Sabre\Xml\Reader;
6
-use Sabre\Xml\XmlDeserializable;
7
-use Sabre\DAV\Exception\BadRequest;
8 5
 use Sabre\CalDAV\Plugin;
6
+use Sabre\DAV\Exception\BadRequest;
9 7
 use Sabre\VObject\DateTimeParser;
8
+use Sabre\Xml\Reader;
9
+use Sabre\Xml\XmlDeserializable;
10 10
 
11 11
 /**
12 12
  * CompFilter parser.
Please login to merge, or discard this patch.
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -24,74 +24,74 @@
 block discarded – undo
24 24
  */
25 25
 class CompFilter implements XmlDeserializable {
26 26
 
27
-    /**
28
-     * The deserialize method is called during xml parsing.
29
-     *
30
-     * This method is called statictly, this is because in theory this method
31
-     * may be used as a type of constructor, or factory method.
32
-     *
33
-     * Often you want to return an instance of the current class, but you are
34
-     * free to return other data as well.
35
-     *
36
-     * You are responsible for advancing the reader to the next element. Not
37
-     * doing anything will result in a never-ending loop.
38
-     *
39
-     * If you just want to skip parsing for this element altogether, you can
40
-     * just call $reader->next();
41
-     *
42
-     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
43
-     * the next element.
44
-     *
45
-     * @param Reader $reader
46
-     * @return mixed
47
-     */
48
-    static function xmlDeserialize(Reader $reader) {
27
+	/**
28
+	 * The deserialize method is called during xml parsing.
29
+	 *
30
+	 * This method is called statictly, this is because in theory this method
31
+	 * may be used as a type of constructor, or factory method.
32
+	 *
33
+	 * Often you want to return an instance of the current class, but you are
34
+	 * free to return other data as well.
35
+	 *
36
+	 * You are responsible for advancing the reader to the next element. Not
37
+	 * doing anything will result in a never-ending loop.
38
+	 *
39
+	 * If you just want to skip parsing for this element altogether, you can
40
+	 * just call $reader->next();
41
+	 *
42
+	 * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
43
+	 * the next element.
44
+	 *
45
+	 * @param Reader $reader
46
+	 * @return mixed
47
+	 */
48
+	static function xmlDeserialize(Reader $reader) {
49 49
 
50
-        $result = [
51
-            'name'           => null,
52
-            'is-not-defined' => false,
53
-            'comp-filters'   => [],
54
-            'prop-filters'   => [],
55
-            'time-range'     => false,
56
-        ];
50
+		$result = [
51
+			'name'           => null,
52
+			'is-not-defined' => false,
53
+			'comp-filters'   => [],
54
+			'prop-filters'   => [],
55
+			'time-range'     => false,
56
+		];
57 57
 
58
-        $att = $reader->parseAttributes();
59
-        $result['name'] = $att['name'];
58
+		$att = $reader->parseAttributes();
59
+		$result['name'] = $att['name'];
60 60
 
61
-        $elems = $reader->parseInnerTree();
61
+		$elems = $reader->parseInnerTree();
62 62
 
63
-        if (is_array($elems)) foreach ($elems as $elem) {
63
+		if (is_array($elems)) foreach ($elems as $elem) {
64 64
 
65
-            switch ($elem['name']) {
65
+			switch ($elem['name']) {
66 66
 
67
-                case '{' . Plugin::NS_CALDAV . '}comp-filter' :
68
-                    $result['comp-filters'][] = $elem['value'];
69
-                    break;
70
-                case '{' . Plugin::NS_CALDAV . '}prop-filter' :
71
-                    $result['prop-filters'][] = $elem['value'];
72
-                    break;
73
-                case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
74
-                    $result['is-not-defined'] = true;
75
-                    break;
76
-                case '{' . Plugin::NS_CALDAV . '}time-range' :
77
-                    if ($result['name'] === 'VCALENDAR') {
78
-                        throw new BadRequest('You cannot add time-range filters on the VCALENDAR component');
79
-                    }
80
-                    $result['time-range'] = [
81
-                        'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
82
-                        'end'   => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
83
-                    ];
84
-                    if ($result['time-range']['start'] && $result['time-range']['end'] && $result['time-range']['end'] <= $result['time-range']['start']) {
85
-                        throw new BadRequest('The end-date must be larger than the start-date');
86
-                    }
87
-                    break;
67
+				case '{' . Plugin::NS_CALDAV . '}comp-filter' :
68
+					$result['comp-filters'][] = $elem['value'];
69
+					break;
70
+				case '{' . Plugin::NS_CALDAV . '}prop-filter' :
71
+					$result['prop-filters'][] = $elem['value'];
72
+					break;
73
+				case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
74
+					$result['is-not-defined'] = true;
75
+					break;
76
+				case '{' . Plugin::NS_CALDAV . '}time-range' :
77
+					if ($result['name'] === 'VCALENDAR') {
78
+						throw new BadRequest('You cannot add time-range filters on the VCALENDAR component');
79
+					}
80
+					$result['time-range'] = [
81
+						'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
82
+						'end'   => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
83
+					];
84
+					if ($result['time-range']['start'] && $result['time-range']['end'] && $result['time-range']['end'] <= $result['time-range']['start']) {
85
+						throw new BadRequest('The end-date must be larger than the start-date');
86
+					}
87
+					break;
88 88
 
89
-            }
89
+			}
90 90
 
91
-        }
91
+		}
92 92
 
93
-        return $result;
93
+		return $result;
94 94
 
95
-    }
95
+	}
96 96
 
97 97
 }
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -60,12 +60,14 @@
 block discarded – undo
60 60
 
61 61
         $elems = $reader->parseInnerTree();
62 62
 
63
-        if (is_array($elems)) foreach ($elems as $elem) {
63
+        if (is_array($elems)) {
64
+        	foreach ($elems as $elem) {
64 65
 
65 66
             switch ($elem['name']) {
66 67
 
67 68
                 case '{' . Plugin::NS_CALDAV . '}comp-filter' :
68 69
                     $result['comp-filters'][] = $elem['value'];
70
+        }
69 71
                     break;
70 72
                 case '{' . Plugin::NS_CALDAV . '}prop-filter' :
71 73
                     $result['prop-filters'][] = $elem['value'];
Please login to merge, or discard this patch.
libraries/SabreDAV/CalDAV/Xml/Filter/ParamFilter.php 3 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -2,9 +2,9 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\CalDAV\Xml\Filter;
4 4
 
5
+use Sabre\CalDAV\Plugin;
5 6
 use Sabre\Xml\Reader;
6 7
 use Sabre\Xml\XmlDeserializable;
7
-use Sabre\CalDAV\Plugin;
8 8
 
9 9
 /**
10 10
  * PropFilter parser.
Please login to merge, or discard this patch.
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -22,61 +22,61 @@
 block discarded – undo
22 22
  */
23 23
 class ParamFilter implements XmlDeserializable {
24 24
 
25
-    /**
26
-     * The deserialize method is called during xml parsing.
27
-     *
28
-     * This method is called statictly, this is because in theory this method
29
-     * may be used as a type of constructor, or factory method.
30
-     *
31
-     * Often you want to return an instance of the current class, but you are
32
-     * free to return other data as well.
33
-     *
34
-     * Important note 2: You are responsible for advancing the reader to the
35
-     * next element. Not doing anything will result in a never-ending loop.
36
-     *
37
-     * If you just want to skip parsing for this element altogether, you can
38
-     * just call $reader->next();
39
-     *
40
-     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
41
-     * the next element.
42
-     *
43
-     * @param Reader $reader
44
-     * @return mixed
45
-     */
46
-    static function xmlDeserialize(Reader $reader) {
25
+	/**
26
+	 * The deserialize method is called during xml parsing.
27
+	 *
28
+	 * This method is called statictly, this is because in theory this method
29
+	 * may be used as a type of constructor, or factory method.
30
+	 *
31
+	 * Often you want to return an instance of the current class, but you are
32
+	 * free to return other data as well.
33
+	 *
34
+	 * Important note 2: You are responsible for advancing the reader to the
35
+	 * next element. Not doing anything will result in a never-ending loop.
36
+	 *
37
+	 * If you just want to skip parsing for this element altogether, you can
38
+	 * just call $reader->next();
39
+	 *
40
+	 * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
41
+	 * the next element.
42
+	 *
43
+	 * @param Reader $reader
44
+	 * @return mixed
45
+	 */
46
+	static function xmlDeserialize(Reader $reader) {
47 47
 
48
-        $result = [
49
-            'name'           => null,
50
-            'is-not-defined' => false,
51
-            'text-match'     => null,
52
-        ];
48
+		$result = [
49
+			'name'           => null,
50
+			'is-not-defined' => false,
51
+			'text-match'     => null,
52
+		];
53 53
 
54
-        $att = $reader->parseAttributes();
55
-        $result['name'] = $att['name'];
54
+		$att = $reader->parseAttributes();
55
+		$result['name'] = $att['name'];
56 56
 
57
-        $elems = $reader->parseInnerTree();
57
+		$elems = $reader->parseInnerTree();
58 58
 
59
-        if (is_array($elems)) foreach ($elems as $elem) {
59
+		if (is_array($elems)) foreach ($elems as $elem) {
60 60
 
61
-            switch ($elem['name']) {
61
+			switch ($elem['name']) {
62 62
 
63
-                case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
64
-                    $result['is-not-defined'] = true;
65
-                    break;
66
-                case '{' . Plugin::NS_CALDAV . '}text-match' :
67
-                    $result['text-match'] = [
68
-                        'negate-condition' => isset($elem['attributes']['negate-condition']) && $elem['attributes']['negate-condition'] === 'yes',
69
-                        'collation'        => isset($elem['attributes']['collation']) ? $elem['attributes']['collation'] : 'i;ascii-casemap',
70
-                        'value'            => $elem['value'],
71
-                    ];
72
-                    break;
63
+				case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
64
+					$result['is-not-defined'] = true;
65
+					break;
66
+				case '{' . Plugin::NS_CALDAV . '}text-match' :
67
+					$result['text-match'] = [
68
+						'negate-condition' => isset($elem['attributes']['negate-condition']) && $elem['attributes']['negate-condition'] === 'yes',
69
+						'collation'        => isset($elem['attributes']['collation']) ? $elem['attributes']['collation'] : 'i;ascii-casemap',
70
+						'value'            => $elem['value'],
71
+					];
72
+					break;
73 73
 
74
-            }
74
+			}
75 75
 
76
-        }
76
+		}
77 77
 
78
-        return $result;
78
+		return $result;
79 79
 
80
-    }
80
+	}
81 81
 
82 82
 }
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -56,12 +56,14 @@
 block discarded – undo
56 56
 
57 57
         $elems = $reader->parseInnerTree();
58 58
 
59
-        if (is_array($elems)) foreach ($elems as $elem) {
59
+        if (is_array($elems)) {
60
+        	foreach ($elems as $elem) {
60 61
 
61 62
             switch ($elem['name']) {
62 63
 
63 64
                 case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
64 65
                     $result['is-not-defined'] = true;
66
+        }
65 67
                     break;
66 68
                 case '{' . Plugin::NS_CALDAV . '}text-match' :
67 69
                     $result['text-match'] = [
Please login to merge, or discard this patch.