Test Failed
Push — master ( 94260c...b3ef6a )
by
unknown
13:39 queued 15s
created

GrommunioDavBackend::isGdavEnabled()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 10
rs 10
1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2016 - 2018 Kopano b.v.
5
 * SPDX-FileCopyrightText: Copyright 2020 - 2024 grommunio GmbH
6
 *
7
 * grommunio DAV backend class which handles grommunio related activities.
8
 */
9
10
namespace grommunio\DAV;
11
12
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
13
14
class GrommunioDavBackend {
15
	private $logger;
16
	protected $session;
17
	protected $stores;
18
	protected $user;
19
	protected $customprops;
20
	protected $syncstate;
21
22
	/**
23
	 * Constructor.
24
	 */
25
	public function __construct(GLogger $glogger) {
26
		$this->logger = $glogger;
27
		$this->syncstate = new GrommunioSyncState($glogger, SYNC_DB);
28
	}
29
30
	/**
31
	 * Connect to grommunio and create session.
32
	 *
33
	 * @param string $user
34
	 * @param string $pass
35
	 *
36
	 * @return bool
37
	 */
38
	public function Logon($user, $pass) {
39
		$this->logger->trace('%s / password', $user);
40
41
		$gDavVersion = 'grommunio-dav' . @constant('GDAV_VERSION');
42
		$userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'unknown';
43
		$this->session = mapi_logon_zarafa($user, $pass, MAPI_SERVER, null, null, 1, $gDavVersion, $userAgent);
44
		if (!$this->session) {
45
			$this->logger->info("Auth: ERROR - logon failed for user %s", $user);
46
47
			return false;
48
		}
49
50
		$this->user = $user;
51
		$this->logger->debug("Auth: OK - user %s - session %s", $this->user, $this->session);
52
53
		return $this->isGdavEnabled();
54
	}
55
56
	/**
57
	 * Returns the authenticated user.
58
	 *
59
	 * @return string
60
	 */
61
	public function GetUser() {
62
		$this->logger->trace($this->user);
63
64
		return $this->user;
65
	}
66
67
	/**
68
	 * Create a folder with MAPI class.
69
	 *
70
	 * @param mixed  $principalUri
71
	 * @param string $url
72
	 * @param string $class
73
	 * @param string $displayname
74
	 *
75
	 * @return string
76
	 */
77
	public function CreateFolder($principalUri, $url, $class, $displayname) {
78
		$props = mapi_getprops($this->GetStore($principalUri), [PR_IPM_SUBTREE_ENTRYID]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_IPM_SUBTREE_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
79
		$folder = mapi_msgstore_openentry($this->GetStore($principalUri), $props[PR_IPM_SUBTREE_ENTRYID]);
80
		$newfolder = mapi_folder_createfolder($folder, $url, $displayname);
0 ignored issues
show
Bug introduced by
The function mapi_folder_createfolder was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

80
		$newfolder = /** @scrutinizer ignore-call */ mapi_folder_createfolder($folder, $url, $displayname);
Loading history...
81
		mapi_setprops($newfolder, [PR_CONTAINER_CLASS => $class]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_CONTAINER_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
82
83
		return $url;
84
	}
85
86
	/**
87
	 * Delete a folder with MAPI class.
88
	 *
89
	 * @param mixed $id
90
	 *
91
	 * @return bool
92
	 */
93
	public function DeleteFolder($id) {
94
		$folder = $this->GetMapiFolder($id);
95
		if (!$folder) {
96
			return false;
97
		}
98
99
		$props = mapi_getprops($folder, [PR_ENTRYID, PR_PARENT_ENTRYID]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
100
		$parentfolder = mapi_msgstore_openentry($this->GetStoreById($id), $props[PR_PARENT_ENTRYID]);
101
		mapi_folder_deletefolder($parentfolder, $props[PR_ENTRYID]);
0 ignored issues
show
Bug introduced by
The function mapi_folder_deletefolder was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
		/** @scrutinizer ignore-call */ 
102
  mapi_folder_deletefolder($parentfolder, $props[PR_ENTRYID]);
Loading history...
102
103
		return true;
104
	}
105
106
	/**
107
	 * Returns a list of folders for a MAPI class.
108
	 *
109
	 * @param string $principalUri
110
	 * @param mixed  $classes
111
	 *
112
	 * @return array
113
	 */
114
	public function GetFolders($principalUri, $classes) {
115
		$this->logger->trace("principal '%s', classes '%s'", $principalUri, $classes);
116
		$folders = [];
117
118
		// TODO limit the output to subfolders of the principalUri?
119
120
		$store = $this->GetStore($principalUri);
121
		$storeprops = mapi_getprops($store, [PR_IPM_WASTEBASKET_ENTRYID]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_IPM_WASTEBASKET_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
122
		$rootfolder = mapi_msgstore_openentry($store);
123
		$hierarchy = mapi_folder_gethierarchytable($rootfolder, CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\MAPI_DEFERRED_ERRORS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\CONVENIENT_DEPTH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
124
		// TODO also filter hidden folders
125
		$restrictions = [];
126
		foreach ($classes as $class) {
127
			$restrictions[] = [RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => PR_CONTAINER_CLASS, VALUE => $class]];
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RELOP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\VALUE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\ULPROPTAG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RES_PROPERTY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_CONTAINER_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RELOP_EQ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
128
		}
129
		mapi_table_restrict($hierarchy, [RES_OR, $restrictions]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_OR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
130
131
		// TODO how to handle hierarchies?
132
		$rows = mapi_table_queryallrows($hierarchy, [PR_DISPLAY_NAME, PR_ENTRYID, PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, PR_FOLDER_TYPE, PR_LOCAL_COMMIT_TIME_MAX, PR_CONTAINER_CLASS, PR_COMMENT, PR_PARENT_ENTRYID]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_DISPLAY_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_PARENT_SOURCE_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_LOCAL_COMMIT_TIME_MAX was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_FOLDER_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_SOURCE_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_COMMENT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_PARENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
133
134
		$rootprops = mapi_getprops($rootfolder, [PR_IPM_CONTACT_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_IPM_CONTACT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_IPM_APPOINTMENT_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
135
		foreach ($rows as $row) {
136
			if ($row[PR_FOLDER_TYPE] == FOLDER_SEARCH) {
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\FOLDER_SEARCH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
137
				continue;
138
			}
139
140
			if (isset($row[PR_PARENT_ENTRYID], $storeprops[PR_IPM_WASTEBASKET_ENTRYID]) && $row[PR_PARENT_ENTRYID] == $storeprops[PR_IPM_WASTEBASKET_ENTRYID]) {
141
				continue;
142
			}
143
144
			$folder = [
145
				'id' => $principalUri . ":" . bin2hex($row[PR_SOURCE_KEY]),
146
				'uri' => $row[PR_DISPLAY_NAME],
147
				'principaluri' => $principalUri,
148
				'{http://sabredav.org/ns}sync-token' => '0000000000',
149
				'{DAV:}displayname' => $row[PR_DISPLAY_NAME],
150
				'{urn:ietf:params:xml:ns:caldav}calendar-description' => $row[PR_COMMENT],
151
				'{http://calendarserver.org/ns/}getctag' => isset($row[PR_LOCAL_COMMIT_TIME_MAX]) ? strval($row[PR_LOCAL_COMMIT_TIME_MAX]) : '0000000000',
152
			];
153
154
			// set the supported component (task or calendar)
155
			if ($row[PR_CONTAINER_CLASS] == "IPF.Task") {
156
				$folder['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'] = new SupportedCalendarComponentSet(['VTODO']);
157
			}
158
			if ($row[PR_CONTAINER_CLASS] == "IPF.Appointment") {
159
				$folder['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'] = new SupportedCalendarComponentSet(['VEVENT']);
160
			}
161
162
			// ensure default contacts folder is put first, some clients
163
			// i.e. Apple Addressbook only supports one contact folder,
164
			// therefore it is desired that folder is the default one.
165
			if (in_array("IPF.Contact", $classes) && isset($rootprops[PR_IPM_CONTACT_ENTRYID]) && $row[PR_ENTRYID] == $rootprops[PR_IPM_CONTACT_ENTRYID]) {
166
				array_unshift($folders, $folder);
167
			}
168
			// ensure default calendar folder is put first,
169
			// before the tasks folder.
170
			elseif (in_array('IPF.Appointment', $classes) && isset($rootprops[PR_IPM_APPOINTMENT_ENTRYID]) && $row[PR_ENTRYID] == $rootprops[PR_IPM_APPOINTMENT_ENTRYID]) {
171
				array_unshift($folders, $folder);
172
			}
173
			else {
174
				array_push($folders, $folder);
175
			}
176
		}
177
		$this->logger->trace('found %d folders: %s', count($folders), $folders);
178
179
		return $folders;
180
	}
181
182
	/**
183
	 * Returns a MAPI restriction for a defined set of filters.
184
	 *
185
	 * @param array  $filters
186
	 * @param string $storeId (optional) mapi compatible storeid - required when using start+end filter
187
	 *
188
	 * @return array|null
189
	 */
190
	private function getRestrictionForFilters($filters, $storeId = null) {
191
		$restrictions = [];
192
		if (isset($filters['start'], $filters['end'], $storeId)) {
193
			$this->logger->trace("getRestrictionForFilters - got start: %d and end: %d", $filters['start'], $filters['end']);
194
			$subrestriction = $this->GetCalendarRestriction($storeId, $filters['start'], $filters['end']);
195
			$restrictions[] = $subrestriction;
196
		}
197
		if (isset($filters['types'])) {
198
			$this->logger->trace("getRestrictionForFilters - got types: %s", $filters['types']);
199
			$arr = [];
200
			foreach ($filters['types'] as $filter) {
201
				$arr[] = [RES_PROPERTY,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_PROPERTY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
202
					[RELOP => RELOP_EQ,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RELOP_EQ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RELOP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
203
						ULPROPTAG => PR_MESSAGE_CLASS,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_MESSAGE_CLASS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\ULPROPTAG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
204
						VALUE => $filter,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\VALUE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
205
					],
206
				];
207
			}
208
			$restrictions[] = [RES_OR, $arr];
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_OR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
209
		}
210
		if (!empty($restrictions)) {
211
			$restriction = [RES_AND, $restrictions];
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_AND was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
212
			$this->logger->trace("getRestrictionForFilters - got restriction: %s", $restriction);
213
214
			return $restriction;
215
		}
216
217
		return null;
218
	}
219
220
	/**
221
	 * Returns a list of objects for a folder given by the id.
222
	 *
223
	 * @param string $id
224
	 * @param string $fileExtension
225
	 * @param array  $filters
226
	 *
227
	 * @return array
228
	 */
229
	public function GetObjects($id, $fileExtension, $filters = []) {
230
		$folder = $this->GetMapiFolder($id);
231
		$properties = $this->GetCustomProperties($id);
232
		$table = mapi_folder_getcontentstable($folder, MAPI_DEFERRED_ERRORS);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\MAPI_DEFERRED_ERRORS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
233
		$restriction = $this->getRestrictionForFilters($filters, $this->GetStoreById($id));
0 ignored issues
show
Bug introduced by
It seems like $this->GetStoreById($id) can also be of type false; however, parameter $storeId of grommunio\DAV\GrommunioD...RestrictionForFilters() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

233
		$restriction = $this->getRestrictionForFilters($filters, /** @scrutinizer ignore-type */ $this->GetStoreById($id));
Loading history...
234
		if ($restriction) {
235
			mapi_table_restrict($table, $restriction);
236
		}
237
238
		$rows = mapi_table_queryallrows($table, [PR_SOURCE_KEY, PR_LAST_MODIFICATION_TIME, PR_MESSAGE_SIZE, $properties['goid']]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_MESSAGE_SIZE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_LAST_MODIFICATION_TIME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_SOURCE_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
239
240
		$results = [];
241
		foreach ($rows as $row) {
242
			$realId = "";
243
			if (isset($row[$properties['goid']])) {
244
				$realId = getUidFromGoid($row[$properties['goid']]);
0 ignored issues
show
Bug introduced by
The function getUidFromGoid was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

244
				$realId = /** @scrutinizer ignore-call */ getUidFromGoid($row[$properties['goid']]);
Loading history...
245
			}
246
			if (!$realId) {
247
				$realId = bin2hex($row[PR_SOURCE_KEY]);
248
			}
249
250
			$result = [
251
				'id' => $realId,
252
				'uri' => $realId . $fileExtension,
253
				'etag' => '"' . $row[PR_LAST_MODIFICATION_TIME] . '"',
254
				'lastmodified' => $row[PR_LAST_MODIFICATION_TIME],
255
				'size' => $row[PR_MESSAGE_SIZE], // only approximation
256
			];
257
258
			if ($fileExtension == GrommunioCalDavBackend::FILE_EXTENSION) {
259
				$result['calendarid'] = $id;
260
			}
261
			elseif ($fileExtension == GrommunioCardDavBackend::FILE_EXTENSION) {
262
				$result['addressbookid'] = $id;
263
			}
264
			$results[] = $result;
265
		}
266
267
		return $results;
268
	}
269
270
	/**
271
	 * Create the object and set appttsref.
272
	 *
273
	 * @param mixed  $folderId
274
	 * @param mixed  $folder
275
	 * @param string $objectId
276
	 *
277
	 * @return mixed
278
	 */
279
	public function CreateObject($folderId, $folder, $objectId) {
280
		$mapimessage = mapi_folder_createmessage($folder);
281
		// we save the objectId in PROP_APPTTSREF so we find it by this id
282
		$properties = $this->GetCustomProperties($folderId);
283
		// FIXME: uid for contacts
284
		$goid = getGoidFromUid($objectId);
0 ignored issues
show
Bug introduced by
The function getGoidFromUid was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

284
		$goid = /** @scrutinizer ignore-call */ getGoidFromUid($objectId);
Loading history...
285
		mapi_setprops($mapimessage, [$properties['goid'] => $goid]);
286
287
		return $mapimessage;
288
	}
289
290
	/**
291
	 * Returns a mapi folder resource for a folderid (PR_SOURCE_KEY).
292
	 *
293
	 * @param string $folderid
294
	 *
295
	 * @return mixed
296
	 */
297
	public function GetMapiFolder($folderid) {
298
		$this->logger->trace('Id: %s', $folderid);
299
		$arr = explode(':', $folderid);
300
		$entryid = mapi_msgstore_entryidfromsourcekey($this->GetStore($arr[0]), hex2bin($arr[1]));
301
302
		return mapi_msgstore_openentry($this->GetStore($arr[0]), $entryid);
303
	}
304
305
	/**
306
	 * Returns MAPI addressbook.
307
	 *
308
	 * @return mixed
309
	 */
310
	public function GetAddressBook() {
311
		// TODO should be a singleton
312
		return mapi_openaddressbook($this->session);
313
	}
314
315
	/**
316
	 * Opens MAPI store for the user.
317
	 *
318
	 * @param string $username
319
	 *
320
	 * @return mixed
321
	 */
322
	public function OpenMapiStore($username = null) {
323
		$msgstorestable = mapi_getmsgstorestable($this->session);
324
		$msgstores = mapi_table_queryallrows($msgstorestable, [PR_DEFAULT_STORE, PR_ENTRYID, PR_MDB_PROVIDER]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_MDB_PROVIDER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_DEFAULT_STORE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
325
326
		$defaultstore = null;
327
		$publicstore = null;
328
		foreach ($msgstores as $row) {
329
			if (isset($row[PR_DEFAULT_STORE]) && $row[PR_DEFAULT_STORE]) {
330
				$defaultstore = $row[PR_ENTRYID];
331
			}
332
			if (isset($row[PR_MDB_PROVIDER]) && $row[PR_MDB_PROVIDER] == ZARAFA_STORE_PUBLIC_GUID) {
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\ZARAFA_STORE_PUBLIC_GUID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
333
				$publicstore = $row[PR_ENTRYID];
334
			}
335
		}
336
337
		/* user's own store or public store */
338
		if ($username == $this->GetUser() && $defaultstore != null) {
339
			return mapi_openmsgstore($this->session, $defaultstore);
340
		}
341
		if ($username == 'public' && $publicstore != null) {
342
			return mapi_openmsgstore($this->session, $publicstore);
343
		}
344
345
		/* otherwise other user's store */
346
		$store = mapi_openmsgstore($this->session, $defaultstore);
347
		if (!$store) {
348
			return false;
349
		}
350
		$otherstore = mapi_msgstore_createentryid($store, $username);
351
352
		return mapi_openmsgstore($this->session, $otherstore);
353
	}
354
355
	/**
356
	 * Returns store for the user.
357
	 *
358
	 * @param string $storename
359
	 *
360
	 * @return mixed
361
	 */
362
	public function GetStore($storename) {
363
		if ($storename == null) {
364
			$storename = $this->GetUser();
365
		}
366
		else {
367
			$storename = str_replace('principals/', '', $storename);
368
		}
369
		$this->logger->trace("storename %s", $storename);
370
371
		/* We already got the store */
372
		if (isset($this->stores[$storename]) && $this->stores[$storename] != null) {
373
			return $this->stores[$storename];
374
		}
375
376
		$this->stores[$storename] = $this->OpenMapiStore($storename);
377
		if (!$this->stores[$storename]) {
378
			$this->logger->info("Auth: ERROR - unable to open store for %s (0x%08X)", $storename, mapi_last_hresult());
379
380
			return false;
381
		}
382
383
		return $this->stores[$storename];
384
	}
385
386
	/**
387
	 * Returns store from the id.
388
	 *
389
	 * @param mixed $id
390
	 *
391
	 * @return mixed
392
	 */
393
	public function GetStoreById($id) {
394
		$arr = explode(':', $id);
395
396
		return $this->GetStore($arr[0]);
397
	}
398
399
	/**
400
	 * Returns logon session.
401
	 *
402
	 * @return mixed
403
	 */
404
	public function GetSession() {
405
		return $this->session;
406
	}
407
408
	/**
409
	 * Returns an object ID of a mapi object.
410
	 * If set, goid will be preferred. If not the PR_SOURCE_KEY of the message (as hex) will be returned.
411
	 *
412
	 * This order is reflected as well when searching for a message with these ids in GrommunioDavBackend->GetMapiMessageForId().
413
	 *
414
	 * @param string $folderId
415
	 * @param mixed  $mapimessage
416
	 *
417
	 * @return string
418
	 */
419
	public function GetIdOfMapiMessage($folderId, $mapimessage) {
420
		$this->logger->trace("Finding ID of %s", $mapimessage);
421
		$properties = $this->GetCustomProperties($folderId);
422
423
		// It's one of these, order:
424
		// - GOID (if set)
425
		// - PROP_VCARDUID (if set)
426
		// - PR_SOURCE_KEY
427
		$props = mapi_getprops($mapimessage, [$properties['goid'], PR_SOURCE_KEY]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_SOURCE_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
428
		if (isset($props[$properties['goid']])) {
429
			$id = getUidFromGoid($props[$properties['goid']]);
0 ignored issues
show
Bug introduced by
The function getUidFromGoid was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

429
			$id = /** @scrutinizer ignore-call */ getUidFromGoid($props[$properties['goid']]);
Loading history...
430
			$this->logger->debug("Found uid %s from goid: %s", $id, bin2hex($props[$properties['goid']]));
431
			if ($id != null) {
432
				return $id;
433
			}
434
		}
435
		// PR_SOURCE_KEY is always available
436
		$id = bin2hex($props[PR_SOURCE_KEY]);
437
		$this->logger->debug("Found PR_SOURCE_KEY: %s", $id);
438
439
		return $id;
440
	}
441
442
	/**
443
	 * Finds and opens a MapiMessage from an objectId.
444
	 * The id can be a PROP_APPTTSREF or a PR_SOURCE_KEY (as hex).
445
	 *
446
	 * @param string $folderId
447
	 * @param string $objectUri
448
	 * @param mixed  $mapifolder optional
449
	 * @param string $extension  optional
450
	 *
451
	 * @return mixed
452
	 */
453
	public function GetMapiMessageForId($folderId, $objectUri, $mapifolder = null, $extension = null) {
454
		$this->logger->trace("Searching for '%s' in '%s' (%s) (%s)", $objectUri, $folderId, $mapifolder, $extension);
455
456
		if (!$mapifolder) {
457
			$mapifolder = $this->GetMapiFolder($folderId);
458
		}
459
460
		$id = $this->GetObjectIdFromObjectUri($objectUri, $extension);
461
462
		/* The ID can be several different things:
463
		 * - a UID that is saved in goid
464
		 * - a PROP_VCARDUID
465
		 * - a PR_SOURCE_KEY
466
		 *
467
		 * If it's a sourcekey, we can open the message directly.
468
		 * If the $extension is set:
469
		 *      if it's ics:
470
		 *          - search GOID with this value
471
		 *      if it's vcf:
472
		 *          - search PROP_VCARDUID value
473
		 */
474
		$entryid = false;
475
		$restriction = false;
476
477
		if (ctype_xdigit($id) && strlen($id) % 2 == 0) {
478
			$this->logger->trace("Try PR_SOURCE_KEY %s", $id);
479
			$arr = explode(':', $folderId);
480
			$entryid = mapi_msgstore_entryidfromsourcekey($this->GetStoreById($arr[0]), hex2bin($arr[1]), hex2bin($id));
481
		}
482
483
		if (!$entryid) {
484
			$this->logger->trace("Entryid not found. Try goid/vcarduid %s", $id);
485
486
			$properties = $this->GetCustomProperties($folderId);
487
			if (strpos($id, '%40') !== false) {
488
				$this->logger->debug("The id contains '%40'. Use urldecode.");
489
				$id = urldecode($id);
490
			}
491
			$restriction = [];
492
493
			if ($extension) {
494
				if ($extension == GrommunioCalDavBackend::FILE_EXTENSION) {
495
					$this->logger->trace("Try goid %s", $id);
496
					$goid = getGoidFromUid($id);
0 ignored issues
show
Bug introduced by
The function getGoidFromUid was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

496
					$goid = /** @scrutinizer ignore-call */ getGoidFromUid($id);
Loading history...
497
					$this->logger->trace("Try goid 0x%08X => %s", $properties["goid"], bin2hex($goid));
498
					$goid0 = getGoidFromUidZero($id);
0 ignored issues
show
Bug introduced by
The function getGoidFromUidZero was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

498
					$goid0 = /** @scrutinizer ignore-call */ getGoidFromUidZero($id);
Loading history...
499
					$restriction[] = [RES_OR, [
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_OR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
500
						[RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $properties["goid"], VALUE => $goid]],
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\ULPROPTAG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\VALUE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RELOP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RES_PROPERTY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RELOP_EQ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
501
						[RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $properties["goid"], VALUE => $goid0]],
502
					]];
503
				}
504
				elseif ($extension == GrommunioCardDavBackend::FILE_EXTENSION) {
505
					$this->logger->trace("Try vcarduid %s", $id);
506
					$restriction[] = [RES_PROPERTY, [RELOP => RELOP_EQ, ULPROPTAG => $properties["vcarduid"], VALUE => $id]];
507
				}
508
			}
509
		}
510
511
		// find the message if we have a restriction
512
		if ($restriction) {
513
			$table = mapi_folder_getcontentstable($mapifolder, MAPI_DEFERRED_ERRORS);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\MAPI_DEFERRED_ERRORS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
514
			mapi_table_restrict($table, [RES_OR, $restriction]);
515
			// Get requested properties, plus whatever we need
516
			$proplist = [PR_ENTRYID];
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_ENTRYID was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
517
			$rows = mapi_table_queryallrows($table, $proplist);
518
			if (count($rows) > 1) {
519
				$this->logger->warn("Found %d entries for id '%s' searching for message, returnin first in the list", count($rows), $id);
520
			}
521
			if (isset($rows[0], $rows[0][PR_ENTRYID])) {
522
				$entryid = $rows[0][PR_ENTRYID];
523
			}
524
		}
525
		if (!$entryid) {
526
			$this->logger->debug("Try to get entryid from appttsref");
527
			$arr = explode(':', $folderId);
528
			$sk = $this->syncstate->getSourcekey($arr[1], $id);
529
			if ($sk !== null) {
530
				$this->logger->debug("Found sourcekey from appttsref %s", $sk);
531
				$entryid = mapi_msgstore_entryidfromsourcekey($this->GetStoreById($arr[0]), hex2bin($arr[1]), hex2bin($sk));
532
			}
533
		}
534
		if ($entryid) {
535
			$mapimessage = mapi_msgstore_openentry($this->GetStoreById($folderId), $entryid);
536
			if (!$mapimessage) {
537
				$this->logger->warn("Error, unable to open entry id: %s 0x%X", bin2hex($entryid), mapi_last_hresult());
538
539
				return null;
540
			}
541
542
			return $mapimessage;
543
		}
544
		$this->logger->debug("Nothing found for %s", $id);
545
546
		return null;
547
	}
548
549
	/**
550
	 * Returns the objectId from an objectUri. It strips the file extension
551
	 * if it matches the passed one.
552
	 *
553
	 * @param string $objectUri
554
	 * @param string $extension
555
	 *
556
	 * @return string
557
	 */
558
	public function GetObjectIdFromObjectUri($objectUri, $extension) {
559
		if (!$extension) {
560
			return $objectUri;
561
		}
562
		$extLength = strlen($extension);
563
		if (substr($objectUri, -$extLength) === $extension) {
564
			return substr($objectUri, 0, -$extLength);
565
		}
566
567
		return $objectUri;
568
	}
569
570
	/**
571
	 * Checks if the PHP-MAPI extension is available and in a requested version.
572
	 *
573
	 * @param string $version the version to be checked ("6.30.10-18495", parts or build number)
574
	 *
575
	 * @return bool installed version is superior to the checked string
576
	 */
577
	protected function checkMapiExtVersion($version = "") {
578
		if (!extension_loaded("mapi")) {
579
			return false;
580
		}
581
		// compare build number if requested
582
		if (preg_match('/^\d+$/', $version) && strlen($version) > 3) {
583
			$vs = preg_split('/-/', phpversion("mapi"));
584
585
			return $version <= $vs[1];
586
		}
587
		if (version_compare(phpversion("mapi"), $version) == -1) {
588
			return false;
589
		}
590
591
		return true;
592
	}
593
594
	/**
595
	 * Get named (custom) properties. Currently only PROP_APPTTSREF.
596
	 *
597
	 * @param string $id the folder id
598
	 *
599
	 * @return mixed
600
	 */
601
	protected function GetCustomProperties($id) {
602
		if (!isset($this->customprops[$id])) {
603
			$this->logger->trace("Fetching properties id:%s", $id);
604
			$store = $this->GetStoreById($id);
605
			$properties = getPropIdsFromStrings($store, [
0 ignored issues
show
Bug introduced by
The function getPropIdsFromStrings was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

605
			$properties = /** @scrutinizer ignore-call */ getPropIdsFromStrings($store, [
Loading history...
606
				"goid" => "PT_BINARY:PSETID_Meeting:" . PidLidGlobalObjectId,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PidLidGlobalObjectId was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
607
				"vcarduid" => MapiProps::PROP_VCARDUID,
608
			]);
609
			$this->customprops[$id] = $properties;
610
		}
611
612
		return $this->customprops[$id];
613
	}
614
615
	/**
616
	 * Create a MAPI restriction to use in the calendar which will
617
	 * return future calendar items (until $end), plus those since $start.
618
	 * Origins: Z-Push.
619
	 *
620
	 * @param mixed $store the MAPI store
621
	 * @param int   $start Timestamp since when to include messages
622
	 * @param int   $end   Ending timestamp
623
	 *
624
	 * @return array
625
	 */
626
	// TODO getting named properties
627
	public function GetCalendarRestriction($store, $start, $end) {
628
		$props = MapiProps::GetAppointmentProperties();
629
		$props = getPropIdsFromStrings($store, $props);
0 ignored issues
show
Bug introduced by
The function getPropIdsFromStrings was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

629
		$props = /** @scrutinizer ignore-call */ getPropIdsFromStrings($store, $props);
Loading history...
630
631
		return [RES_OR,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_OR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
632
			[
633
				// OR
634
				// item.end > window.start && item.start < window.end
635
				[RES_AND,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_AND was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
636
					[
637
						[RES_PROPERTY,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_PROPERTY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
638
							[RELOP => RELOP_LE,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RELOP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\RELOP_LE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
639
								ULPROPTAG => $props["starttime"],
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\ULPROPTAG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
640
								VALUE => $end,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\VALUE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
641
							],
642
						],
643
						[RES_PROPERTY,
644
							[RELOP => RELOP_GE,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RELOP_GE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
645
								ULPROPTAG => $props["endtime"],
646
								VALUE => $start,
647
							],
648
						],
649
					],
650
				],
651
				// OR
652
				[RES_OR,
653
					[
654
						// OR
655
						// (EXIST(recurrence_enddate_property) && item[isRecurring] == true && recurrence_enddate_property >= start)
656
						[RES_AND,
657
							[
658
								[RES_EXIST,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_EXIST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
659
									[ULPROPTAG => $props["recurrenceend"],
660
									],
661
								],
662
								[RES_PROPERTY,
663
									[RELOP => RELOP_EQ,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RELOP_EQ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
664
										ULPROPTAG => $props["isrecurring"],
665
										VALUE => true,
666
									],
667
								],
668
								[RES_PROPERTY,
669
									[RELOP => RELOP_GE,
670
										ULPROPTAG => $props["recurrenceend"],
671
										VALUE => $start,
672
									],
673
								],
674
							],
675
						],
676
						// OR
677
						// (!EXIST(recurrence_enddate_property) && item[isRecurring] == true && item[start] <= end)
678
						[RES_AND,
679
							[
680
								[RES_NOT,
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\RES_NOT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
681
									[
682
										[RES_EXIST,
683
											[ULPROPTAG => $props["recurrenceend"],
684
											],
685
										],
686
									],
687
								],
688
								[RES_PROPERTY,
689
									[RELOP => RELOP_LE,
690
										ULPROPTAG => $props["starttime"],
691
										VALUE => $end,
692
									],
693
								],
694
								[RES_PROPERTY,
695
									[RELOP => RELOP_EQ,
696
										ULPROPTAG => $props["isrecurring"],
697
										VALUE => true,
698
									],
699
								],
700
							],
701
						],
702
					],
703
				], // EXISTS OR
704
			],
705
		];        // global OR
706
	}
707
708
	/**
709
	 * Performs ICS based sync used from getChangesForAddressBook
710
	 * / getChangesForCalendar.
711
	 *
712
	 * @param string $folderId
713
	 * @param string $syncToken
714
	 * @param string $fileExtension
715
	 * @param int    $limit
716
	 * @param array  $filters
717
	 *
718
	 * @return array|null
719
	 */
720
	public function Sync($folderId, $syncToken, $fileExtension, $limit = null, $filters = []) {
721
		$arr = explode(':', $folderId);
722
		$phpwrapper = new PHPWrapper($this->GetStoreById($folderId), $this->logger, $this->GetCustomProperties($folderId), $fileExtension, $this->syncstate, $arr[1]);
723
		$mapiimporter = mapi_wrap_importcontentschanges($phpwrapper);
0 ignored issues
show
Bug introduced by
The function mapi_wrap_importcontentschanges was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

723
		$mapiimporter = /** @scrutinizer ignore-call */ mapi_wrap_importcontentschanges($phpwrapper);
Loading history...
724
725
		$mapifolder = $this->GetMapiFolder($folderId);
726
		$exporter = mapi_openproperty($mapifolder, PR_CONTENTS_SYNCHRONIZER, IID_IExchangeExportChanges, 0, 0);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\IID_IExchangeExportChanges was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\PR_CONTENTS_SYNCHRONIZER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
727
		if (!$exporter) {
728
			$this->logger->error("Unable to get exporter");
729
730
			return null;
731
		}
732
733
		$stream = mapi_stream_create();
0 ignored issues
show
Bug introduced by
The function mapi_stream_create was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

733
		$stream = /** @scrutinizer ignore-call */ mapi_stream_create();
Loading history...
734
		if ($syncToken == null) {
735
			mapi_stream_write($stream, hex2bin("0000000000000000"));
736
		}
737
		else {
738
			$value = $this->syncstate->getState($arr[1], $syncToken);
739
			if ($value === null) {
740
				$this->logger->error("Unable to get value from token: %s - folderId: %s", $syncToken, $folderId);
741
742
				return null;
743
			}
744
			mapi_stream_write($stream, hex2bin($value));
745
		}
746
747
		// force restriction of "types" to export only appointments or contacts
748
		$restriction = $this->getRestrictionForFilters($filters);
749
750
		// The last parameter in mapi_exportchanges_config is buffer size for mapi_exportchanges_synchronize - how many
751
		// changes will be processed in its call. Setting it to MAX_SYNC_ITEMS won't export more items than is set in
752
		// the config. If there are more changes than MAX_SYNC_ITEMS the client will eventually catch up and sync
753
		// the rest on the subsequent sync request(s).
754
		$bufferSize = ($limit !== null && $limit > 0) ? $limit : MAX_SYNC_ITEMS;
755
		mapi_exportchanges_config($exporter, $stream, SYNC_NORMAL | SYNC_UNICODE, $mapiimporter, $restriction, false, false, $bufferSize);
0 ignored issues
show
Bug introduced by
The function mapi_exportchanges_config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

755
		/** @scrutinizer ignore-call */ 
756
  mapi_exportchanges_config($exporter, $stream, SYNC_NORMAL | SYNC_UNICODE, $mapiimporter, $restriction, false, false, $bufferSize);
Loading history...
Bug introduced by
The constant grommunio\DAV\SYNC_UNICODE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant grommunio\DAV\SYNC_NORMAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
756
		$changesCount = mapi_exportchanges_getchangecount($exporter);
0 ignored issues
show
Bug introduced by
The function mapi_exportchanges_getchangecount was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

756
		$changesCount = /** @scrutinizer ignore-call */ mapi_exportchanges_getchangecount($exporter);
Loading history...
757
		$this->logger->debug("Exporter found %d changes, buffer size for mapi_exportchanges_synchronize %d", $changesCount, $bufferSize);
758
		while (is_array(mapi_exportchanges_synchronize($exporter))) {
0 ignored issues
show
Bug introduced by
The function mapi_exportchanges_synchronize was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

758
		while (is_array(/** @scrutinizer ignore-call */ mapi_exportchanges_synchronize($exporter))) {
Loading history...
759
			if ($changesCount > $bufferSize) {
760
				$this->logger->info("There were too many changes to be exported in this request. Total changes %d, exported %d.", $changesCount, $phpwrapper->Total());
761
762
				break;
763
			}
764
		}
765
		$exportedChanges = $phpwrapper->Total();
766
		$this->logger->debug("Exported %d changes, pending %d", $exportedChanges, $changesCount - $exportedChanges);
767
768
		mapi_exportchanges_updatestate($exporter, $stream);
0 ignored issues
show
Bug introduced by
The function mapi_exportchanges_updatestate was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

768
		/** @scrutinizer ignore-call */ 
769
  mapi_exportchanges_updatestate($exporter, $stream);
Loading history...
769
		mapi_stream_seek($stream, 0, STREAM_SEEK_SET);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\STREAM_SEEK_SET was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The function mapi_stream_seek was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

769
		/** @scrutinizer ignore-call */ 
770
  mapi_stream_seek($stream, 0, STREAM_SEEK_SET);
Loading history...
770
		$state = "";
771
		while (true) {
772
			$data = mapi_stream_read($stream, 4096);
0 ignored issues
show
Bug introduced by
The function mapi_stream_read was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

772
			$data = /** @scrutinizer ignore-call */ mapi_stream_read($stream, 4096);
Loading history...
773
			if (strlen($data) > 0) {
774
				$state .= $data;
775
			}
776
			else {
777
				break;
778
			}
779
		}
780
781
		$newtoken = ($phpwrapper->Total() > 0) ? uniqid() : $syncToken;
782
783
		$this->syncstate->setState($arr[1], $newtoken, bin2hex($state));
784
785
		$result = [
786
			"syncToken" => $newtoken,
787
			"added" => $phpwrapper->GetAdded(),
788
			"modified" => $phpwrapper->GetModified(),
789
			"deleted" => $phpwrapper->GetDeleted(),
790
		];
791
792
		$this->logger->trace("Returning %s", $result);
793
794
		return $result;
795
	}
796
797
	/**
798
	 * Returns an array of necessary properties to set with default values.
799
	 *
800
	 * @see MapiProps::GetDefault...Properties()
801
	 *
802
	 * @param mixed $id           storeid
803
	 * @param mixed $mapimessage  mapi message to check
804
	 * @param array $propList     array of mapped properties
805
	 * @param array $defaultProps array of necessary properties with default values
806
	 *
807
	 * @return array
808
	 */
809
	public function GetPropsToSet($id, $mapimessage, $propList, $defaultProps) {
810
		$propsToSet = [];
811
		$store = $this->GetStoreById($id);
812
		$propList = getPropIdsFromStrings($store, $propList);
0 ignored issues
show
Bug introduced by
The function getPropIdsFromStrings was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

812
		$propList = /** @scrutinizer ignore-call */ getPropIdsFromStrings($store, $propList);
Loading history...
813
		$props = mapi_getprops($mapimessage);
814
815
		foreach ($defaultProps as $prop => $value) {
816
			if (!isset($props[$propList[$prop]])) {
817
				$propsToSet[$propList[$prop]] = $value;
818
			}
819
		}
820
821
		return $propsToSet;
822
	}
823
824
	/**
825
	 * Checks whether the user is enabled for grommunio-dav.
826
	 *
827
	 * @return bool
828
	 */
829
	private function isGdavEnabled() {
830
		$storeProps = mapi_getprops($this->GetStore($this->GetUser()), [PR_EC_ENABLED_FEATURES_L]);
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\PR_EC_ENABLED_FEATURES_L was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
831
		if ($storeProps[PR_EC_ENABLED_FEATURES_L] & UP_DAV) {
0 ignored issues
show
Bug introduced by
The constant grommunio\DAV\UP_DAV was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
832
			$this->logger->debug("user %s is enabled for grommunio-dav", $this->user);
833
834
			return true;
835
		}
836
		$this->logger->debug("user %s is disabled for grommunio-dav", $this->user);
837
838
		return false;
839
	}
840
}
841