Test Failed
Push — master ( 19e7e7...e85ccb )
by
unknown
07:48
created

AdvancedSearchListModule::messageList()   C

Complexity

Conditions 13
Paths 71

Size

Total Lines 82
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 13
eloc 52
c 2
b 1
f 0
nc 71
nop 4
dl 0
loc 82
rs 6.6166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
require_once BASE_PATH . 'server/includes/core/class.indexsqlite.php';
4
5
class AdvancedSearchListModule extends ListModule {
6
	/**
7
	 * Constructor.
8
	 *
9
	 * @param int   $id   unique id
10
	 * @param array $data list of all actions
11
	 */
12
	public function __construct($id, $data) {
13
		parent::__construct($id, $data);
14
		// TODO: create a new method in Properties class that will return only the properties we
15
		// need for search list (and perhaps for preview???)
16
		$this->properties = $GLOBALS["properties"]->getMailListProperties();
17
		$this->properties = array_merge($this->properties, $GLOBALS["properties"]->getAppointmentListProperties());
18
		$this->properties = array_merge($this->properties, $GLOBALS["properties"]->getContactListProperties());
19
		$this->properties = array_merge($this->properties, $GLOBALS["properties"]->getStickyNoteListProperties());
20
		$this->properties = array_merge($this->properties, $GLOBALS["properties"]->getTaskListProperties());
21
		$this->properties = array_merge($this->properties, [
22
			'body' => PR_BODY,
23
			'html_body' => PR_HTML,
24
			'startdate' => "PT_SYSTIME:PSETID_Appointment:" . PidLidAppointmentStartWhole,
25
			'duedate' => "PT_SYSTIME:PSETID_Appointment:" . PidLidAppointmentEndWhole,
26
			'creation_time' => PR_CREATION_TIME,
27
			"task_duedate" => "PT_SYSTIME:PSETID_Task:" . PidLidTaskDueDate,
28
		]);
29
		$this->properties = getPropIdsFromStrings($GLOBALS["mapisession"]->getDefaultMessageStore(), $this->properties);
30
		$this->sort = [
31
			PR_MESSAGE_DELIVERY_TIME => TABLE_SORT_DESCEND,
32
		];
33
	}
34
35
	/**
36
	 * Executes all the actions in the $data variable.
37
	 */
38
	public function execute() {
39
		foreach ($this->data as $actionType => $action) {
40
			if (isset($actionType)) {
41
				try {
42
					$store = $this->getActionStore($action);
43
					$parententryid = $this->getActionParentEntryID($action);
0 ignored issues
show
Unused Code introduced by
The assignment to $parententryid is dead and can be removed.
Loading history...
44
					$entryid = $this->getActionEntryID($action);
45
46
					switch ($actionType) {
47
						case "list":
48
						case "updatelist":
49
							$this->getDelegateFolderInfo($store);
0 ignored issues
show
Bug introduced by
$store of type object is incompatible with the type resource expected by parameter $store of ListModule::getDelegateFolderInfo(). ( Ignorable by Annotation )

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

49
							$this->getDelegateFolderInfo(/** @scrutinizer ignore-type */ $store);
Loading history...
50
							$this->messageList($store, $entryid, $action, $actionType);
51
							break;
52
53
						case "search":
54
							$this->search($store, $entryid, $action, $actionType);
55
							break;
56
57
						case "updatesearch":
58
							$this->updatesearch($store, $entryid, $action);
59
							break;
60
61
						case "stopsearch":
62
							$this->stopSearch($store, $entryid, $action);
63
							break;
64
65
						case "delete_searchfolder":
66
							$this->deleteSearchFolder($store, $entryid, $action);
67
							break;
68
					}
69
				}
70
				catch (MAPIException $e) {
71
					// This is a very nasty hack that makes sure that grommunio Web doesn't show an error message when
72
					// search wants to throw an error. This is only done because a proper fix for this bug has not
73
					// been found yet. When WA-9161 is really solved, this should be removed again.
74
					if ($actionType !== 'search' && $actionType !== 'updatesearch' && $actionType !== 'stopsearch') {
75
						$this->processException($e, $actionType);
76
					}
77
					else {
78
						if (DEBUG_LOADER === 'LOAD_SOURCE') {
79
							// Log all info we can get about this error to the error log of the web server
80
							error_log("Error in search: \n" . var_export($e, true) . "\n\n" . var_export(debug_backtrace(), true));
81
						}
82
						// Send success feedback without data, as if nothing strange happened...
83
						$this->sendFeedback(true);
84
					}
85
				}
86
			}
87
		}
88
	}
89
90
	/**
91
	 * Function which retrieves a list of messages in a folder.
92
	 *
93
	 * @param object $store      MAPI Message Store Object
94
	 * @param string $entryid    entryid of the folder
95
	 * @param array  $action     the action data, sent by the client
96
	 * @param string $actionType the action type, sent by the client
97
	 */
98
	public function messageList($store, $entryid, $action, $actionType) {
99
		$this->searchFolderList = false; // Set to indicate this is not the search result, but a normal folder content
100
		$data = [];
101
102
		if ($store && $entryid) {
103
			// Restriction
104
			$this->parseRestriction($action);
0 ignored issues
show
Bug introduced by
$action of type array is incompatible with the type object expected by parameter $action of ListModule::parseRestriction(). ( Ignorable by Annotation )

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

104
			$this->parseRestriction(/** @scrutinizer ignore-type */ $action);
Loading history...
105
106
			// Sort
107
			$this->parseSortOrder($action, null, true);
108
109
			$limit = $action['restriction']['limit'] ?? 1000;
110
111
			$isSearchFolder = isset($action['search_folder_entryid']);
112
			$entryid = $isSearchFolder ? hex2bin($action['search_folder_entryid']) : $entryid;
113
114
			if ($actionType == 'search') {
115
				$rows = [[PR_ENTRYID => $entryid]];
116
				if (isset($action['subfolders']) && $action['subfolders']) {
117
					$folder = mapi_msgstore_openentry($store, $entryid);
118
					$htable = mapi_folder_gethierarchytable($folder, CONVENIENT_DEPTH | MAPI_DEFERRED_ERRORS);
119
					$rows = mapi_table_queryallrows($htable, [PR_ENTRYID]);
120
				}
121
				$data['item'] = [];
122
				foreach ($rows as $row) {
123
					$items = $GLOBALS["operations"]->getTable($store, $row[PR_ENTRYID], $this->properties, $this->sort, $this->start, $limit, $this->restriction);
124
					$data['item'] = array_merge($data['item'], $items['item']);
125
					if (count($data['item']) >= $limit) {
126
						break;
127
					}
128
				}
129
				$data['page'] = [];
130
				$data['page']['start'] = 0;
131
				$data['page']['rowcount'] = 0;
132
				$data['page']['totalrowcount'] = count($data['item']);
133
				$data['search_meta'] = [];
134
				$data['search_meta']['searchfolder_entryid'] = null;
135
				$data['search_meta']['search_store_entryid'] = $action['store_entryid'];
136
				$data['search_meta']['searchstate'] = null;
137
				$data['search_meta']['results'] = count($data['item']);
138
				$data['folder'] = [];
139
				$data['folder']['content_count'] = count($data['item']);
140
				$data['folder']['content_unread'] = 0;
141
			}
142
			else {
143
				// Get the table and merge the arrays
144
				$data = $GLOBALS["operations"]->getTable($store, $entryid, $this->properties, $this->sort, $this->start, $limit, $this->restriction);
145
			}
146
147
			// If the request come from search folder then no need to send folder information
148
			if (!$isSearchFolder && !isset($data['folder'])) {
149
				// Open the folder.
150
				$folder = mapi_msgstore_openentry($store, $entryid);
151
				$data["folder"] = [];
152
153
				// Obtain some statistics from the folder contents
154
				$contentcount = mapi_getprops($folder, [PR_CONTENT_COUNT, PR_CONTENT_UNREAD]);
155
				if (isset($contentcount[PR_CONTENT_COUNT])) {
156
					$data["folder"]["content_count"] = $contentcount[PR_CONTENT_COUNT];
157
				}
158
159
				if (isset($contentcount[PR_CONTENT_UNREAD])) {
160
					$data["folder"]["content_unread"] = $contentcount[PR_CONTENT_UNREAD];
161
				}
162
			}
163
164
			$data = $this->filterPrivateItems($data);
165
166
			// Allowing to hook in just before the data sent away to be sent to the client
167
			$GLOBALS['PluginManager']->triggerHook('server.module.listmodule.list.after', [
168
				'moduleObject' => &$this,
169
				'store' => $store,
170
				'entryid' => $entryid,
171
				'action' => $action,
172
				'data' => &$data,
173
			]);
174
175
			// unset will remove the value but will not regenerate array keys, so we need to
176
			// do it here
177
			$data["item"] = array_values($data["item"]);
178
			$this->addActionData($actionType, $data);
179
			$GLOBALS["bus"]->addData($this->getResponseData());
180
		}
181
	}
182
183
	private function parsePatterns($restriction, &$patterns) {
184
		if (empty($restriction)) {
185
			return;
186
		}
187
		$type = $restriction[0];
188
		if ($type == RES_CONTENT) {
189
			$subres = $restriction[1];
190
191
			switch ($subres[ULPROPTAG]) {
192
				case PR_SUBJECT:
193
					$patterns['subject'] = $subres[VALUE][$subres[ULPROPTAG]];
194
					break;
195
196
				case PR_BODY:
197
					$patterns['content'] = $subres[VALUE][$subres[ULPROPTAG]];
198
					$patterns['attachments'] = $subres[VALUE][$subres[ULPROPTAG]];
199
					break;
200
201
				case PR_SENDER_NAME:
202
					$patterns['sender'] = $subres[VALUE][$subres[ULPROPTAG]];
203
					break;
204
205
				case PR_SENT_REPRESENTING_NAME:
206
					$patterns['sending'] = $subres[VALUE][$subres[ULPROPTAG]];
207
					break;
208
209
				case PR_DISPLAY_TO:
210
				case PR_DISPLAY_CC:
211
					$patterns['recipients'] = $subres[VALUE][$subres[ULPROPTAG]];
212
					break;
213
214
				case PR_MESSAGE_CLASS:
215
					if (empty($patterns['message_classes'])) {
216
						$patterns['message_classes'] = [];
217
					}
218
					$patterns['message_classes'][] = $subres[VALUE][$subres[ULPROPTAG]];
219
					break;
220
221
				case PR_DISPLAY_NAME:
222
					$patterns['others'] = $subres[VALUE][$subres[ULPROPTAG]];
223
					break;
224
225
				case $this->properties['categories']:
226
					if (!isset($patterns['categories'])) {
227
						$patterns['categories'] = [];
228
					}
229
					if (isset($subres[VALUE][$subres[ULPROPTAG]][0])) {
230
						$patterns['categories'][] = $subres[VALUE][$subres[ULPROPTAG]][0];
231
					}
232
					break;
233
			}
234
		}
235
		elseif ($type == RES_AND || $type == RES_OR) {
236
			foreach ($restriction[1] as $subres) {
237
				$this->parsePatterns($subres, $patterns);
238
			}
239
		}
240
		elseif ($type == RES_BITMASK) {
241
			$subres = $restriction[1];
242
			if ($subres[ULPROPTAG] == PR_MESSAGE_FLAGS && $subres[ULTYPE] == BMR_EQZ) {
243
				$patterns['unread'] = MSGFLAG_READ & $subres[ULMASK];
244
			}
245
		}
246
		elseif ($type == RES_PROPERTY) {
247
			$subres = $restriction[1];
248
			if ($subres[ULPROPTAG] == PR_MESSAGE_DELIVERY_TIME ||
249
				$subres[ULPROPTAG] == PR_LAST_MODIFICATION_TIME) {
250
				if ($subres[RELOP] == RELOP_LT ||
251
					$subres[RELOP] == RELOP_LE) {
252
					$patterns['date_end'] = $subres[VALUE][$subres[ULPROPTAG]];
253
				}
254
				elseif ($subres[RELOP] == RELOP_GT ||
255
					$subres[RELOP] == RELOP_GE) {
256
					$patterns['date_start'] = $subres[VALUE][$subres[ULPROPTAG]];
257
				}
258
			}
259
		}
260
		elseif ($type == RES_SUBRESTRICTION) {
261
			$subres = $restriction[1];
262
			$patterns['has_attachments'] = $subres[ULPROPTAG] == PR_MESSAGE_ATTACHMENTS;
263
		}
264
	}
265
266
	/**
267
	 *	Function will set search restrictions on search folder and start search process
268
	 *	and it will also parse visible columns and sorting data when sending results to client.
269
	 *
270
	 * @param object $store      MAPI Message Store Object
271
	 * @param string $entryid    entryid of the folder
272
	 * @param object $action     the action data, sent by the client
273
	 * @param string $actionType the action type, sent by the client
274
	 */
275
	public function search($store, $entryid, $action, $actionType) {
276
		$useSearchFolder = isset($action["use_searchfolder"]) ? $action["use_searchfolder"] : false;
277
		if (!$useSearchFolder) {
278
			/*
279
			 * store doesn't support search folders so we can't use this
280
			 * method instead we will pass restriction to messageList and
281
			 * it will give us the restricted results
282
			 */
283
			return parent::messageList($store, $entryid, $action, "list");
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::messageList($sto...tryid, $action, 'list') targeting ListModule::messageList() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
$action of type object is incompatible with the type array expected by parameter $action of ListModule::messageList(). ( Ignorable by Annotation )

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

283
			return parent::messageList($store, $entryid, /** @scrutinizer ignore-type */ $action, "list");
Loading history...
284
		}
285
		$store_props = mapi_getprops($store, [PR_MDB_PROVIDER, PR_DEFAULT_STORE, PR_IPM_SUBTREE_ENTRYID]);
286
		if ($store_props[PR_MDB_PROVIDER] == ZARAFA_STORE_PUBLIC_GUID) {
287
			// public store does not support search folders
288
			return parent::messageList($store, $entryid, $action, "search");
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::messageList($sto...yid, $action, 'search') targeting ListModule::messageList() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
289
		}
290
		if ($GLOBALS['entryid']->compareEntryIds(bin2hex($entryid), bin2hex(TodoList::getEntryId()))) {
291
			// todo list do not need to perform full text index search
292
			return parent::messageList($store, $entryid, $action, "list");
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::messageList($sto...tryid, $action, 'list') targeting ListModule::messageList() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
293
		}
294
295
		$this->searchFolderList = true; // Set to indicate this is not the normal folder, but a search folder
296
		$this->restriction = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type array of property $restriction.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
297
298
		// Parse Restriction
299
		$this->parseRestriction($action);
300
		if ($this->restriction == false) {
301
			// if error in creating restriction then send error to client
302
			$errorInfo = [];
303
			$errorInfo["error_message"] = _("Error in search, please try again") . ".";
304
			$errorInfo["original_error_message"] = "Error in parsing restrictions.";
305
306
			return $this->sendSearchErrorToClient($store, $entryid, $action, $errorInfo);
0 ignored issues
show
Bug introduced by
$entryid of type string is incompatible with the type hexString expected by parameter $entryid of ListModule::sendSearchErrorToClient(). ( Ignorable by Annotation )

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

306
			return $this->sendSearchErrorToClient($store, /** @scrutinizer ignore-type */ $entryid, $action, $errorInfo);
Loading history...
Bug introduced by
$errorInfo of type array is incompatible with the type object expected by parameter $errorInfo of ListModule::sendSearchErrorToClient(). ( Ignorable by Annotation )

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

306
			return $this->sendSearchErrorToClient($store, $entryid, $action, /** @scrutinizer ignore-type */ $errorInfo);
Loading history...
307
		}
308
309
		$isSetSearchFolderEntryId = isset($action['search_folder_entryid']);
310
		if ($isSetSearchFolderEntryId) {
311
			$this->sessionData['searchFolderEntryId'] = $action['search_folder_entryid'];
312
		}
313
314
		if (isset($action['forceCreateSearchFolder']) && $action['forceCreateSearchFolder']) {
315
			$isSetSearchFolderEntryId = false;
316
		}
317
318
		// create or open search folder
319
		$searchFolder = $this->createSearchFolder($store, $isSetSearchFolderEntryId);
320
		if ($searchFolder === false) {
321
			if ($store_props[PR_MDB_PROVIDER] == ZARAFA_STORE_DELEGATE_GUID) {
322
				$this->messageList($store, $entryid, $action, "search");
323
				return true;
324
			}
325
			// if error in creating search folder then send error to client
326
			$errorInfo = [];
327
328
			switch (mapi_last_hresult()) {
329
				case MAPI_E_NO_ACCESS:
330
					$errorInfo["error_message"] = _("Unable to perform search query, no permissions to create search folder.");
331
					break;
332
333
				case MAPI_E_NOT_FOUND:
334
					$errorInfo["error_message"] = _("Unable to perform search query, search folder not found.");
335
					break;
336
337
				default:
338
					$errorInfo["error_message"] = _("Unable to perform search query, store might not support searching.");
339
			}
340
341
			$errorInfo["original_error_message"] = _("Error in creating search folder.");
342
343
			return $this->sendSearchErrorToClient($store, $entryid, $action, $errorInfo);
344
		}
345
346
		$subfolder_flag = 0;
347
		$recursive = false;
348
		if (isset($action["subfolders"]) && $action["subfolders"] == "true") {
349
			$recursive = true;
350
			$subfolder_flag = RECURSIVE_SEARCH;
351
		}
352
353
		if (!is_array($entryid)) {
0 ignored issues
show
introduced by
The condition is_array($entryid) is always false.
Loading history...
354
			$entryids = [$entryid];
355
		}
356
		else {
357
			$entryids = $entryid;
358
		}
359
360
		$searchFolderEntryId = $this->sessionData['searchFolderEntryId'];
361
362
		// check if searchcriteria has changed
363
		$restrictionCheck = md5(serialize($this->restriction) . $searchFolderEntryId . $subfolder_flag);
364
365
		// check if there is need to set searchcriteria again
366
		if (!isset($this->sessionData['searchCriteriaCheck']) || $restrictionCheck != $this->sessionData['searchCriteriaCheck']) {
367
			if (!empty($this->sessionData['searchOriginalEntryids']) &&
368
				isset($action['entryid']) &&
369
				in_array($action['entryid'], $this->sessionData['searchOriginalEntryids'])
370
			) {
371
				// get entryids of original folders, and use it to set new search criteria
372
				$entryids = [];
373
				$entryIdsCount = count($this->sessionData['searchOriginalEntryids']);
374
				for ($index = 0; $index < $entryIdsCount; ++$index) {
375
					$entryids[] = hex2bin($this->sessionData['searchOriginalEntryids'][$index]);
376
				}
377
			}
378
			else {
379
				// store entryids of original folders, so that can be used for re-setting the search criteria if needed
380
				$this->sessionData['searchOriginalEntryids'] = [];
381
				for ($index = 0, $len = count($entryids); $index < $len; ++$index) {
382
					$this->sessionData['searchOriginalEntryids'][] = bin2hex($entryids[$index]);
383
				}
384
			}
385
			// we never start the search folder because we will populate the search folder by ourselves
386
			mapi_folder_setsearchcriteria($searchFolder, $this->restriction, $entryids, $subfolder_flag | STOP_SEARCH);
387
			$this->sessionData['searchCriteriaCheck'] = $restrictionCheck;
388
		}
389
390
		if (isset($this->sessionData['searchCriteriaCheck']) || $restrictionCheck == $this->sessionData['searchCriteriaCheck']) {
391
			$folderEntryid = bin2hex($entryid);
392
			if ($this->sessionData['searchOriginalEntryids'][0] !== $folderEntryid) {
393
				$this->sessionData['searchOriginalEntryids'][0] = $folderEntryid;
394
				// we never start the search folder because we will populate the search folder by ourselves
395
				mapi_folder_setsearchcriteria($searchFolder, $this->restriction, [$entryid], $subfolder_flag | STOP_SEARCH);
396
			}
397
		}
398
399
		// Sort
400
		$this->parseSortOrder($action);
401
		// Initialize search patterns with default values
402
		$search_patterns = array_fill_keys(['sender', 'sending', 'recipients',
403
			'subject', 'content', 'attachments', 'others', 'message_classes',
404
			'date_start', 'date_end', 'unread', 'has_attachments', 'categories'],
405
			null);
406
		$this->parsePatterns($this->restriction, $search_patterns);
407
		if (isset($search_patterns['message_classes']) &&
408
			count($search_patterns['message_classes']) >= 7) {
409
			$search_patterns['message_classes'] = null;
410
		}
411
412
		if ($store_props[PR_MDB_PROVIDER] == ZARAFA_STORE_DELEGATE_GUID) {
413
			$eidObj = $GLOBALS["entryid"]->createMsgStoreEntryIdObj(hex2bin($action['store_entryid']));
414
			$username = $eidObj['ServerShortname'];
415
			$session = $GLOBALS["mapisession"]->getSession();
416
417
			if ($username) {
418
				$indexDB = new IndexSqlite($username, $session, $store);
419
			}
420
		}
421
		else {
422
			$indexDB = new IndexSqlite();
423
		}
424
425
		$search_result = $indexDB->search(hex2bin($searchFolderEntryId), $search_patterns, $entryid, $recursive);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $indexDB does not seem to be defined for all execution paths leading up to this point.
Loading history...
426
		// Use the query search if search in index fails or is not available.
427
		if ($search_result == false) {
428
			// Search in the inbox instead of Top of Information Store
429
			if (isset($store_props[PR_IPM_SUBTREE_ENTRYID]) &&
430
				$GLOBALS['entryid']->compareEntryIds(bin2hex($entryid), bin2hex($store_props[PR_IPM_SUBTREE_ENTRYID]))) {
431
				$inbox = mapi_msgstore_getreceivefolder($store);
432
				$inboxProps = mapi_getprops($inbox, [PR_ENTRYID]);
433
				$entryid = $inboxProps[PR_ENTRYID];
434
			}
435
436
			return parent::messageList($store, $entryid, $action, "search");
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::messageList($sto...yid, $action, 'search') targeting ListModule::messageList() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
437
		}
438
439
		unset($action["restriction"]);
440
441
		// Get the table and merge the arrays
442
		$table = $GLOBALS["operations"]->getTable($store, hex2bin($searchFolderEntryId), $this->properties, $this->sort, $this->start);
443
		// Create the data array, which will be send back to the client
444
		$data = [];
445
		$data = array_merge($data, $table);
446
447
		$this->getDelegateFolderInfo($store);
0 ignored issues
show
Bug introduced by
$store of type object is incompatible with the type resource expected by parameter $store of ListModule::getDelegateFolderInfo(). ( Ignorable by Annotation )

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

447
		$this->getDelegateFolderInfo(/** @scrutinizer ignore-type */ $store);
Loading history...
448
		$data = $this->filterPrivateItems($data);
449
450
		// remember which entryid's are send to the client
451
		$searchResults = [];
452
		foreach ($table["item"] as $item) {
453
			// store entryid => last_modification_time mapping
454
			$searchResults[$item["entryid"]] = $item["props"]["last_modification_time"];
455
		}
456
457
		// store search results into session data
458
		if (!isset($this->sessionData['searchResults'])) {
459
			$this->sessionData['searchResults'] = [];
460
		}
461
		$this->sessionData['searchResults'][$searchFolderEntryId] = $searchResults;
462
463
		$result = mapi_folder_getsearchcriteria($searchFolder);
464
465
		$data["search_meta"] = [];
466
		$data["search_meta"]["searchfolder_entryid"] = $searchFolderEntryId;
467
		$data["search_meta"]["search_store_entryid"] = $action["store_entryid"];
468
		$data["search_meta"]["searchstate"] = $result["searchstate"];
469
		$data["search_meta"]["results"] = count($searchResults);
470
471
		// Reopen the search folder, because otherwise the suggestion property will
472
		// not have been updated
473
		$searchFolder = $this->createSearchFolder($store, true);
474
		$storeProps = mapi_getprops($searchFolder, [PR_EC_SUGGESTION]);
475
		if (isset($storeProps[PR_EC_SUGGESTION])) {
476
			$data["search_meta"]["suggestion"] = $storeProps[PR_EC_SUGGESTION];
477
		}
478
479
		$this->addActionData("search", $data);
480
		$GLOBALS["bus"]->addData($this->getResponseData());
481
482
		return true;
483
	}
484
}
485