Completed
Branch develop (804b52)
by
unknown
20:54
created
htdocs/includes/sabre/sabre/dav/lib/DAV/Browser/GuessContentType.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -26,68 +26,68 @@
 block discarded – undo
26 26
  */
27 27
 class GuessContentType extends DAV\ServerPlugin
28 28
 {
29
-    /**
30
-     * List of recognized file extensions.
31
-     *
32
-     * Feel free to add more
33
-     *
34
-     * @var array
35
-     */
36
-    public $extensionMap = [
37
-        // images
38
-        'jpg' => 'image/jpeg',
39
-        'gif' => 'image/gif',
40
-        'png' => 'image/png',
29
+	/**
30
+	 * List of recognized file extensions.
31
+	 *
32
+	 * Feel free to add more
33
+	 *
34
+	 * @var array
35
+	 */
36
+	public $extensionMap = [
37
+		// images
38
+		'jpg' => 'image/jpeg',
39
+		'gif' => 'image/gif',
40
+		'png' => 'image/png',
41 41
 
42
-        // groupware
43
-        'ics' => 'text/calendar',
44
-        'vcf' => 'text/vcard',
42
+		// groupware
43
+		'ics' => 'text/calendar',
44
+		'vcf' => 'text/vcard',
45 45
 
46
-        // text
47
-        'txt' => 'text/plain',
48
-    ];
46
+		// text
47
+		'txt' => 'text/plain',
48
+	];
49 49
 
50
-    /**
51
-     * Initializes the plugin.
52
-     */
53
-    public function initialize(DAV\Server $server)
54
-    {
55
-        // Using a relatively low priority (200) to allow other extensions
56
-        // to set the content-type first.
57
-        $server->on('propFind', [$this, 'propFind'], 200);
58
-    }
50
+	/**
51
+	 * Initializes the plugin.
52
+	 */
53
+	public function initialize(DAV\Server $server)
54
+	{
55
+		// Using a relatively low priority (200) to allow other extensions
56
+		// to set the content-type first.
57
+		$server->on('propFind', [$this, 'propFind'], 200);
58
+	}
59 59
 
60
-    /**
61
-     * Our PROPFIND handler.
62
-     *
63
-     * Here we set a contenttype, if the node didn't already have one.
64
-     */
65
-    public function propFind(PropFind $propFind, INode $node)
66
-    {
67
-        $propFind->handle('{DAV:}getcontenttype', function () use ($propFind) {
68
-            list(, $fileName) = Uri\split($propFind->getPath());
60
+	/**
61
+	 * Our PROPFIND handler.
62
+	 *
63
+	 * Here we set a contenttype, if the node didn't already have one.
64
+	 */
65
+	public function propFind(PropFind $propFind, INode $node)
66
+	{
67
+		$propFind->handle('{DAV:}getcontenttype', function () use ($propFind) {
68
+			list(, $fileName) = Uri\split($propFind->getPath());
69 69
 
70
-            return $this->getContentType($fileName);
71
-        });
72
-    }
70
+			return $this->getContentType($fileName);
71
+		});
72
+	}
73 73
 
74
-    /**
75
-     * Simple method to return the contenttype.
76
-     *
77
-     * @param string $fileName
78
-     *
79
-     * @return string
80
-     */
81
-    protected function getContentType($fileName)
82
-    {
83
-        if (null !== $fileName) {
84
-            // Just grabbing the extension
85
-            $extension = strtolower(substr($fileName, strrpos($fileName, '.') + 1));
86
-            if (isset($this->extensionMap[$extension])) {
87
-                return $this->extensionMap[$extension];
88
-            }
89
-        }
74
+	/**
75
+	 * Simple method to return the contenttype.
76
+	 *
77
+	 * @param string $fileName
78
+	 *
79
+	 * @return string
80
+	 */
81
+	protected function getContentType($fileName)
82
+	{
83
+		if (null !== $fileName) {
84
+			// Just grabbing the extension
85
+			$extension = strtolower(substr($fileName, strrpos($fileName, '.') + 1));
86
+			if (isset($this->extensionMap[$extension])) {
87
+				return $this->extensionMap[$extension];
88
+			}
89
+		}
90 90
 
91
-        return 'application/octet-stream';
92
-    }
91
+		return 'application/octet-stream';
92
+	}
93 93
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/ICollection.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -15,65 +15,65 @@
 block discarded – undo
15 15
  */
16 16
 interface ICollection extends INode
17 17
 {
18
-    /**
19
-     * Creates a new file in the directory.
20
-     *
21
-     * Data will either be supplied as a stream resource, or in certain cases
22
-     * as a string. Keep in mind that you may have to support either.
23
-     *
24
-     * After successful creation of the file, you may choose to return the ETag
25
-     * of the new file here.
26
-     *
27
-     * The returned ETag must be surrounded by double-quotes (The quotes should
28
-     * be part of the actual string).
29
-     *
30
-     * If you cannot accurately determine the ETag, you should not return it.
31
-     * If you don't store the file exactly as-is (you're transforming it
32
-     * somehow) you should also not return an ETag.
33
-     *
34
-     * This means that if a subsequent GET to this new file does not exactly
35
-     * return the same contents of what was submitted here, you are strongly
36
-     * recommended to omit the ETag.
37
-     *
38
-     * @param string          $name Name of the file
39
-     * @param resource|string $data Initial payload
40
-     *
41
-     * @return string|null
42
-     */
43
-    public function createFile($name, $data = null);
18
+	/**
19
+	 * Creates a new file in the directory.
20
+	 *
21
+	 * Data will either be supplied as a stream resource, or in certain cases
22
+	 * as a string. Keep in mind that you may have to support either.
23
+	 *
24
+	 * After successful creation of the file, you may choose to return the ETag
25
+	 * of the new file here.
26
+	 *
27
+	 * The returned ETag must be surrounded by double-quotes (The quotes should
28
+	 * be part of the actual string).
29
+	 *
30
+	 * If you cannot accurately determine the ETag, you should not return it.
31
+	 * If you don't store the file exactly as-is (you're transforming it
32
+	 * somehow) you should also not return an ETag.
33
+	 *
34
+	 * This means that if a subsequent GET to this new file does not exactly
35
+	 * return the same contents of what was submitted here, you are strongly
36
+	 * recommended to omit the ETag.
37
+	 *
38
+	 * @param string          $name Name of the file
39
+	 * @param resource|string $data Initial payload
40
+	 *
41
+	 * @return string|null
42
+	 */
43
+	public function createFile($name, $data = null);
44 44
 
45
-    /**
46
-     * Creates a new subdirectory.
47
-     *
48
-     * @param string $name
49
-     */
50
-    public function createDirectory($name);
45
+	/**
46
+	 * Creates a new subdirectory.
47
+	 *
48
+	 * @param string $name
49
+	 */
50
+	public function createDirectory($name);
51 51
 
52
-    /**
53
-     * Returns a specific child node, referenced by its name.
54
-     *
55
-     * This method must throw Sabre\DAV\Exception\NotFound if the node does not
56
-     * exist.
57
-     *
58
-     * @param string $name
59
-     *
60
-     * @return INode
61
-     */
62
-    public function getChild($name);
52
+	/**
53
+	 * Returns a specific child node, referenced by its name.
54
+	 *
55
+	 * This method must throw Sabre\DAV\Exception\NotFound if the node does not
56
+	 * exist.
57
+	 *
58
+	 * @param string $name
59
+	 *
60
+	 * @return INode
61
+	 */
62
+	public function getChild($name);
63 63
 
64
-    /**
65
-     * Returns an array with all the child nodes.
66
-     *
67
-     * @return INode[]
68
-     */
69
-    public function getChildren();
64
+	/**
65
+	 * Returns an array with all the child nodes.
66
+	 *
67
+	 * @return INode[]
68
+	 */
69
+	public function getChildren();
70 70
 
71
-    /**
72
-     * Checks if a child-node with the specified name exists.
73
-     *
74
-     * @param string $name
75
-     *
76
-     * @return bool
77
-     */
78
-    public function childExists($name);
71
+	/**
72
+	 * Checks if a child-node with the specified name exists.
73
+	 *
74
+	 * @param string $name
75
+	 *
76
+	 * @return bool
77
+	 */
78
+	public function childExists($name);
79 79
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/UUIDUtil.php 1 patch
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -17,50 +17,50 @@
 block discarded – undo
17 17
  */
18 18
 class UUIDUtil
19 19
 {
20
-    /**
21
-     * Returns a pseudo-random v4 UUID.
22
-     *
23
-     * This function is based on a comment by Andrew Moore on php.net
24
-     *
25
-     * @see http://www.php.net/manual/en/function.uniqid.php#94959
26
-     *
27
-     * @return string
28
-     */
29
-    public static function getUUID()
30
-    {
31
-        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
32
-            // 32 bits for "time_low"
33
-            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
20
+	/**
21
+	 * Returns a pseudo-random v4 UUID.
22
+	 *
23
+	 * This function is based on a comment by Andrew Moore on php.net
24
+	 *
25
+	 * @see http://www.php.net/manual/en/function.uniqid.php#94959
26
+	 *
27
+	 * @return string
28
+	 */
29
+	public static function getUUID()
30
+	{
31
+		return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
32
+			// 32 bits for "time_low"
33
+			mt_rand(0, 0xffff), mt_rand(0, 0xffff),
34 34
 
35
-            // 16 bits for "time_mid"
36
-            mt_rand(0, 0xffff),
35
+			// 16 bits for "time_mid"
36
+			mt_rand(0, 0xffff),
37 37
 
38
-            // 16 bits for "time_hi_and_version",
39
-            // four most significant bits holds version number 4
40
-            mt_rand(0, 0x0fff) | 0x4000,
38
+			// 16 bits for "time_hi_and_version",
39
+			// four most significant bits holds version number 4
40
+			mt_rand(0, 0x0fff) | 0x4000,
41 41
 
42
-            // 16 bits, 8 bits for "clk_seq_hi_res",
43
-            // 8 bits for "clk_seq_low",
44
-            // two most significant bits holds zero and one for variant DCE1.1
45
-            mt_rand(0, 0x3fff) | 0x8000,
42
+			// 16 bits, 8 bits for "clk_seq_hi_res",
43
+			// 8 bits for "clk_seq_low",
44
+			// two most significant bits holds zero and one for variant DCE1.1
45
+			mt_rand(0, 0x3fff) | 0x8000,
46 46
 
47
-            // 48 bits for "node"
48
-            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
49
-        );
50
-    }
47
+			// 48 bits for "node"
48
+			mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
49
+		);
50
+	}
51 51
 
52
-    /**
53
-     * Checks if a string is a valid UUID.
54
-     *
55
-     * @param string $uuid
56
-     *
57
-     * @return bool
58
-     */
59
-    public static function validateUUID($uuid)
60
-    {
61
-        return 0 !== preg_match(
62
-            '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i',
63
-            $uuid
64
-        );
65
-    }
52
+	/**
53
+	 * Checks if a string is a valid UUID.
54
+	 *
55
+	 * @param string $uuid
56
+	 *
57
+	 * @return bool
58
+	 */
59
+	public static function validateUUID($uuid)
60
+	{
61
+		return 0 !== preg_match(
62
+			'/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i',
63
+			$uuid
64
+		);
65
+	}
66 66
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/Sharing/Plugin.php 1 patch
Indentation   +269 added lines, -269 removed lines patch added patch discarded remove patch
@@ -28,231 +28,231 @@  discard block
 block discarded – undo
28 28
  */
29 29
 class Plugin extends ServerPlugin
30 30
 {
31
-    const ACCESS_NOTSHARED = 0;
32
-    const ACCESS_SHAREDOWNER = 1;
33
-    const ACCESS_READ = 2;
34
-    const ACCESS_READWRITE = 3;
35
-    const ACCESS_NOACCESS = 4;
36
-
37
-    const INVITE_NORESPONSE = 1;
38
-    const INVITE_ACCEPTED = 2;
39
-    const INVITE_DECLINED = 3;
40
-    const INVITE_INVALID = 4;
41
-
42
-    /**
43
-     * Reference to SabreDAV server object.
44
-     *
45
-     * @var Server
46
-     */
47
-    protected $server;
48
-
49
-    /**
50
-     * This method should return a list of server-features.
51
-     *
52
-     * This is for example 'versioning' and is added to the DAV: header
53
-     * in an OPTIONS response.
54
-     *
55
-     * @return array
56
-     */
57
-    public function getFeatures()
58
-    {
59
-        return ['resource-sharing'];
60
-    }
61
-
62
-    /**
63
-     * Returns a plugin name.
64
-     *
65
-     * Using this name other plugins will be able to access other plugins
66
-     * using \Sabre\DAV\Server::getPlugin
67
-     *
68
-     * @return string
69
-     */
70
-    public function getPluginName()
71
-    {
72
-        return 'sharing';
73
-    }
74
-
75
-    /**
76
-     * This initializes the plugin.
77
-     *
78
-     * This function is called by Sabre\DAV\Server, after
79
-     * addPlugin is called.
80
-     *
81
-     * This method should set up the required event subscriptions.
82
-     */
83
-    public function initialize(Server $server)
84
-    {
85
-        $this->server = $server;
86
-
87
-        $server->xml->elementMap['{DAV:}share-resource'] = 'Sabre\\DAV\\Xml\\Request\\ShareResource';
88
-
89
-        array_push(
90
-            $server->protectedProperties,
91
-            '{DAV:}share-mode'
92
-        );
93
-
94
-        $server->on('method:POST', [$this, 'httpPost']);
95
-        $server->on('propFind', [$this, 'propFind']);
96
-        $server->on('getSupportedPrivilegeSet', [$this, 'getSupportedPrivilegeSet']);
97
-        $server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel']);
98
-        $server->on('onBrowserPostAction', [$this, 'browserPostAction']);
99
-    }
100
-
101
-    /**
102
-     * Updates the list of sharees on a shared resource.
103
-     *
104
-     * The sharees  array is a list of people that are to be added modified
105
-     * or removed in the list of shares.
106
-     *
107
-     * @param string   $path
108
-     * @param Sharee[] $sharees
109
-     */
110
-    public function shareResource($path, array $sharees)
111
-    {
112
-        $node = $this->server->tree->getNodeForPath($path);
113
-
114
-        if (!$node instanceof ISharedNode) {
115
-            throw new Forbidden('Sharing is not allowed on this node');
116
-        }
117
-
118
-        // Getting ACL info
119
-        $acl = $this->server->getPlugin('acl');
120
-
121
-        // If there's no ACL support, we allow everything
122
-        if ($acl) {
123
-            $acl->checkPrivileges($path, '{DAV:}share');
124
-        }
125
-
126
-        foreach ($sharees as $sharee) {
127
-            // We're going to attempt to get a local principal uri for a share
128
-            // href by emitting the getPrincipalByUri event.
129
-            $principal = null;
130
-            $this->server->emit('getPrincipalByUri', [$sharee->href, &$principal]);
131
-            $sharee->principal = $principal;
132
-        }
133
-        $node->updateInvites($sharees);
134
-    }
135
-
136
-    /**
137
-     * This event is triggered when properties are requested for nodes.
138
-     *
139
-     * This allows us to inject any sharings-specific properties.
140
-     */
141
-    public function propFind(PropFind $propFind, INode $node)
142
-    {
143
-        if ($node instanceof ISharedNode) {
144
-            $propFind->handle('{DAV:}share-access', function () use ($node) {
145
-                return new Property\ShareAccess($node->getShareAccess());
146
-            });
147
-            $propFind->handle('{DAV:}invite', function () use ($node) {
148
-                return new Property\Invite($node->getInvites());
149
-            });
150
-            $propFind->handle('{DAV:}share-resource-uri', function () use ($node) {
151
-                return new Property\Href($node->getShareResourceUri());
152
-            });
153
-        }
154
-    }
155
-
156
-    /**
157
-     * We intercept this to handle POST requests on shared resources.
158
-     *
159
-     * @return bool|null
160
-     */
161
-    public function httpPost(RequestInterface $request, ResponseInterface $response)
162
-    {
163
-        $path = $request->getPath();
164
-        $contentType = $request->getHeader('Content-Type');
165
-        if (null === $contentType) {
166
-            return;
167
-        }
168
-
169
-        // We're only interested in the davsharing content type.
170
-        if (false === strpos($contentType, 'application/davsharing+xml')) {
171
-            return;
172
-        }
173
-
174
-        $message = $this->server->xml->parse(
175
-            $request->getBody(),
176
-            $request->getUrl(),
177
-            $documentType
178
-        );
179
-
180
-        switch ($documentType) {
181
-            case '{DAV:}share-resource':
182
-                $this->shareResource($path, $message->sharees);
183
-                $response->setStatus(200);
184
-                // Adding this because sending a response body may cause issues,
185
-                // and I wanted some type of indicator the response was handled.
186
-                $response->setHeader('X-Sabre-Status', 'everything-went-well');
187
-
188
-                // Breaking the event chain
189
-                return false;
190
-
191
-            default:
192
-                throw new BadRequest('Unexpected document type: '.$documentType.' for this Content-Type');
193
-        }
194
-    }
195
-
196
-    /**
197
-     * This method is triggered whenever a subsystem reqeuests the privileges
198
-     * hat are supported on a particular node.
199
-     *
200
-     * We need to add a number of privileges for scheduling purposes.
201
-     */
202
-    public function getSupportedPrivilegeSet(INode $node, array &$supportedPrivilegeSet)
203
-    {
204
-        if ($node instanceof ISharedNode) {
205
-            $supportedPrivilegeSet['{DAV:}share'] = [
206
-                'abstract' => false,
207
-                'aggregates' => [],
208
-            ];
209
-        }
210
-    }
211
-
212
-    /**
213
-     * Returns a bunch of meta-data about the plugin.
214
-     *
215
-     * Providing this information is optional, and is mainly displayed by the
216
-     * Browser plugin.
217
-     *
218
-     * The description key in the returned array may contain html and will not
219
-     * be sanitized.
220
-     *
221
-     * @return array
222
-     */
223
-    public function getPluginInfo()
224
-    {
225
-        return [
226
-            'name' => $this->getPluginName(),
227
-            'description' => 'This plugin implements WebDAV resource sharing',
228
-            'link' => 'https://github.com/evert/webdav-sharing',
229
-        ];
230
-    }
231
-
232
-    /**
233
-     * This method is used to generate HTML output for the
234
-     * DAV\Browser\Plugin.
235
-     *
236
-     * @param string $output
237
-     * @param string $path
238
-     *
239
-     * @return bool|null
240
-     */
241
-    public function htmlActionsPanel(INode $node, &$output, $path)
242
-    {
243
-        if (!$node instanceof ISharedNode) {
244
-            return;
245
-        }
246
-
247
-        $aclPlugin = $this->server->getPlugin('acl');
248
-        if ($aclPlugin) {
249
-            if (!$aclPlugin->checkPrivileges($path, '{DAV:}share', \Sabre\DAVACL\Plugin::R_PARENT, false)) {
250
-                // Sharing is not permitted, we will not draw this interface.
251
-                return;
252
-            }
253
-        }
254
-
255
-        $output .= '<tr><td colspan="2"><form method="post" action="">
31
+	const ACCESS_NOTSHARED = 0;
32
+	const ACCESS_SHAREDOWNER = 1;
33
+	const ACCESS_READ = 2;
34
+	const ACCESS_READWRITE = 3;
35
+	const ACCESS_NOACCESS = 4;
36
+
37
+	const INVITE_NORESPONSE = 1;
38
+	const INVITE_ACCEPTED = 2;
39
+	const INVITE_DECLINED = 3;
40
+	const INVITE_INVALID = 4;
41
+
42
+	/**
43
+	 * Reference to SabreDAV server object.
44
+	 *
45
+	 * @var Server
46
+	 */
47
+	protected $server;
48
+
49
+	/**
50
+	 * This method should return a list of server-features.
51
+	 *
52
+	 * This is for example 'versioning' and is added to the DAV: header
53
+	 * in an OPTIONS response.
54
+	 *
55
+	 * @return array
56
+	 */
57
+	public function getFeatures()
58
+	{
59
+		return ['resource-sharing'];
60
+	}
61
+
62
+	/**
63
+	 * Returns a plugin name.
64
+	 *
65
+	 * Using this name other plugins will be able to access other plugins
66
+	 * using \Sabre\DAV\Server::getPlugin
67
+	 *
68
+	 * @return string
69
+	 */
70
+	public function getPluginName()
71
+	{
72
+		return 'sharing';
73
+	}
74
+
75
+	/**
76
+	 * This initializes the plugin.
77
+	 *
78
+	 * This function is called by Sabre\DAV\Server, after
79
+	 * addPlugin is called.
80
+	 *
81
+	 * This method should set up the required event subscriptions.
82
+	 */
83
+	public function initialize(Server $server)
84
+	{
85
+		$this->server = $server;
86
+
87
+		$server->xml->elementMap['{DAV:}share-resource'] = 'Sabre\\DAV\\Xml\\Request\\ShareResource';
88
+
89
+		array_push(
90
+			$server->protectedProperties,
91
+			'{DAV:}share-mode'
92
+		);
93
+
94
+		$server->on('method:POST', [$this, 'httpPost']);
95
+		$server->on('propFind', [$this, 'propFind']);
96
+		$server->on('getSupportedPrivilegeSet', [$this, 'getSupportedPrivilegeSet']);
97
+		$server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel']);
98
+		$server->on('onBrowserPostAction', [$this, 'browserPostAction']);
99
+	}
100
+
101
+	/**
102
+	 * Updates the list of sharees on a shared resource.
103
+	 *
104
+	 * The sharees  array is a list of people that are to be added modified
105
+	 * or removed in the list of shares.
106
+	 *
107
+	 * @param string   $path
108
+	 * @param Sharee[] $sharees
109
+	 */
110
+	public function shareResource($path, array $sharees)
111
+	{
112
+		$node = $this->server->tree->getNodeForPath($path);
113
+
114
+		if (!$node instanceof ISharedNode) {
115
+			throw new Forbidden('Sharing is not allowed on this node');
116
+		}
117
+
118
+		// Getting ACL info
119
+		$acl = $this->server->getPlugin('acl');
120
+
121
+		// If there's no ACL support, we allow everything
122
+		if ($acl) {
123
+			$acl->checkPrivileges($path, '{DAV:}share');
124
+		}
125
+
126
+		foreach ($sharees as $sharee) {
127
+			// We're going to attempt to get a local principal uri for a share
128
+			// href by emitting the getPrincipalByUri event.
129
+			$principal = null;
130
+			$this->server->emit('getPrincipalByUri', [$sharee->href, &$principal]);
131
+			$sharee->principal = $principal;
132
+		}
133
+		$node->updateInvites($sharees);
134
+	}
135
+
136
+	/**
137
+	 * This event is triggered when properties are requested for nodes.
138
+	 *
139
+	 * This allows us to inject any sharings-specific properties.
140
+	 */
141
+	public function propFind(PropFind $propFind, INode $node)
142
+	{
143
+		if ($node instanceof ISharedNode) {
144
+			$propFind->handle('{DAV:}share-access', function () use ($node) {
145
+				return new Property\ShareAccess($node->getShareAccess());
146
+			});
147
+			$propFind->handle('{DAV:}invite', function () use ($node) {
148
+				return new Property\Invite($node->getInvites());
149
+			});
150
+			$propFind->handle('{DAV:}share-resource-uri', function () use ($node) {
151
+				return new Property\Href($node->getShareResourceUri());
152
+			});
153
+		}
154
+	}
155
+
156
+	/**
157
+	 * We intercept this to handle POST requests on shared resources.
158
+	 *
159
+	 * @return bool|null
160
+	 */
161
+	public function httpPost(RequestInterface $request, ResponseInterface $response)
162
+	{
163
+		$path = $request->getPath();
164
+		$contentType = $request->getHeader('Content-Type');
165
+		if (null === $contentType) {
166
+			return;
167
+		}
168
+
169
+		// We're only interested in the davsharing content type.
170
+		if (false === strpos($contentType, 'application/davsharing+xml')) {
171
+			return;
172
+		}
173
+
174
+		$message = $this->server->xml->parse(
175
+			$request->getBody(),
176
+			$request->getUrl(),
177
+			$documentType
178
+		);
179
+
180
+		switch ($documentType) {
181
+			case '{DAV:}share-resource':
182
+				$this->shareResource($path, $message->sharees);
183
+				$response->setStatus(200);
184
+				// Adding this because sending a response body may cause issues,
185
+				// and I wanted some type of indicator the response was handled.
186
+				$response->setHeader('X-Sabre-Status', 'everything-went-well');
187
+
188
+				// Breaking the event chain
189
+				return false;
190
+
191
+			default:
192
+				throw new BadRequest('Unexpected document type: '.$documentType.' for this Content-Type');
193
+		}
194
+	}
195
+
196
+	/**
197
+	 * This method is triggered whenever a subsystem reqeuests the privileges
198
+	 * hat are supported on a particular node.
199
+	 *
200
+	 * We need to add a number of privileges for scheduling purposes.
201
+	 */
202
+	public function getSupportedPrivilegeSet(INode $node, array &$supportedPrivilegeSet)
203
+	{
204
+		if ($node instanceof ISharedNode) {
205
+			$supportedPrivilegeSet['{DAV:}share'] = [
206
+				'abstract' => false,
207
+				'aggregates' => [],
208
+			];
209
+		}
210
+	}
211
+
212
+	/**
213
+	 * Returns a bunch of meta-data about the plugin.
214
+	 *
215
+	 * Providing this information is optional, and is mainly displayed by the
216
+	 * Browser plugin.
217
+	 *
218
+	 * The description key in the returned array may contain html and will not
219
+	 * be sanitized.
220
+	 *
221
+	 * @return array
222
+	 */
223
+	public function getPluginInfo()
224
+	{
225
+		return [
226
+			'name' => $this->getPluginName(),
227
+			'description' => 'This plugin implements WebDAV resource sharing',
228
+			'link' => 'https://github.com/evert/webdav-sharing',
229
+		];
230
+	}
231
+
232
+	/**
233
+	 * This method is used to generate HTML output for the
234
+	 * DAV\Browser\Plugin.
235
+	 *
236
+	 * @param string $output
237
+	 * @param string $path
238
+	 *
239
+	 * @return bool|null
240
+	 */
241
+	public function htmlActionsPanel(INode $node, &$output, $path)
242
+	{
243
+		if (!$node instanceof ISharedNode) {
244
+			return;
245
+		}
246
+
247
+		$aclPlugin = $this->server->getPlugin('acl');
248
+		if ($aclPlugin) {
249
+			if (!$aclPlugin->checkPrivileges($path, '{DAV:}share', \Sabre\DAVACL\Plugin::R_PARENT, false)) {
250
+				// Sharing is not permitted, we will not draw this interface.
251
+				return;
252
+			}
253
+		}
254
+
255
+		$output .= '<tr><td colspan="2"><form method="post" action="">
256 256
             <h3>Share this resource</h3>
257 257
             <input type="hidden" name="sabreAction" value="share" />
258 258
             <label>Share with (uri):</label> <input type="text" name="href" placeholder="mailto:[email protected]"/><br />
@@ -265,48 +265,48 @@  discard block
 block discarded – undo
265 265
              <input type="submit" value="share" />
266 266
             </form>
267 267
             </td></tr>';
268
-    }
269
-
270
-    /**
271
-     * This method is triggered for POST actions generated by the browser
272
-     * plugin.
273
-     *
274
-     * @param string $path
275
-     * @param string $action
276
-     * @param array  $postVars
277
-     */
278
-    public function browserPostAction($path, $action, $postVars)
279
-    {
280
-        if ('share' !== $action) {
281
-            return;
282
-        }
283
-
284
-        if (empty($postVars['href'])) {
285
-            throw new BadRequest('The "href" POST parameter is required');
286
-        }
287
-        if (empty($postVars['access'])) {
288
-            throw new BadRequest('The "access" POST parameter is required');
289
-        }
290
-
291
-        $accessMap = [
292
-            'readwrite' => self::ACCESS_READWRITE,
293
-            'read' => self::ACCESS_READ,
294
-            'no-access' => self::ACCESS_NOACCESS,
295
-        ];
296
-
297
-        if (!isset($accessMap[$postVars['access']])) {
298
-            throw new BadRequest('The "access" POST must be readwrite, read or no-access');
299
-        }
300
-        $sharee = new Sharee([
301
-            'href' => $postVars['href'],
302
-            'access' => $accessMap[$postVars['access']],
303
-        ]);
304
-
305
-        $this->shareResource(
306
-            $path,
307
-            [$sharee]
308
-        );
309
-
310
-        return false;
311
-    }
268
+	}
269
+
270
+	/**
271
+	 * This method is triggered for POST actions generated by the browser
272
+	 * plugin.
273
+	 *
274
+	 * @param string $path
275
+	 * @param string $action
276
+	 * @param array  $postVars
277
+	 */
278
+	public function browserPostAction($path, $action, $postVars)
279
+	{
280
+		if ('share' !== $action) {
281
+			return;
282
+		}
283
+
284
+		if (empty($postVars['href'])) {
285
+			throw new BadRequest('The "href" POST parameter is required');
286
+		}
287
+		if (empty($postVars['access'])) {
288
+			throw new BadRequest('The "access" POST parameter is required');
289
+		}
290
+
291
+		$accessMap = [
292
+			'readwrite' => self::ACCESS_READWRITE,
293
+			'read' => self::ACCESS_READ,
294
+			'no-access' => self::ACCESS_NOACCESS,
295
+		];
296
+
297
+		if (!isset($accessMap[$postVars['access']])) {
298
+			throw new BadRequest('The "access" POST must be readwrite, read or no-access');
299
+		}
300
+		$sharee = new Sharee([
301
+			'href' => $postVars['href'],
302
+			'access' => $accessMap[$postVars['access']],
303
+		]);
304
+
305
+		$this->shareResource(
306
+			$path,
307
+			[$sharee]
308
+		);
309
+
310
+		return false;
311
+	}
312 312
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/Sharing/ISharedNode.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -17,53 +17,53 @@
 block discarded – undo
17 17
  */
18 18
 interface ISharedNode extends INode
19 19
 {
20
-    /**
21
-     * Returns the 'access level' for the instance of this shared resource.
22
-     *
23
-     * The value should be one of the Sabre\DAV\Sharing\Plugin::ACCESS_
24
-     * constants.
25
-     *
26
-     * @return int
27
-     */
28
-    public function getShareAccess();
20
+	/**
21
+	 * Returns the 'access level' for the instance of this shared resource.
22
+	 *
23
+	 * The value should be one of the Sabre\DAV\Sharing\Plugin::ACCESS_
24
+	 * constants.
25
+	 *
26
+	 * @return int
27
+	 */
28
+	public function getShareAccess();
29 29
 
30
-    /**
31
-     * This function must return a URI that uniquely identifies the shared
32
-     * resource. This URI should be identical across instances, and is
33
-     * also used in several other XML bodies to connect invites to
34
-     * resources.
35
-     *
36
-     * This may simply be a relative reference to the original shared instance,
37
-     * but it could also be a urn. As long as it's a valid URI and unique.
38
-     *
39
-     * @return string
40
-     */
41
-    public function getShareResourceUri();
30
+	/**
31
+	 * This function must return a URI that uniquely identifies the shared
32
+	 * resource. This URI should be identical across instances, and is
33
+	 * also used in several other XML bodies to connect invites to
34
+	 * resources.
35
+	 *
36
+	 * This may simply be a relative reference to the original shared instance,
37
+	 * but it could also be a urn. As long as it's a valid URI and unique.
38
+	 *
39
+	 * @return string
40
+	 */
41
+	public function getShareResourceUri();
42 42
 
43
-    /**
44
-     * Updates the list of sharees.
45
-     *
46
-     * Every item must be a Sharee object.
47
-     *
48
-     * @param \Sabre\DAV\Xml\Element\Sharee[] $sharees
49
-     */
50
-    public function updateInvites(array $sharees);
43
+	/**
44
+	 * Updates the list of sharees.
45
+	 *
46
+	 * Every item must be a Sharee object.
47
+	 *
48
+	 * @param \Sabre\DAV\Xml\Element\Sharee[] $sharees
49
+	 */
50
+	public function updateInvites(array $sharees);
51 51
 
52
-    /**
53
-     * Returns the list of people whom this resource is shared with.
54
-     *
55
-     * Every item in the returned array must be a Sharee object with
56
-     * at least the following properties set:
57
-     *
58
-     * * $href
59
-     * * $shareAccess
60
-     * * $inviteStatus
61
-     *
62
-     * and optionally:
63
-     *
64
-     * * $properties
65
-     *
66
-     * @return \Sabre\DAV\Xml\Element\Sharee[]
67
-     */
68
-    public function getInvites();
52
+	/**
53
+	 * Returns the list of people whom this resource is shared with.
54
+	 *
55
+	 * Every item in the returned array must be a Sharee object with
56
+	 * at least the following properties set:
57
+	 *
58
+	 * * $href
59
+	 * * $shareAccess
60
+	 * * $inviteStatus
61
+	 *
62
+	 * and optionally:
63
+	 *
64
+	 * * $properties
65
+	 *
66
+	 * @return \Sabre\DAV\Xml\Element\Sharee[]
67
+	 */
68
+	public function getInvites();
69 69
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/INode.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -13,32 +13,32 @@
 block discarded – undo
13 13
  */
14 14
 interface INode
15 15
 {
16
-    /**
17
-     * Deleted the current node.
18
-     */
19
-    public function delete();
16
+	/**
17
+	 * Deleted the current node.
18
+	 */
19
+	public function delete();
20 20
 
21
-    /**
22
-     * Returns the name of the node.
23
-     *
24
-     * This is used to generate the url.
25
-     *
26
-     * @return string
27
-     */
28
-    public function getName();
21
+	/**
22
+	 * Returns the name of the node.
23
+	 *
24
+	 * This is used to generate the url.
25
+	 *
26
+	 * @return string
27
+	 */
28
+	public function getName();
29 29
 
30
-    /**
31
-     * Renames the node.
32
-     *
33
-     * @param string $name The new name
34
-     */
35
-    public function setName($name);
30
+	/**
31
+	 * Renames the node.
32
+	 *
33
+	 * @param string $name The new name
34
+	 */
35
+	public function setName($name);
36 36
 
37
-    /**
38
-     * Returns the last modification time, as a unix timestamp. Return null
39
-     * if the information is not available.
40
-     *
41
-     * @return int|null
42
-     */
43
-    public function getLastModified();
37
+	/**
38
+	 * Returns the last modification time, as a unix timestamp. Return null
39
+	 * if the information is not available.
40
+	 *
41
+	 * @return int|null
42
+	 */
43
+	public function getLastModified();
44 44
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/TimeZoneUtil.php 1 patch
Indentation   +223 added lines, -223 removed lines patch added patch discarded remove patch
@@ -24,249 +24,249 @@
 block discarded – undo
24 24
  */
25 25
 class TimeZoneUtil
26 26
 {
27
-    /** @var self */
28
-    private static $instance = null;
27
+	/** @var self */
28
+	private static $instance = null;
29 29
 
30
-    /** @var TimezoneGuesser[] */
31
-    private $timezoneGuessers = [];
30
+	/** @var TimezoneGuesser[] */
31
+	private $timezoneGuessers = [];
32 32
 
33
-    /** @var TimezoneFinder[] */
34
-    private $timezoneFinders = [];
33
+	/** @var TimezoneFinder[] */
34
+	private $timezoneFinders = [];
35 35
 
36
-    private function __construct()
37
-    {
38
-        $this->addGuesser('lic', new GuessFromLicEntry());
39
-        $this->addGuesser('msTzId', new GuessFromMsTzId());
40
-        $this->addFinder('tzid', new FindFromTimezoneIdentifier());
41
-        $this->addFinder('tzmap', new FindFromTimezoneMap());
42
-        $this->addFinder('offset', new FindFromOffset());
43
-    }
36
+	private function __construct()
37
+	{
38
+		$this->addGuesser('lic', new GuessFromLicEntry());
39
+		$this->addGuesser('msTzId', new GuessFromMsTzId());
40
+		$this->addFinder('tzid', new FindFromTimezoneIdentifier());
41
+		$this->addFinder('tzmap', new FindFromTimezoneMap());
42
+		$this->addFinder('offset', new FindFromOffset());
43
+	}
44 44
 
45
-    private static function getInstance(): self
46
-    {
47
-        if (null === self::$instance) {
48
-            self::$instance = new self();
49
-        }
45
+	private static function getInstance(): self
46
+	{
47
+		if (null === self::$instance) {
48
+			self::$instance = new self();
49
+		}
50 50
 
51
-        return self::$instance;
52
-    }
51
+		return self::$instance;
52
+	}
53 53
 
54
-    private function addGuesser(string $key, TimezoneGuesser $guesser): void
55
-    {
56
-        $this->timezoneGuessers[$key] = $guesser;
57
-    }
54
+	private function addGuesser(string $key, TimezoneGuesser $guesser): void
55
+	{
56
+		$this->timezoneGuessers[$key] = $guesser;
57
+	}
58 58
 
59
-    private function addFinder(string $key, TimezoneFinder $finder): void
60
-    {
61
-        $this->timezoneFinders[$key] = $finder;
62
-    }
59
+	private function addFinder(string $key, TimezoneFinder $finder): void
60
+	{
61
+		$this->timezoneFinders[$key] = $finder;
62
+	}
63 63
 
64
-    /**
65
-     * This method will try to find out the correct timezone for an iCalendar
66
-     * date-time value.
67
-     *
68
-     * You must pass the contents of the TZID parameter, as well as the full
69
-     * calendar.
70
-     *
71
-     * If the lookup fails, this method will return the default PHP timezone
72
-     * (as configured using date_default_timezone_set, or the date.timezone ini
73
-     * setting).
74
-     *
75
-     * Alternatively, if $failIfUncertain is set to true, it will throw an
76
-     * exception if we cannot accurately determine the timezone.
77
-     */
78
-    private function findTimeZone(string $tzid, Component $vcalendar = null, bool $failIfUncertain = false): DateTimeZone
79
-    {
80
-        foreach ($this->timezoneFinders as $timezoneFinder) {
81
-            $timezone = $timezoneFinder->find($tzid, $failIfUncertain);
82
-            if (!$timezone instanceof DateTimeZone) {
83
-                continue;
84
-            }
64
+	/**
65
+	 * This method will try to find out the correct timezone for an iCalendar
66
+	 * date-time value.
67
+	 *
68
+	 * You must pass the contents of the TZID parameter, as well as the full
69
+	 * calendar.
70
+	 *
71
+	 * If the lookup fails, this method will return the default PHP timezone
72
+	 * (as configured using date_default_timezone_set, or the date.timezone ini
73
+	 * setting).
74
+	 *
75
+	 * Alternatively, if $failIfUncertain is set to true, it will throw an
76
+	 * exception if we cannot accurately determine the timezone.
77
+	 */
78
+	private function findTimeZone(string $tzid, Component $vcalendar = null, bool $failIfUncertain = false): DateTimeZone
79
+	{
80
+		foreach ($this->timezoneFinders as $timezoneFinder) {
81
+			$timezone = $timezoneFinder->find($tzid, $failIfUncertain);
82
+			if (!$timezone instanceof DateTimeZone) {
83
+				continue;
84
+			}
85 85
 
86
-            return $timezone;
87
-        }
86
+			return $timezone;
87
+		}
88 88
 
89
-        if ($vcalendar) {
90
-            // If that didn't work, we will scan VTIMEZONE objects
91
-            foreach ($vcalendar->select('VTIMEZONE') as $vtimezone) {
92
-                if ((string) $vtimezone->TZID === $tzid) {
93
-                    foreach ($this->timezoneGuessers as $timezoneGuesser) {
94
-                        $timezone = $timezoneGuesser->guess($vtimezone, $failIfUncertain);
95
-                        if (!$timezone instanceof DateTimeZone) {
96
-                            continue;
97
-                        }
89
+		if ($vcalendar) {
90
+			// If that didn't work, we will scan VTIMEZONE objects
91
+			foreach ($vcalendar->select('VTIMEZONE') as $vtimezone) {
92
+				if ((string) $vtimezone->TZID === $tzid) {
93
+					foreach ($this->timezoneGuessers as $timezoneGuesser) {
94
+						$timezone = $timezoneGuesser->guess($vtimezone, $failIfUncertain);
95
+						if (!$timezone instanceof DateTimeZone) {
96
+							continue;
97
+						}
98 98
 
99
-                        return $timezone;
100
-                    }
101
-                }
102
-            }
103
-        }
99
+						return $timezone;
100
+					}
101
+				}
102
+			}
103
+		}
104 104
 
105
-        if ($failIfUncertain) {
106
-            throw new InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: '.$tzid);
107
-        }
105
+		if ($failIfUncertain) {
106
+			throw new InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: '.$tzid);
107
+		}
108 108
 
109
-        // If we got all the way here, we default to whatever has been set as the PHP default timezone.
110
-        return new DateTimeZone(date_default_timezone_get());
111
-    }
109
+		// If we got all the way here, we default to whatever has been set as the PHP default timezone.
110
+		return new DateTimeZone(date_default_timezone_get());
111
+	}
112 112
 
113
-    public static function addTimezoneGuesser(string $key, TimezoneGuesser $guesser): void
114
-    {
115
-        self::getInstance()->addGuesser($key, $guesser);
116
-    }
113
+	public static function addTimezoneGuesser(string $key, TimezoneGuesser $guesser): void
114
+	{
115
+		self::getInstance()->addGuesser($key, $guesser);
116
+	}
117 117
 
118
-    public static function addTimezoneFinder(string $key, TimezoneFinder $finder): void
119
-    {
120
-        self::getInstance()->addFinder($key, $finder);
121
-    }
118
+	public static function addTimezoneFinder(string $key, TimezoneFinder $finder): void
119
+	{
120
+		self::getInstance()->addFinder($key, $finder);
121
+	}
122 122
 
123
-    /**
124
-     * @param string $tzid
125
-     * @param false  $failIfUncertain
126
-     *
127
-     * @return DateTimeZone
128
-     */
129
-    public static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false)
130
-    {
131
-        return self::getInstance()->findTimeZone($tzid, $vcalendar, $failIfUncertain);
132
-    }
123
+	/**
124
+	 * @param string $tzid
125
+	 * @param false  $failIfUncertain
126
+	 *
127
+	 * @return DateTimeZone
128
+	 */
129
+	public static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false)
130
+	{
131
+		return self::getInstance()->findTimeZone($tzid, $vcalendar, $failIfUncertain);
132
+	}
133 133
 
134
-    public static function clean(): void
135
-    {
136
-        self::$instance = null;
137
-    }
134
+	public static function clean(): void
135
+	{
136
+		self::$instance = null;
137
+	}
138 138
 
139
-    // Keeping things for backwards compatibility
140
-    /**
141
-     * @var array|null
142
-     *
143
-     * @deprecated
144
-     */
145
-    public static $map = null;
139
+	// Keeping things for backwards compatibility
140
+	/**
141
+	 * @var array|null
142
+	 *
143
+	 * @deprecated
144
+	 */
145
+	public static $map = null;
146 146
 
147
-    /**
148
-     * List of microsoft exchange timezone ids.
149
-     *
150
-     * Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
151
-     *
152
-     * @deprecated
153
-     */
154
-    public static $microsoftExchangeMap = [
155
-        0 => 'UTC',
156
-        31 => 'Africa/Casablanca',
157
-        // Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
158
-        // I'm not even kidding.. We handle this special case in the
159
-        // getTimeZone method.
160
-        2 => 'Europe/Lisbon',
161
-        1 => 'Europe/London',
162
-        4 => 'Europe/Berlin',
163
-        6 => 'Europe/Prague',
164
-        3 => 'Europe/Paris',
165
-        69 => 'Africa/Luanda', // This was a best guess
166
-        7 => 'Europe/Athens',
167
-        5 => 'Europe/Bucharest',
168
-        49 => 'Africa/Cairo',
169
-        50 => 'Africa/Harare',
170
-        59 => 'Europe/Helsinki',
171
-        27 => 'Asia/Jerusalem',
172
-        26 => 'Asia/Baghdad',
173
-        74 => 'Asia/Kuwait',
174
-        51 => 'Europe/Moscow',
175
-        56 => 'Africa/Nairobi',
176
-        25 => 'Asia/Tehran',
177
-        24 => 'Asia/Muscat', // Best guess
178
-        54 => 'Asia/Baku',
179
-        48 => 'Asia/Kabul',
180
-        58 => 'Asia/Yekaterinburg',
181
-        47 => 'Asia/Karachi',
182
-        23 => 'Asia/Calcutta',
183
-        62 => 'Asia/Kathmandu',
184
-        46 => 'Asia/Almaty',
185
-        71 => 'Asia/Dhaka',
186
-        66 => 'Asia/Colombo',
187
-        61 => 'Asia/Rangoon',
188
-        22 => 'Asia/Bangkok',
189
-        64 => 'Asia/Krasnoyarsk',
190
-        45 => 'Asia/Shanghai',
191
-        63 => 'Asia/Irkutsk',
192
-        21 => 'Asia/Singapore',
193
-        73 => 'Australia/Perth',
194
-        75 => 'Asia/Taipei',
195
-        20 => 'Asia/Tokyo',
196
-        72 => 'Asia/Seoul',
197
-        70 => 'Asia/Yakutsk',
198
-        19 => 'Australia/Adelaide',
199
-        44 => 'Australia/Darwin',
200
-        18 => 'Australia/Brisbane',
201
-        76 => 'Australia/Sydney',
202
-        43 => 'Pacific/Guam',
203
-        42 => 'Australia/Hobart',
204
-        68 => 'Asia/Vladivostok',
205
-        41 => 'Asia/Magadan',
206
-        17 => 'Pacific/Auckland',
207
-        40 => 'Pacific/Fiji',
208
-        67 => 'Pacific/Tongatapu',
209
-        29 => 'Atlantic/Azores',
210
-        53 => 'Atlantic/Cape_Verde',
211
-        30 => 'America/Noronha',
212
-         8 => 'America/Sao_Paulo', // Best guess
213
-        32 => 'America/Argentina/Buenos_Aires',
214
-        60 => 'America/Godthab',
215
-        28 => 'America/St_Johns',
216
-         9 => 'America/Halifax',
217
-        33 => 'America/Caracas',
218
-        65 => 'America/Santiago',
219
-        35 => 'America/Bogota',
220
-        10 => 'America/New_York',
221
-        34 => 'America/Indiana/Indianapolis',
222
-        55 => 'America/Guatemala',
223
-        11 => 'America/Chicago',
224
-        37 => 'America/Mexico_City',
225
-        36 => 'America/Edmonton',
226
-        38 => 'America/Phoenix',
227
-        12 => 'America/Denver', // Best guess
228
-        13 => 'America/Los_Angeles', // Best guess
229
-        14 => 'America/Anchorage',
230
-        15 => 'Pacific/Honolulu',
231
-        16 => 'Pacific/Midway',
232
-        39 => 'Pacific/Kwajalein',
233
-    ];
147
+	/**
148
+	 * List of microsoft exchange timezone ids.
149
+	 *
150
+	 * Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
151
+	 *
152
+	 * @deprecated
153
+	 */
154
+	public static $microsoftExchangeMap = [
155
+		0 => 'UTC',
156
+		31 => 'Africa/Casablanca',
157
+		// Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
158
+		// I'm not even kidding.. We handle this special case in the
159
+		// getTimeZone method.
160
+		2 => 'Europe/Lisbon',
161
+		1 => 'Europe/London',
162
+		4 => 'Europe/Berlin',
163
+		6 => 'Europe/Prague',
164
+		3 => 'Europe/Paris',
165
+		69 => 'Africa/Luanda', // This was a best guess
166
+		7 => 'Europe/Athens',
167
+		5 => 'Europe/Bucharest',
168
+		49 => 'Africa/Cairo',
169
+		50 => 'Africa/Harare',
170
+		59 => 'Europe/Helsinki',
171
+		27 => 'Asia/Jerusalem',
172
+		26 => 'Asia/Baghdad',
173
+		74 => 'Asia/Kuwait',
174
+		51 => 'Europe/Moscow',
175
+		56 => 'Africa/Nairobi',
176
+		25 => 'Asia/Tehran',
177
+		24 => 'Asia/Muscat', // Best guess
178
+		54 => 'Asia/Baku',
179
+		48 => 'Asia/Kabul',
180
+		58 => 'Asia/Yekaterinburg',
181
+		47 => 'Asia/Karachi',
182
+		23 => 'Asia/Calcutta',
183
+		62 => 'Asia/Kathmandu',
184
+		46 => 'Asia/Almaty',
185
+		71 => 'Asia/Dhaka',
186
+		66 => 'Asia/Colombo',
187
+		61 => 'Asia/Rangoon',
188
+		22 => 'Asia/Bangkok',
189
+		64 => 'Asia/Krasnoyarsk',
190
+		45 => 'Asia/Shanghai',
191
+		63 => 'Asia/Irkutsk',
192
+		21 => 'Asia/Singapore',
193
+		73 => 'Australia/Perth',
194
+		75 => 'Asia/Taipei',
195
+		20 => 'Asia/Tokyo',
196
+		72 => 'Asia/Seoul',
197
+		70 => 'Asia/Yakutsk',
198
+		19 => 'Australia/Adelaide',
199
+		44 => 'Australia/Darwin',
200
+		18 => 'Australia/Brisbane',
201
+		76 => 'Australia/Sydney',
202
+		43 => 'Pacific/Guam',
203
+		42 => 'Australia/Hobart',
204
+		68 => 'Asia/Vladivostok',
205
+		41 => 'Asia/Magadan',
206
+		17 => 'Pacific/Auckland',
207
+		40 => 'Pacific/Fiji',
208
+		67 => 'Pacific/Tongatapu',
209
+		29 => 'Atlantic/Azores',
210
+		53 => 'Atlantic/Cape_Verde',
211
+		30 => 'America/Noronha',
212
+		 8 => 'America/Sao_Paulo', // Best guess
213
+		32 => 'America/Argentina/Buenos_Aires',
214
+		60 => 'America/Godthab',
215
+		28 => 'America/St_Johns',
216
+		 9 => 'America/Halifax',
217
+		33 => 'America/Caracas',
218
+		65 => 'America/Santiago',
219
+		35 => 'America/Bogota',
220
+		10 => 'America/New_York',
221
+		34 => 'America/Indiana/Indianapolis',
222
+		55 => 'America/Guatemala',
223
+		11 => 'America/Chicago',
224
+		37 => 'America/Mexico_City',
225
+		36 => 'America/Edmonton',
226
+		38 => 'America/Phoenix',
227
+		12 => 'America/Denver', // Best guess
228
+		13 => 'America/Los_Angeles', // Best guess
229
+		14 => 'America/Anchorage',
230
+		15 => 'Pacific/Honolulu',
231
+		16 => 'Pacific/Midway',
232
+		39 => 'Pacific/Kwajalein',
233
+	];
234 234
 
235
-    /**
236
-     * This method will load in all the tz mapping information, if it's not yet
237
-     * done.
238
-     *
239
-     * @deprecated
240
-     */
241
-    public static function loadTzMaps()
242
-    {
243
-        if (!is_null(self::$map)) {
244
-            return;
245
-        }
235
+	/**
236
+	 * This method will load in all the tz mapping information, if it's not yet
237
+	 * done.
238
+	 *
239
+	 * @deprecated
240
+	 */
241
+	public static function loadTzMaps()
242
+	{
243
+		if (!is_null(self::$map)) {
244
+			return;
245
+		}
246 246
 
247
-        self::$map = array_merge(
248
-            include __DIR__.'/timezonedata/windowszones.php',
249
-            include __DIR__.'/timezonedata/lotuszones.php',
250
-            include __DIR__.'/timezonedata/exchangezones.php',
251
-            include __DIR__.'/timezonedata/php-workaround.php'
252
-        );
253
-    }
247
+		self::$map = array_merge(
248
+			include __DIR__.'/timezonedata/windowszones.php',
249
+			include __DIR__.'/timezonedata/lotuszones.php',
250
+			include __DIR__.'/timezonedata/exchangezones.php',
251
+			include __DIR__.'/timezonedata/php-workaround.php'
252
+		);
253
+	}
254 254
 
255
-    /**
256
-     * This method returns an array of timezone identifiers, that are supported
257
-     * by DateTimeZone(), but not returned by DateTimeZone::listIdentifiers().
258
-     *
259
-     * We're not using DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC) because:
260
-     * - It's not supported by some PHP versions as well as HHVM.
261
-     * - It also returns identifiers, that are invalid values for new DateTimeZone() on some PHP versions.
262
-     * (See timezonedata/php-bc.php and timezonedata php-workaround.php)
263
-     *
264
-     * @return array
265
-     *
266
-     * @deprecated
267
-     */
268
-    public static function getIdentifiersBC()
269
-    {
270
-        return include __DIR__.'/timezonedata/php-bc.php';
271
-    }
255
+	/**
256
+	 * This method returns an array of timezone identifiers, that are supported
257
+	 * by DateTimeZone(), but not returned by DateTimeZone::listIdentifiers().
258
+	 *
259
+	 * We're not using DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC) because:
260
+	 * - It's not supported by some PHP versions as well as HHVM.
261
+	 * - It also returns identifiers, that are invalid values for new DateTimeZone() on some PHP versions.
262
+	 * (See timezonedata/php-bc.php and timezonedata php-workaround.php)
263
+	 *
264
+	 * @return array
265
+	 *
266
+	 * @deprecated
267
+	 */
268
+	public static function getIdentifiersBC()
269
+	{
270
+		return include __DIR__.'/timezonedata/php-bc.php';
271
+	}
272 272
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/Document.php 1 patch
Indentation   +221 added lines, -221 removed lines patch added patch discarded remove patch
@@ -18,247 +18,247 @@
 block discarded – undo
18 18
  */
19 19
 abstract class Document extends Component
20 20
 {
21
-    /**
22
-     * Unknown document type.
23
-     */
24
-    const UNKNOWN = 1;
21
+	/**
22
+	 * Unknown document type.
23
+	 */
24
+	const UNKNOWN = 1;
25 25
 
26
-    /**
27
-     * vCalendar 1.0.
28
-     */
29
-    const VCALENDAR10 = 2;
26
+	/**
27
+	 * vCalendar 1.0.
28
+	 */
29
+	const VCALENDAR10 = 2;
30 30
 
31
-    /**
32
-     * iCalendar 2.0.
33
-     */
34
-    const ICALENDAR20 = 3;
31
+	/**
32
+	 * iCalendar 2.0.
33
+	 */
34
+	const ICALENDAR20 = 3;
35 35
 
36
-    /**
37
-     * vCard 2.1.
38
-     */
39
-    const VCARD21 = 4;
36
+	/**
37
+	 * vCard 2.1.
38
+	 */
39
+	const VCARD21 = 4;
40 40
 
41
-    /**
42
-     * vCard 3.0.
43
-     */
44
-    const VCARD30 = 5;
41
+	/**
42
+	 * vCard 3.0.
43
+	 */
44
+	const VCARD30 = 5;
45 45
 
46
-    /**
47
-     * vCard 4.0.
48
-     */
49
-    const VCARD40 = 6;
46
+	/**
47
+	 * vCard 4.0.
48
+	 */
49
+	const VCARD40 = 6;
50 50
 
51
-    /**
52
-     * The default name for this component.
53
-     *
54
-     * This should be 'VCALENDAR' or 'VCARD'.
55
-     *
56
-     * @var string
57
-     */
58
-    public static $defaultName;
51
+	/**
52
+	 * The default name for this component.
53
+	 *
54
+	 * This should be 'VCALENDAR' or 'VCARD'.
55
+	 *
56
+	 * @var string
57
+	 */
58
+	public static $defaultName;
59 59
 
60
-    /**
61
-     * List of properties, and which classes they map to.
62
-     *
63
-     * @var array
64
-     */
65
-    public static $propertyMap = [];
60
+	/**
61
+	 * List of properties, and which classes they map to.
62
+	 *
63
+	 * @var array
64
+	 */
65
+	public static $propertyMap = [];
66 66
 
67
-    /**
68
-     * List of components, along with which classes they map to.
69
-     *
70
-     * @var array
71
-     */
72
-    public static $componentMap = [];
67
+	/**
68
+	 * List of components, along with which classes they map to.
69
+	 *
70
+	 * @var array
71
+	 */
72
+	public static $componentMap = [];
73 73
 
74
-    /**
75
-     * List of value-types, and which classes they map to.
76
-     *
77
-     * @var array
78
-     */
79
-    public static $valueMap = [];
74
+	/**
75
+	 * List of value-types, and which classes they map to.
76
+	 *
77
+	 * @var array
78
+	 */
79
+	public static $valueMap = [];
80 80
 
81
-    /**
82
-     * Creates a new document.
83
-     *
84
-     * We're changing the default behavior slightly here. First, we don't want
85
-     * to have to specify a name (we already know it), and we want to allow
86
-     * children to be specified in the first argument.
87
-     *
88
-     * But, the default behavior also works.
89
-     *
90
-     * So the two sigs:
91
-     *
92
-     * new Document(array $children = [], $defaults = true);
93
-     * new Document(string $name, array $children = [], $defaults = true)
94
-     */
95
-    public function __construct()
96
-    {
97
-        $args = func_get_args();
98
-        $name = static::$defaultName;
99
-        if (0 === count($args) || is_array($args[0])) {
100
-            $children = isset($args[0]) ? $args[0] : [];
101
-            $defaults = isset($args[1]) ? $args[1] : true;
102
-        } else {
103
-            $name = $args[0];
104
-            $children = isset($args[1]) ? $args[1] : [];
105
-            $defaults = isset($args[2]) ? $args[2] : true;
106
-        }
107
-        parent::__construct($this, $name, $children, $defaults);
108
-    }
81
+	/**
82
+	 * Creates a new document.
83
+	 *
84
+	 * We're changing the default behavior slightly here. First, we don't want
85
+	 * to have to specify a name (we already know it), and we want to allow
86
+	 * children to be specified in the first argument.
87
+	 *
88
+	 * But, the default behavior also works.
89
+	 *
90
+	 * So the two sigs:
91
+	 *
92
+	 * new Document(array $children = [], $defaults = true);
93
+	 * new Document(string $name, array $children = [], $defaults = true)
94
+	 */
95
+	public function __construct()
96
+	{
97
+		$args = func_get_args();
98
+		$name = static::$defaultName;
99
+		if (0 === count($args) || is_array($args[0])) {
100
+			$children = isset($args[0]) ? $args[0] : [];
101
+			$defaults = isset($args[1]) ? $args[1] : true;
102
+		} else {
103
+			$name = $args[0];
104
+			$children = isset($args[1]) ? $args[1] : [];
105
+			$defaults = isset($args[2]) ? $args[2] : true;
106
+		}
107
+		parent::__construct($this, $name, $children, $defaults);
108
+	}
109 109
 
110
-    /**
111
-     * Returns the current document type.
112
-     *
113
-     * @return int
114
-     */
115
-    public function getDocumentType()
116
-    {
117
-        return self::UNKNOWN;
118
-    }
110
+	/**
111
+	 * Returns the current document type.
112
+	 *
113
+	 * @return int
114
+	 */
115
+	public function getDocumentType()
116
+	{
117
+		return self::UNKNOWN;
118
+	}
119 119
 
120
-    /**
121
-     * Creates a new component or property.
122
-     *
123
-     * If it's a known component, we will automatically call createComponent.
124
-     * otherwise, we'll assume it's a property and call createProperty instead.
125
-     *
126
-     * @param string $name
127
-     * @param string $arg1,... Unlimited number of args
128
-     *
129
-     * @return mixed
130
-     */
131
-    public function create($name)
132
-    {
133
-        if (isset(static::$componentMap[strtoupper($name)])) {
134
-            return call_user_func_array([$this, 'createComponent'], func_get_args());
135
-        } else {
136
-            return call_user_func_array([$this, 'createProperty'], func_get_args());
137
-        }
138
-    }
120
+	/**
121
+	 * Creates a new component or property.
122
+	 *
123
+	 * If it's a known component, we will automatically call createComponent.
124
+	 * otherwise, we'll assume it's a property and call createProperty instead.
125
+	 *
126
+	 * @param string $name
127
+	 * @param string $arg1,... Unlimited number of args
128
+	 *
129
+	 * @return mixed
130
+	 */
131
+	public function create($name)
132
+	{
133
+		if (isset(static::$componentMap[strtoupper($name)])) {
134
+			return call_user_func_array([$this, 'createComponent'], func_get_args());
135
+		} else {
136
+			return call_user_func_array([$this, 'createProperty'], func_get_args());
137
+		}
138
+	}
139 139
 
140
-    /**
141
-     * Creates a new component.
142
-     *
143
-     * This method automatically searches for the correct component class, based
144
-     * on its name.
145
-     *
146
-     * You can specify the children either in key=>value syntax, in which case
147
-     * properties will automatically be created, or you can just pass a list of
148
-     * Component and Property object.
149
-     *
150
-     * By default, a set of sensible values will be added to the component. For
151
-     * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
152
-     * ensure that this does not happen, set $defaults to false.
153
-     *
154
-     * @param string $name
155
-     * @param array  $children
156
-     * @param bool   $defaults
157
-     *
158
-     * @return Component
159
-     */
160
-    public function createComponent($name, array $children = null, $defaults = true)
161
-    {
162
-        $name = strtoupper($name);
163
-        $class = Component::class;
140
+	/**
141
+	 * Creates a new component.
142
+	 *
143
+	 * This method automatically searches for the correct component class, based
144
+	 * on its name.
145
+	 *
146
+	 * You can specify the children either in key=>value syntax, in which case
147
+	 * properties will automatically be created, or you can just pass a list of
148
+	 * Component and Property object.
149
+	 *
150
+	 * By default, a set of sensible values will be added to the component. For
151
+	 * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
152
+	 * ensure that this does not happen, set $defaults to false.
153
+	 *
154
+	 * @param string $name
155
+	 * @param array  $children
156
+	 * @param bool   $defaults
157
+	 *
158
+	 * @return Component
159
+	 */
160
+	public function createComponent($name, array $children = null, $defaults = true)
161
+	{
162
+		$name = strtoupper($name);
163
+		$class = Component::class;
164 164
 
165
-        if (isset(static::$componentMap[$name])) {
166
-            $class = static::$componentMap[$name];
167
-        }
168
-        if (is_null($children)) {
169
-            $children = [];
170
-        }
165
+		if (isset(static::$componentMap[$name])) {
166
+			$class = static::$componentMap[$name];
167
+		}
168
+		if (is_null($children)) {
169
+			$children = [];
170
+		}
171 171
 
172
-        return new $class($this, $name, $children, $defaults);
173
-    }
172
+		return new $class($this, $name, $children, $defaults);
173
+	}
174 174
 
175
-    /**
176
-     * Factory method for creating new properties.
177
-     *
178
-     * This method automatically searches for the correct property class, based
179
-     * on its name.
180
-     *
181
-     * You can specify the parameters either in key=>value syntax, in which case
182
-     * parameters will automatically be created, or you can just pass a list of
183
-     * Parameter objects.
184
-     *
185
-     * @param string $name
186
-     * @param mixed  $value
187
-     * @param array  $parameters
188
-     * @param string $valueType  Force a specific valuetype, such as URI or TEXT
189
-     *
190
-     * @return Property
191
-     */
192
-    public function createProperty($name, $value = null, array $parameters = null, $valueType = null)
193
-    {
194
-        // If there's a . in the name, it means it's prefixed by a groupname.
195
-        if (false !== ($i = strpos($name, '.'))) {
196
-            $group = substr($name, 0, $i);
197
-            $name = strtoupper(substr($name, $i + 1));
198
-        } else {
199
-            $name = strtoupper($name);
200
-            $group = null;
201
-        }
175
+	/**
176
+	 * Factory method for creating new properties.
177
+	 *
178
+	 * This method automatically searches for the correct property class, based
179
+	 * on its name.
180
+	 *
181
+	 * You can specify the parameters either in key=>value syntax, in which case
182
+	 * parameters will automatically be created, or you can just pass a list of
183
+	 * Parameter objects.
184
+	 *
185
+	 * @param string $name
186
+	 * @param mixed  $value
187
+	 * @param array  $parameters
188
+	 * @param string $valueType  Force a specific valuetype, such as URI or TEXT
189
+	 *
190
+	 * @return Property
191
+	 */
192
+	public function createProperty($name, $value = null, array $parameters = null, $valueType = null)
193
+	{
194
+		// If there's a . in the name, it means it's prefixed by a groupname.
195
+		if (false !== ($i = strpos($name, '.'))) {
196
+			$group = substr($name, 0, $i);
197
+			$name = strtoupper(substr($name, $i + 1));
198
+		} else {
199
+			$name = strtoupper($name);
200
+			$group = null;
201
+		}
202 202
 
203
-        $class = null;
203
+		$class = null;
204 204
 
205
-        if ($valueType) {
206
-            // The valueType argument comes first to figure out the correct
207
-            // class.
208
-            $class = $this->getClassNameForPropertyValue($valueType);
209
-        }
205
+		if ($valueType) {
206
+			// The valueType argument comes first to figure out the correct
207
+			// class.
208
+			$class = $this->getClassNameForPropertyValue($valueType);
209
+		}
210 210
 
211
-        if (is_null($class)) {
212
-            // If a VALUE parameter is supplied, we should use that.
213
-            if (isset($parameters['VALUE'])) {
214
-                $class = $this->getClassNameForPropertyValue($parameters['VALUE']);
215
-                if (is_null($class)) {
216
-                    throw new InvalidDataException('Unsupported VALUE parameter for '.$name.' property. You supplied "'.$parameters['VALUE'].'"');
217
-                }
218
-            } else {
219
-                $class = $this->getClassNameForPropertyName($name);
220
-            }
221
-        }
222
-        if (is_null($parameters)) {
223
-            $parameters = [];
224
-        }
211
+		if (is_null($class)) {
212
+			// If a VALUE parameter is supplied, we should use that.
213
+			if (isset($parameters['VALUE'])) {
214
+				$class = $this->getClassNameForPropertyValue($parameters['VALUE']);
215
+				if (is_null($class)) {
216
+					throw new InvalidDataException('Unsupported VALUE parameter for '.$name.' property. You supplied "'.$parameters['VALUE'].'"');
217
+				}
218
+			} else {
219
+				$class = $this->getClassNameForPropertyName($name);
220
+			}
221
+		}
222
+		if (is_null($parameters)) {
223
+			$parameters = [];
224
+		}
225 225
 
226
-        return new $class($this, $name, $value, $parameters, $group);
227
-    }
226
+		return new $class($this, $name, $value, $parameters, $group);
227
+	}
228 228
 
229
-    /**
230
-     * This method returns a full class-name for a value parameter.
231
-     *
232
-     * For instance, DTSTART may have VALUE=DATE. In that case we will look in
233
-     * our valueMap table and return the appropriate class name.
234
-     *
235
-     * This method returns null if we don't have a specialized class.
236
-     *
237
-     * @param string $valueParam
238
-     *
239
-     * @return string|null
240
-     */
241
-    public function getClassNameForPropertyValue($valueParam)
242
-    {
243
-        $valueParam = strtoupper($valueParam);
244
-        if (isset(static::$valueMap[$valueParam])) {
245
-            return static::$valueMap[$valueParam];
246
-        }
247
-    }
229
+	/**
230
+	 * This method returns a full class-name for a value parameter.
231
+	 *
232
+	 * For instance, DTSTART may have VALUE=DATE. In that case we will look in
233
+	 * our valueMap table and return the appropriate class name.
234
+	 *
235
+	 * This method returns null if we don't have a specialized class.
236
+	 *
237
+	 * @param string $valueParam
238
+	 *
239
+	 * @return string|null
240
+	 */
241
+	public function getClassNameForPropertyValue($valueParam)
242
+	{
243
+		$valueParam = strtoupper($valueParam);
244
+		if (isset(static::$valueMap[$valueParam])) {
245
+			return static::$valueMap[$valueParam];
246
+		}
247
+	}
248 248
 
249
-    /**
250
-     * Returns the default class for a property name.
251
-     *
252
-     * @param string $propertyName
253
-     *
254
-     * @return string
255
-     */
256
-    public function getClassNameForPropertyName($propertyName)
257
-    {
258
-        if (isset(static::$propertyMap[$propertyName])) {
259
-            return static::$propertyMap[$propertyName];
260
-        } else {
261
-            return Property\Unknown::class;
262
-        }
263
-    }
249
+	/**
250
+	 * Returns the default class for a property name.
251
+	 *
252
+	 * @param string $propertyName
253
+	 *
254
+	 * @return string
255
+	 */
256
+	public function getClassNameForPropertyName($propertyName)
257
+	{
258
+		if (isset(static::$propertyMap[$propertyName])) {
259
+			return static::$propertyMap[$propertyName];
260
+		} else {
261
+			return Property\Unknown::class;
262
+		}
263
+	}
264 264
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/vobject/lib/FreeBusyGenerator.php 1 patch
Indentation   +521 added lines, -521 removed lines patch added patch discarded remove patch
@@ -25,525 +25,525 @@
 block discarded – undo
25 25
  */
26 26
 class FreeBusyGenerator
27 27
 {
28
-    /**
29
-     * Input objects.
30
-     *
31
-     * @var array
32
-     */
33
-    protected $objects = [];
34
-
35
-    /**
36
-     * Start of range.
37
-     *
38
-     * @var DateTimeInterface|null
39
-     */
40
-    protected $start;
41
-
42
-    /**
43
-     * End of range.
44
-     *
45
-     * @var DateTimeInterface|null
46
-     */
47
-    protected $end;
48
-
49
-    /**
50
-     * VCALENDAR object.
51
-     *
52
-     * @var Document
53
-     */
54
-    protected $baseObject;
55
-
56
-    /**
57
-     * Reference timezone.
58
-     *
59
-     * When we are calculating busy times, and we come across so-called
60
-     * floating times (times without a timezone), we use the reference timezone
61
-     * instead.
62
-     *
63
-     * This is also used for all-day events.
64
-     *
65
-     * This defaults to UTC.
66
-     *
67
-     * @var DateTimeZone
68
-     */
69
-    protected $timeZone;
70
-
71
-    /**
72
-     * A VAVAILABILITY document.
73
-     *
74
-     * If this is set, its information will be included when calculating
75
-     * freebusy time.
76
-     *
77
-     * @var Document
78
-     */
79
-    protected $vavailability;
80
-
81
-    /**
82
-     * Creates the generator.
83
-     *
84
-     * Check the setTimeRange and setObjects methods for details about the
85
-     * arguments.
86
-     *
87
-     * @param DateTimeInterface $start
88
-     * @param DateTimeInterface $end
89
-     * @param mixed             $objects
90
-     * @param DateTimeZone      $timeZone
91
-     */
92
-    public function __construct(DateTimeInterface $start = null, DateTimeInterface $end = null, $objects = null, DateTimeZone $timeZone = null)
93
-    {
94
-        $this->setTimeRange($start, $end);
95
-
96
-        if ($objects) {
97
-            $this->setObjects($objects);
98
-        }
99
-        if (is_null($timeZone)) {
100
-            $timeZone = new DateTimeZone('UTC');
101
-        }
102
-        $this->setTimeZone($timeZone);
103
-    }
104
-
105
-    /**
106
-     * Sets the VCALENDAR object.
107
-     *
108
-     * If this is set, it will not be generated for you. You are responsible
109
-     * for setting things like the METHOD, CALSCALE, VERSION, etc..
110
-     *
111
-     * The VFREEBUSY object will be automatically added though.
112
-     */
113
-    public function setBaseObject(Document $vcalendar)
114
-    {
115
-        $this->baseObject = $vcalendar;
116
-    }
117
-
118
-    /**
119
-     * Sets a VAVAILABILITY document.
120
-     */
121
-    public function setVAvailability(Document $vcalendar)
122
-    {
123
-        $this->vavailability = $vcalendar;
124
-    }
125
-
126
-    /**
127
-     * Sets the input objects.
128
-     *
129
-     * You must either specify a vcalendar object as a string, or as the parse
130
-     * Component.
131
-     * It's also possible to specify multiple objects as an array.
132
-     *
133
-     * @param mixed $objects
134
-     */
135
-    public function setObjects($objects)
136
-    {
137
-        if (!is_array($objects)) {
138
-            $objects = [$objects];
139
-        }
140
-
141
-        $this->objects = [];
142
-        foreach ($objects as $object) {
143
-            if (is_string($object) || is_resource($object)) {
144
-                $this->objects[] = Reader::read($object);
145
-            } elseif ($object instanceof Component) {
146
-                $this->objects[] = $object;
147
-            } else {
148
-                throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component arguments to setObjects');
149
-            }
150
-        }
151
-    }
152
-
153
-    /**
154
-     * Sets the time range.
155
-     *
156
-     * Any freebusy object falling outside of this time range will be ignored.
157
-     *
158
-     * @param DateTimeInterface $start
159
-     * @param DateTimeInterface $end
160
-     */
161
-    public function setTimeRange(DateTimeInterface $start = null, DateTimeInterface $end = null)
162
-    {
163
-        if (!$start) {
164
-            $start = new DateTimeImmutable(Settings::$minDate);
165
-        }
166
-        if (!$end) {
167
-            $end = new DateTimeImmutable(Settings::$maxDate);
168
-        }
169
-        $this->start = $start;
170
-        $this->end = $end;
171
-    }
172
-
173
-    /**
174
-     * Sets the reference timezone for floating times.
175
-     */
176
-    public function setTimeZone(DateTimeZone $timeZone)
177
-    {
178
-        $this->timeZone = $timeZone;
179
-    }
180
-
181
-    /**
182
-     * Parses the input data and returns a correct VFREEBUSY object, wrapped in
183
-     * a VCALENDAR.
184
-     *
185
-     * @return Component
186
-     */
187
-    public function getResult()
188
-    {
189
-        $fbData = new FreeBusyData(
190
-            $this->start->getTimeStamp(),
191
-            $this->end->getTimeStamp()
192
-        );
193
-        if ($this->vavailability) {
194
-            $this->calculateAvailability($fbData, $this->vavailability);
195
-        }
196
-
197
-        $this->calculateBusy($fbData, $this->objects);
198
-
199
-        return $this->generateFreeBusyCalendar($fbData);
200
-    }
201
-
202
-    /**
203
-     * This method takes a VAVAILABILITY component and figures out all the
204
-     * available times.
205
-     */
206
-    protected function calculateAvailability(FreeBusyData $fbData, VCalendar $vavailability)
207
-    {
208
-        $vavailComps = iterator_to_array($vavailability->VAVAILABILITY);
209
-        usort(
210
-            $vavailComps,
211
-            function ($a, $b) {
212
-                // We need to order the components by priority. Priority 1
213
-                // comes first, up until priority 9. Priority 0 comes after
214
-                // priority 9. No priority implies priority 0.
215
-                //
216
-                // Yes, I'm serious.
217
-                $priorityA = isset($a->PRIORITY) ? (int) $a->PRIORITY->getValue() : 0;
218
-                $priorityB = isset($b->PRIORITY) ? (int) $b->PRIORITY->getValue() : 0;
219
-
220
-                if (0 === $priorityA) {
221
-                    $priorityA = 10;
222
-                }
223
-                if (0 === $priorityB) {
224
-                    $priorityB = 10;
225
-                }
226
-
227
-                return $priorityA - $priorityB;
228
-            }
229
-        );
230
-
231
-        // Now we go over all the VAVAILABILITY components and figure if
232
-        // there's any we don't need to consider.
233
-        //
234
-        // This is can be because of one of two reasons: either the
235
-        // VAVAILABILITY component falls outside the time we are interested in,
236
-        // or a different VAVAILABILITY component with a higher priority has
237
-        // already completely covered the time-range.
238
-        $old = $vavailComps;
239
-        $new = [];
240
-
241
-        foreach ($old as $vavail) {
242
-            list($compStart, $compEnd) = $vavail->getEffectiveStartEnd();
243
-
244
-            // We don't care about datetimes that are earlier or later than the
245
-            // start and end of the freebusy report, so this gets normalized
246
-            // first.
247
-            if (is_null($compStart) || $compStart < $this->start) {
248
-                $compStart = $this->start;
249
-            }
250
-            if (is_null($compEnd) || $compEnd > $this->end) {
251
-                $compEnd = $this->end;
252
-            }
253
-
254
-            // If the item fell out of the timerange, we can just skip it.
255
-            if ($compStart > $this->end || $compEnd < $this->start) {
256
-                continue;
257
-            }
258
-
259
-            // Going through our existing list of components to see if there's
260
-            // a higher priority component that already fully covers this one.
261
-            foreach ($new as $higherVavail) {
262
-                list($higherStart, $higherEnd) = $higherVavail->getEffectiveStartEnd();
263
-                if (
264
-                    (is_null($higherStart) || $higherStart < $compStart) &&
265
-                    (is_null($higherEnd) || $higherEnd > $compEnd)
266
-                ) {
267
-                    // Component is fully covered by a higher priority
268
-                    // component. We can skip this component.
269
-                    continue 2;
270
-                }
271
-            }
272
-
273
-            // We're keeping it!
274
-            $new[] = $vavail;
275
-        }
276
-
277
-        // Lastly, we need to traverse the remaining components and fill in the
278
-        // freebusydata slots.
279
-        //
280
-        // We traverse the components in reverse, because we want the higher
281
-        // priority components to override the lower ones.
282
-        foreach (array_reverse($new) as $vavail) {
283
-            $busyType = isset($vavail->BUSYTYPE) ? strtoupper($vavail->BUSYTYPE) : 'BUSY-UNAVAILABLE';
284
-            list($vavailStart, $vavailEnd) = $vavail->getEffectiveStartEnd();
285
-
286
-            // Making the component size no larger than the requested free-busy
287
-            // report range.
288
-            if (!$vavailStart || $vavailStart < $this->start) {
289
-                $vavailStart = $this->start;
290
-            }
291
-            if (!$vavailEnd || $vavailEnd > $this->end) {
292
-                $vavailEnd = $this->end;
293
-            }
294
-
295
-            // Marking the entire time range of the VAVAILABILITY component as
296
-            // busy.
297
-            $fbData->add(
298
-                $vavailStart->getTimeStamp(),
299
-                $vavailEnd->getTimeStamp(),
300
-                $busyType
301
-            );
302
-
303
-            // Looping over the AVAILABLE components.
304
-            if (isset($vavail->AVAILABLE)) {
305
-                foreach ($vavail->AVAILABLE as $available) {
306
-                    list($availStart, $availEnd) = $available->getEffectiveStartEnd();
307
-                    $fbData->add(
308
-                    $availStart->getTimeStamp(),
309
-                    $availEnd->getTimeStamp(),
310
-                    'FREE'
311
-                );
312
-
313
-                    if ($available->RRULE) {
314
-                        // Our favourite thing: recurrence!!
315
-
316
-                        $rruleIterator = new Recur\RRuleIterator(
317
-                        $available->RRULE->getValue(),
318
-                        $availStart
319
-                    );
320
-                        $rruleIterator->fastForward($vavailStart);
321
-
322
-                        $startEndDiff = $availStart->diff($availEnd);
323
-
324
-                        while ($rruleIterator->valid()) {
325
-                            $recurStart = $rruleIterator->current();
326
-                            $recurEnd = $recurStart->add($startEndDiff);
327
-
328
-                            if ($recurStart > $vavailEnd) {
329
-                                // We're beyond the legal timerange.
330
-                                break;
331
-                            }
332
-
333
-                            if ($recurEnd > $vavailEnd) {
334
-                                // Truncating the end if it exceeds the
335
-                                // VAVAILABILITY end.
336
-                                $recurEnd = $vavailEnd;
337
-                            }
338
-
339
-                            $fbData->add(
340
-                            $recurStart->getTimeStamp(),
341
-                            $recurEnd->getTimeStamp(),
342
-                            'FREE'
343
-                        );
344
-
345
-                            $rruleIterator->next();
346
-                        }
347
-                    }
348
-                }
349
-            }
350
-        }
351
-    }
352
-
353
-    /**
354
-     * This method takes an array of iCalendar objects and applies its busy
355
-     * times on fbData.
356
-     *
357
-     * @param VCalendar[] $objects
358
-     */
359
-    protected function calculateBusy(FreeBusyData $fbData, array $objects)
360
-    {
361
-        foreach ($objects as $key => $object) {
362
-            foreach ($object->getBaseComponents() as $component) {
363
-                switch ($component->name) {
364
-                    case 'VEVENT':
365
-                        $FBTYPE = 'BUSY';
366
-                        if (isset($component->TRANSP) && ('TRANSPARENT' === strtoupper($component->TRANSP))) {
367
-                            break;
368
-                        }
369
-                        if (isset($component->STATUS)) {
370
-                            $status = strtoupper($component->STATUS);
371
-                            if ('CANCELLED' === $status) {
372
-                                break;
373
-                            }
374
-                            if ('TENTATIVE' === $status) {
375
-                                $FBTYPE = 'BUSY-TENTATIVE';
376
-                            }
377
-                        }
378
-
379
-                        $times = [];
380
-
381
-                        if ($component->RRULE) {
382
-                            try {
383
-                                $iterator = new EventIterator($object, (string) $component->UID, $this->timeZone);
384
-                            } catch (NoInstancesException $e) {
385
-                                // This event is recurring, but it doesn't have a single
386
-                                // instance. We are skipping this event from the output
387
-                                // entirely.
388
-                                unset($this->objects[$key]);
389
-                                break;
390
-                            }
391
-
392
-                            if ($this->start) {
393
-                                $iterator->fastForward($this->start);
394
-                            }
395
-
396
-                            $maxRecurrences = Settings::$maxRecurrences;
397
-
398
-                            while ($iterator->valid() && --$maxRecurrences) {
399
-                                $startTime = $iterator->getDTStart();
400
-                                if ($this->end && $startTime > $this->end) {
401
-                                    break;
402
-                                }
403
-                                $times[] = [
404
-                                    $iterator->getDTStart(),
405
-                                    $iterator->getDTEnd(),
406
-                                ];
407
-
408
-                                $iterator->next();
409
-                            }
410
-                        } else {
411
-                            $startTime = $component->DTSTART->getDateTime($this->timeZone);
412
-                            if ($this->end && $startTime > $this->end) {
413
-                                break;
414
-                            }
415
-                            $endTime = null;
416
-                            if (isset($component->DTEND)) {
417
-                                $endTime = $component->DTEND->getDateTime($this->timeZone);
418
-                            } elseif (isset($component->DURATION)) {
419
-                                $duration = DateTimeParser::parseDuration((string) $component->DURATION);
420
-                                $endTime = clone $startTime;
421
-                                $endTime = $endTime->add($duration);
422
-                            } elseif (!$component->DTSTART->hasTime()) {
423
-                                $endTime = clone $startTime;
424
-                                $endTime = $endTime->modify('+1 day');
425
-                            } else {
426
-                                // The event had no duration (0 seconds)
427
-                                break;
428
-                            }
429
-
430
-                            $times[] = [$startTime, $endTime];
431
-                        }
432
-
433
-                        foreach ($times as $time) {
434
-                            if ($this->end && $time[0] > $this->end) {
435
-                                break;
436
-                            }
437
-                            if ($this->start && $time[1] < $this->start) {
438
-                                break;
439
-                            }
440
-
441
-                            $fbData->add(
442
-                                $time[0]->getTimeStamp(),
443
-                                $time[1]->getTimeStamp(),
444
-                                $FBTYPE
445
-                            );
446
-                        }
447
-                        break;
448
-
449
-                    case 'VFREEBUSY':
450
-                        foreach ($component->FREEBUSY as $freebusy) {
451
-                            $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY';
452
-
453
-                            // Skipping intervals marked as 'free'
454
-                            if ('FREE' === $fbType) {
455
-                                continue;
456
-                            }
457
-
458
-                            $values = explode(',', $freebusy);
459
-                            foreach ($values as $value) {
460
-                                list($startTime, $endTime) = explode('/', $value);
461
-                                $startTime = DateTimeParser::parseDateTime($startTime);
462
-
463
-                                if ('P' === substr($endTime, 0, 1) || '-P' === substr($endTime, 0, 2)) {
464
-                                    $duration = DateTimeParser::parseDuration($endTime);
465
-                                    $endTime = clone $startTime;
466
-                                    $endTime = $endTime->add($duration);
467
-                                } else {
468
-                                    $endTime = DateTimeParser::parseDateTime($endTime);
469
-                                }
470
-
471
-                                if ($this->start && $this->start > $endTime) {
472
-                                    continue;
473
-                                }
474
-                                if ($this->end && $this->end < $startTime) {
475
-                                    continue;
476
-                                }
477
-                                $fbData->add(
478
-                                    $startTime->getTimeStamp(),
479
-                                    $endTime->getTimeStamp(),
480
-                                    $fbType
481
-                                );
482
-                            }
483
-                        }
484
-                        break;
485
-                }
486
-            }
487
-        }
488
-    }
489
-
490
-    /**
491
-     * This method takes a FreeBusyData object and generates the VCALENDAR
492
-     * object associated with it.
493
-     *
494
-     * @return VCalendar
495
-     */
496
-    protected function generateFreeBusyCalendar(FreeBusyData $fbData)
497
-    {
498
-        if ($this->baseObject) {
499
-            $calendar = $this->baseObject;
500
-        } else {
501
-            $calendar = new VCalendar();
502
-        }
503
-
504
-        $vfreebusy = $calendar->createComponent('VFREEBUSY');
505
-        $calendar->add($vfreebusy);
506
-
507
-        if ($this->start) {
508
-            $dtstart = $calendar->createProperty('DTSTART');
509
-            $dtstart->setDateTime($this->start);
510
-            $vfreebusy->add($dtstart);
511
-        }
512
-        if ($this->end) {
513
-            $dtend = $calendar->createProperty('DTEND');
514
-            $dtend->setDateTime($this->end);
515
-            $vfreebusy->add($dtend);
516
-        }
517
-
518
-        $tz = new \DateTimeZone('UTC');
519
-        $dtstamp = $calendar->createProperty('DTSTAMP');
520
-        $dtstamp->setDateTime(new DateTimeImmutable('now', $tz));
521
-        $vfreebusy->add($dtstamp);
522
-
523
-        foreach ($fbData->getData() as $busyTime) {
524
-            $busyType = strtoupper($busyTime['type']);
525
-
526
-            // Ignoring all the FREE parts, because those are already assumed.
527
-            if ('FREE' === $busyType) {
528
-                continue;
529
-            }
530
-
531
-            $busyTime[0] = new \DateTimeImmutable('@'.$busyTime['start'], $tz);
532
-            $busyTime[1] = new \DateTimeImmutable('@'.$busyTime['end'], $tz);
533
-
534
-            $prop = $calendar->createProperty(
535
-                'FREEBUSY',
536
-                $busyTime[0]->format('Ymd\\THis\\Z').'/'.$busyTime[1]->format('Ymd\\THis\\Z')
537
-            );
538
-
539
-            // Only setting FBTYPE if it's not BUSY, because BUSY is the
540
-            // default anyway.
541
-            if ('BUSY' !== $busyType) {
542
-                $prop['FBTYPE'] = $busyType;
543
-            }
544
-            $vfreebusy->add($prop);
545
-        }
546
-
547
-        return $calendar;
548
-    }
28
+	/**
29
+	 * Input objects.
30
+	 *
31
+	 * @var array
32
+	 */
33
+	protected $objects = [];
34
+
35
+	/**
36
+	 * Start of range.
37
+	 *
38
+	 * @var DateTimeInterface|null
39
+	 */
40
+	protected $start;
41
+
42
+	/**
43
+	 * End of range.
44
+	 *
45
+	 * @var DateTimeInterface|null
46
+	 */
47
+	protected $end;
48
+
49
+	/**
50
+	 * VCALENDAR object.
51
+	 *
52
+	 * @var Document
53
+	 */
54
+	protected $baseObject;
55
+
56
+	/**
57
+	 * Reference timezone.
58
+	 *
59
+	 * When we are calculating busy times, and we come across so-called
60
+	 * floating times (times without a timezone), we use the reference timezone
61
+	 * instead.
62
+	 *
63
+	 * This is also used for all-day events.
64
+	 *
65
+	 * This defaults to UTC.
66
+	 *
67
+	 * @var DateTimeZone
68
+	 */
69
+	protected $timeZone;
70
+
71
+	/**
72
+	 * A VAVAILABILITY document.
73
+	 *
74
+	 * If this is set, its information will be included when calculating
75
+	 * freebusy time.
76
+	 *
77
+	 * @var Document
78
+	 */
79
+	protected $vavailability;
80
+
81
+	/**
82
+	 * Creates the generator.
83
+	 *
84
+	 * Check the setTimeRange and setObjects methods for details about the
85
+	 * arguments.
86
+	 *
87
+	 * @param DateTimeInterface $start
88
+	 * @param DateTimeInterface $end
89
+	 * @param mixed             $objects
90
+	 * @param DateTimeZone      $timeZone
91
+	 */
92
+	public function __construct(DateTimeInterface $start = null, DateTimeInterface $end = null, $objects = null, DateTimeZone $timeZone = null)
93
+	{
94
+		$this->setTimeRange($start, $end);
95
+
96
+		if ($objects) {
97
+			$this->setObjects($objects);
98
+		}
99
+		if (is_null($timeZone)) {
100
+			$timeZone = new DateTimeZone('UTC');
101
+		}
102
+		$this->setTimeZone($timeZone);
103
+	}
104
+
105
+	/**
106
+	 * Sets the VCALENDAR object.
107
+	 *
108
+	 * If this is set, it will not be generated for you. You are responsible
109
+	 * for setting things like the METHOD, CALSCALE, VERSION, etc..
110
+	 *
111
+	 * The VFREEBUSY object will be automatically added though.
112
+	 */
113
+	public function setBaseObject(Document $vcalendar)
114
+	{
115
+		$this->baseObject = $vcalendar;
116
+	}
117
+
118
+	/**
119
+	 * Sets a VAVAILABILITY document.
120
+	 */
121
+	public function setVAvailability(Document $vcalendar)
122
+	{
123
+		$this->vavailability = $vcalendar;
124
+	}
125
+
126
+	/**
127
+	 * Sets the input objects.
128
+	 *
129
+	 * You must either specify a vcalendar object as a string, or as the parse
130
+	 * Component.
131
+	 * It's also possible to specify multiple objects as an array.
132
+	 *
133
+	 * @param mixed $objects
134
+	 */
135
+	public function setObjects($objects)
136
+	{
137
+		if (!is_array($objects)) {
138
+			$objects = [$objects];
139
+		}
140
+
141
+		$this->objects = [];
142
+		foreach ($objects as $object) {
143
+			if (is_string($object) || is_resource($object)) {
144
+				$this->objects[] = Reader::read($object);
145
+			} elseif ($object instanceof Component) {
146
+				$this->objects[] = $object;
147
+			} else {
148
+				throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component arguments to setObjects');
149
+			}
150
+		}
151
+	}
152
+
153
+	/**
154
+	 * Sets the time range.
155
+	 *
156
+	 * Any freebusy object falling outside of this time range will be ignored.
157
+	 *
158
+	 * @param DateTimeInterface $start
159
+	 * @param DateTimeInterface $end
160
+	 */
161
+	public function setTimeRange(DateTimeInterface $start = null, DateTimeInterface $end = null)
162
+	{
163
+		if (!$start) {
164
+			$start = new DateTimeImmutable(Settings::$minDate);
165
+		}
166
+		if (!$end) {
167
+			$end = new DateTimeImmutable(Settings::$maxDate);
168
+		}
169
+		$this->start = $start;
170
+		$this->end = $end;
171
+	}
172
+
173
+	/**
174
+	 * Sets the reference timezone for floating times.
175
+	 */
176
+	public function setTimeZone(DateTimeZone $timeZone)
177
+	{
178
+		$this->timeZone = $timeZone;
179
+	}
180
+
181
+	/**
182
+	 * Parses the input data and returns a correct VFREEBUSY object, wrapped in
183
+	 * a VCALENDAR.
184
+	 *
185
+	 * @return Component
186
+	 */
187
+	public function getResult()
188
+	{
189
+		$fbData = new FreeBusyData(
190
+			$this->start->getTimeStamp(),
191
+			$this->end->getTimeStamp()
192
+		);
193
+		if ($this->vavailability) {
194
+			$this->calculateAvailability($fbData, $this->vavailability);
195
+		}
196
+
197
+		$this->calculateBusy($fbData, $this->objects);
198
+
199
+		return $this->generateFreeBusyCalendar($fbData);
200
+	}
201
+
202
+	/**
203
+	 * This method takes a VAVAILABILITY component and figures out all the
204
+	 * available times.
205
+	 */
206
+	protected function calculateAvailability(FreeBusyData $fbData, VCalendar $vavailability)
207
+	{
208
+		$vavailComps = iterator_to_array($vavailability->VAVAILABILITY);
209
+		usort(
210
+			$vavailComps,
211
+			function ($a, $b) {
212
+				// We need to order the components by priority. Priority 1
213
+				// comes first, up until priority 9. Priority 0 comes after
214
+				// priority 9. No priority implies priority 0.
215
+				//
216
+				// Yes, I'm serious.
217
+				$priorityA = isset($a->PRIORITY) ? (int) $a->PRIORITY->getValue() : 0;
218
+				$priorityB = isset($b->PRIORITY) ? (int) $b->PRIORITY->getValue() : 0;
219
+
220
+				if (0 === $priorityA) {
221
+					$priorityA = 10;
222
+				}
223
+				if (0 === $priorityB) {
224
+					$priorityB = 10;
225
+				}
226
+
227
+				return $priorityA - $priorityB;
228
+			}
229
+		);
230
+
231
+		// Now we go over all the VAVAILABILITY components and figure if
232
+		// there's any we don't need to consider.
233
+		//
234
+		// This is can be because of one of two reasons: either the
235
+		// VAVAILABILITY component falls outside the time we are interested in,
236
+		// or a different VAVAILABILITY component with a higher priority has
237
+		// already completely covered the time-range.
238
+		$old = $vavailComps;
239
+		$new = [];
240
+
241
+		foreach ($old as $vavail) {
242
+			list($compStart, $compEnd) = $vavail->getEffectiveStartEnd();
243
+
244
+			// We don't care about datetimes that are earlier or later than the
245
+			// start and end of the freebusy report, so this gets normalized
246
+			// first.
247
+			if (is_null($compStart) || $compStart < $this->start) {
248
+				$compStart = $this->start;
249
+			}
250
+			if (is_null($compEnd) || $compEnd > $this->end) {
251
+				$compEnd = $this->end;
252
+			}
253
+
254
+			// If the item fell out of the timerange, we can just skip it.
255
+			if ($compStart > $this->end || $compEnd < $this->start) {
256
+				continue;
257
+			}
258
+
259
+			// Going through our existing list of components to see if there's
260
+			// a higher priority component that already fully covers this one.
261
+			foreach ($new as $higherVavail) {
262
+				list($higherStart, $higherEnd) = $higherVavail->getEffectiveStartEnd();
263
+				if (
264
+					(is_null($higherStart) || $higherStart < $compStart) &&
265
+					(is_null($higherEnd) || $higherEnd > $compEnd)
266
+				) {
267
+					// Component is fully covered by a higher priority
268
+					// component. We can skip this component.
269
+					continue 2;
270
+				}
271
+			}
272
+
273
+			// We're keeping it!
274
+			$new[] = $vavail;
275
+		}
276
+
277
+		// Lastly, we need to traverse the remaining components and fill in the
278
+		// freebusydata slots.
279
+		//
280
+		// We traverse the components in reverse, because we want the higher
281
+		// priority components to override the lower ones.
282
+		foreach (array_reverse($new) as $vavail) {
283
+			$busyType = isset($vavail->BUSYTYPE) ? strtoupper($vavail->BUSYTYPE) : 'BUSY-UNAVAILABLE';
284
+			list($vavailStart, $vavailEnd) = $vavail->getEffectiveStartEnd();
285
+
286
+			// Making the component size no larger than the requested free-busy
287
+			// report range.
288
+			if (!$vavailStart || $vavailStart < $this->start) {
289
+				$vavailStart = $this->start;
290
+			}
291
+			if (!$vavailEnd || $vavailEnd > $this->end) {
292
+				$vavailEnd = $this->end;
293
+			}
294
+
295
+			// Marking the entire time range of the VAVAILABILITY component as
296
+			// busy.
297
+			$fbData->add(
298
+				$vavailStart->getTimeStamp(),
299
+				$vavailEnd->getTimeStamp(),
300
+				$busyType
301
+			);
302
+
303
+			// Looping over the AVAILABLE components.
304
+			if (isset($vavail->AVAILABLE)) {
305
+				foreach ($vavail->AVAILABLE as $available) {
306
+					list($availStart, $availEnd) = $available->getEffectiveStartEnd();
307
+					$fbData->add(
308
+					$availStart->getTimeStamp(),
309
+					$availEnd->getTimeStamp(),
310
+					'FREE'
311
+				);
312
+
313
+					if ($available->RRULE) {
314
+						// Our favourite thing: recurrence!!
315
+
316
+						$rruleIterator = new Recur\RRuleIterator(
317
+						$available->RRULE->getValue(),
318
+						$availStart
319
+					);
320
+						$rruleIterator->fastForward($vavailStart);
321
+
322
+						$startEndDiff = $availStart->diff($availEnd);
323
+
324
+						while ($rruleIterator->valid()) {
325
+							$recurStart = $rruleIterator->current();
326
+							$recurEnd = $recurStart->add($startEndDiff);
327
+
328
+							if ($recurStart > $vavailEnd) {
329
+								// We're beyond the legal timerange.
330
+								break;
331
+							}
332
+
333
+							if ($recurEnd > $vavailEnd) {
334
+								// Truncating the end if it exceeds the
335
+								// VAVAILABILITY end.
336
+								$recurEnd = $vavailEnd;
337
+							}
338
+
339
+							$fbData->add(
340
+							$recurStart->getTimeStamp(),
341
+							$recurEnd->getTimeStamp(),
342
+							'FREE'
343
+						);
344
+
345
+							$rruleIterator->next();
346
+						}
347
+					}
348
+				}
349
+			}
350
+		}
351
+	}
352
+
353
+	/**
354
+	 * This method takes an array of iCalendar objects and applies its busy
355
+	 * times on fbData.
356
+	 *
357
+	 * @param VCalendar[] $objects
358
+	 */
359
+	protected function calculateBusy(FreeBusyData $fbData, array $objects)
360
+	{
361
+		foreach ($objects as $key => $object) {
362
+			foreach ($object->getBaseComponents() as $component) {
363
+				switch ($component->name) {
364
+					case 'VEVENT':
365
+						$FBTYPE = 'BUSY';
366
+						if (isset($component->TRANSP) && ('TRANSPARENT' === strtoupper($component->TRANSP))) {
367
+							break;
368
+						}
369
+						if (isset($component->STATUS)) {
370
+							$status = strtoupper($component->STATUS);
371
+							if ('CANCELLED' === $status) {
372
+								break;
373
+							}
374
+							if ('TENTATIVE' === $status) {
375
+								$FBTYPE = 'BUSY-TENTATIVE';
376
+							}
377
+						}
378
+
379
+						$times = [];
380
+
381
+						if ($component->RRULE) {
382
+							try {
383
+								$iterator = new EventIterator($object, (string) $component->UID, $this->timeZone);
384
+							} catch (NoInstancesException $e) {
385
+								// This event is recurring, but it doesn't have a single
386
+								// instance. We are skipping this event from the output
387
+								// entirely.
388
+								unset($this->objects[$key]);
389
+								break;
390
+							}
391
+
392
+							if ($this->start) {
393
+								$iterator->fastForward($this->start);
394
+							}
395
+
396
+							$maxRecurrences = Settings::$maxRecurrences;
397
+
398
+							while ($iterator->valid() && --$maxRecurrences) {
399
+								$startTime = $iterator->getDTStart();
400
+								if ($this->end && $startTime > $this->end) {
401
+									break;
402
+								}
403
+								$times[] = [
404
+									$iterator->getDTStart(),
405
+									$iterator->getDTEnd(),
406
+								];
407
+
408
+								$iterator->next();
409
+							}
410
+						} else {
411
+							$startTime = $component->DTSTART->getDateTime($this->timeZone);
412
+							if ($this->end && $startTime > $this->end) {
413
+								break;
414
+							}
415
+							$endTime = null;
416
+							if (isset($component->DTEND)) {
417
+								$endTime = $component->DTEND->getDateTime($this->timeZone);
418
+							} elseif (isset($component->DURATION)) {
419
+								$duration = DateTimeParser::parseDuration((string) $component->DURATION);
420
+								$endTime = clone $startTime;
421
+								$endTime = $endTime->add($duration);
422
+							} elseif (!$component->DTSTART->hasTime()) {
423
+								$endTime = clone $startTime;
424
+								$endTime = $endTime->modify('+1 day');
425
+							} else {
426
+								// The event had no duration (0 seconds)
427
+								break;
428
+							}
429
+
430
+							$times[] = [$startTime, $endTime];
431
+						}
432
+
433
+						foreach ($times as $time) {
434
+							if ($this->end && $time[0] > $this->end) {
435
+								break;
436
+							}
437
+							if ($this->start && $time[1] < $this->start) {
438
+								break;
439
+							}
440
+
441
+							$fbData->add(
442
+								$time[0]->getTimeStamp(),
443
+								$time[1]->getTimeStamp(),
444
+								$FBTYPE
445
+							);
446
+						}
447
+						break;
448
+
449
+					case 'VFREEBUSY':
450
+						foreach ($component->FREEBUSY as $freebusy) {
451
+							$fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY';
452
+
453
+							// Skipping intervals marked as 'free'
454
+							if ('FREE' === $fbType) {
455
+								continue;
456
+							}
457
+
458
+							$values = explode(',', $freebusy);
459
+							foreach ($values as $value) {
460
+								list($startTime, $endTime) = explode('/', $value);
461
+								$startTime = DateTimeParser::parseDateTime($startTime);
462
+
463
+								if ('P' === substr($endTime, 0, 1) || '-P' === substr($endTime, 0, 2)) {
464
+									$duration = DateTimeParser::parseDuration($endTime);
465
+									$endTime = clone $startTime;
466
+									$endTime = $endTime->add($duration);
467
+								} else {
468
+									$endTime = DateTimeParser::parseDateTime($endTime);
469
+								}
470
+
471
+								if ($this->start && $this->start > $endTime) {
472
+									continue;
473
+								}
474
+								if ($this->end && $this->end < $startTime) {
475
+									continue;
476
+								}
477
+								$fbData->add(
478
+									$startTime->getTimeStamp(),
479
+									$endTime->getTimeStamp(),
480
+									$fbType
481
+								);
482
+							}
483
+						}
484
+						break;
485
+				}
486
+			}
487
+		}
488
+	}
489
+
490
+	/**
491
+	 * This method takes a FreeBusyData object and generates the VCALENDAR
492
+	 * object associated with it.
493
+	 *
494
+	 * @return VCalendar
495
+	 */
496
+	protected function generateFreeBusyCalendar(FreeBusyData $fbData)
497
+	{
498
+		if ($this->baseObject) {
499
+			$calendar = $this->baseObject;
500
+		} else {
501
+			$calendar = new VCalendar();
502
+		}
503
+
504
+		$vfreebusy = $calendar->createComponent('VFREEBUSY');
505
+		$calendar->add($vfreebusy);
506
+
507
+		if ($this->start) {
508
+			$dtstart = $calendar->createProperty('DTSTART');
509
+			$dtstart->setDateTime($this->start);
510
+			$vfreebusy->add($dtstart);
511
+		}
512
+		if ($this->end) {
513
+			$dtend = $calendar->createProperty('DTEND');
514
+			$dtend->setDateTime($this->end);
515
+			$vfreebusy->add($dtend);
516
+		}
517
+
518
+		$tz = new \DateTimeZone('UTC');
519
+		$dtstamp = $calendar->createProperty('DTSTAMP');
520
+		$dtstamp->setDateTime(new DateTimeImmutable('now', $tz));
521
+		$vfreebusy->add($dtstamp);
522
+
523
+		foreach ($fbData->getData() as $busyTime) {
524
+			$busyType = strtoupper($busyTime['type']);
525
+
526
+			// Ignoring all the FREE parts, because those are already assumed.
527
+			if ('FREE' === $busyType) {
528
+				continue;
529
+			}
530
+
531
+			$busyTime[0] = new \DateTimeImmutable('@'.$busyTime['start'], $tz);
532
+			$busyTime[1] = new \DateTimeImmutable('@'.$busyTime['end'], $tz);
533
+
534
+			$prop = $calendar->createProperty(
535
+				'FREEBUSY',
536
+				$busyTime[0]->format('Ymd\\THis\\Z').'/'.$busyTime[1]->format('Ymd\\THis\\Z')
537
+			);
538
+
539
+			// Only setting FBTYPE if it's not BUSY, because BUSY is the
540
+			// default anyway.
541
+			if ('BUSY' !== $busyType) {
542
+				$prop['FBTYPE'] = $busyType;
543
+			}
544
+			$vfreebusy->add($prop);
545
+		}
546
+
547
+		return $calendar;
548
+	}
549 549
 }
Please login to merge, or discard this patch.