Test Failed
Push — master ( 647c72...cd42b5 )
by
unknown
10:25
created

AddressbookListModule::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
	/**
3
	 * Addressbook Module
4
	 */
5
	class AddressbookListModule extends ListModule
6
	{
7
		/**
8
		 * Constructor
9
		 * @param int $id unique id.
10
		 * @param array $data list of all actions.
11
		 */
12
		function __construct($id, $data)
13
		{
14
			$this->properties = $GLOBALS['properties']->getAddressBookListProperties();
15
16
			parent::__construct($id, $data);
17
		}
18
19
		/**
20
		 * Creates the notifiers for this module,
21
		 * and register them to the Bus.
22
		 */
23
		function createNotifiers()
24
		{
25
			$GLOBALS["bus"]->registerNotifier('addressbooknotifier', ADDRESSBOOK_ENTRYID);
26
		}
27
28
		/**
29
		 * Executes all the actions in the $data variable.
30
		 * @return boolean true on success of false on fialure.
31
		 */
32
		function execute()
33
		{
34
			foreach($this->data as $actionType => $action)
35
			{
36
				if(isset($actionType)) {
37
					try {
38
						$store = $this->getActionStore($action);
39
						$parententryid = $this->getActionParentEntryID($action);
40
						$entryid = $this->getActionEntryID($action);
41
42
						if(isset($action['subActionType']) && $action['subActionType'] != '') {
43
							$subActionType = $action['subActionType'];
44
						}
45
46
						switch($actionType)
47
						{
48
							case 'list':
49
								switch($subActionType)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subActionType does not seem to be defined for all execution paths leading up to this point.
Loading history...
50
								{
51
									case 'hierarchy':
52
										$this->getHierarchy($action);
53
										break;
54
									case 'globaladdressbook':
55
										$this->GABUsers($action, $subActionType);
56
										break;
57
									default:
58
										$this->handleUnknownActionType($actionType);
59
								}
60
								break;
61
							default:
62
								$this->handleUnknownActionType($actionType);
63
						}
64
					} catch (MAPIException $e) {
65
						$this->processException($e, $actionType, $store, $parententryid, $entryid, $action);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parententryid does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $entryid does not seem to be defined for all execution paths leading up to this point.
Loading history...
66
					}
67
				}
68
			}
69
		}
70
71
		/**
72
		 * Function which retrieves the list of system users in Zarafa.
73
		 * @param object $store MAPI Message Store Object
74
		 * @param array $action the action data, sent by the client
75
		 * @param string $actionType the action type, sent by the client
76
		 * @return boolean true on success or false on failure
77
		 */
78
		function GABUsers($action, $actionType)
79
		{
80
			$searchstring = '';
81
			$hide_users = false;
82
			$hide_groups = false;
83
			$hide_companies = false;
84
85
			if(isset($action['restriction'])) {
86
				if(isset($action['restriction']['searchstring'])) {
87
					// Get search string for searching in AB.
88
					$searchstring = $action['restriction']['searchstring'];
89
				}
90
91
				if(isset($action['restriction']['hide_users'])) {
92
					$hide_users = $action['restriction']['hide_users'];
93
				}
94
				if(isset($action['restriction']['hide_groups'])) {
95
					$hide_groups = $action['restriction']['hide_groups'];
96
				}
97
				if(isset($action['restriction']['hide_companies'])) {
98
					$hide_companies = $action['restriction']['hide_companies'];
99
				}
100
			}
101
102
			$items = array();
103
104
			$data['page'] = array();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
105
			$data['page']['start'] = 0;
106
			$data['page']['rowcount'] = 0;
107
			$data['page']['totalrowcount'] = 0;
108
109
			$data = array();
110
111
			$this->sort = array();
112
113
			$map = array();
114
			$map['fileas'] = $this->properties['account'];
115
116
			// Rewrite the sort info when sorting on full name as this is a combination of multiple fields
117
			global $sortingField;
118
			if ( isset($action["sort"]) && is_array($action["sort"]) && count($action["sort"])===1 && isset($action["sort"][0]["field"])) {
119
				$sortingDir = $action["sort"][0]["direction"];
120
				$sortingField = $action["sort"][0]["field"];
121
				if($action["sort"][0]["field"] === 'full_name') {
122
					$action["sort"] = array(
123
						array(
124
							"field" 	=> "surname",
125
							"direction" => $sortingDir
126
						),
127
						array(
128
							"field" 	=> "given_name",
129
							"direction" => $sortingDir
130
						),
131
						array(
132
							"field" 	=> "middle_name",
133
							"direction" => $sortingDir
134
						),
135
						array(
136
							"field" 	=> "display_name",
137
							"direction" => $sortingDir
138
						),
139
					);
140
				}
141
142
				// Parse incoming sort order
143
				$this->parseSortOrder($action, $map, true);
144
			}
145
146
			$folderType = $action['folderType'];
147
148
			if (($folderType!=='gab' || ENABLE_FULL_GAB) || !empty($searchstring)) {
149
				$ab = $GLOBALS['mapisession']->getAddressbook(false, true);
150
151
				if (!empty($action['entryid'])) {
152
					$entryid = hex2bin($action['entryid']);
153
				} else {
154
					$entryid = mapi_ab_getdefaultdir($ab);
155
				}
156
157
				$dir = mapi_ab_openentry($ab,$entryid);
158
159
				/**
160
				 * @TODO: 'All Address Lists' on IABContainer gives MAPI_E_INVALID_PARAMETER,
161
				 * as it contains subfolders only. When #7344 is fixed, MAPI will return error here,
162
				 * handle it here and return false.
163
				 */
164
				$table = mapi_folder_getcontentstable($dir, MAPI_DEFERRED_ERRORS);
165
166
				$restriction = false;
167
				$tempRestriction = false;
168
				$userGroupRestriction = false;
169
170
				if($hide_users || $hide_groups || $hide_companies) {
171
					$userRestrictions = array();
172
					if ($hide_users) {
173
						$tmp = $this->createUsersRestriction($hide_users);
174
						if ($tmp) {
0 ignored issues
show
introduced by
$tmp is of type restrictionObject, thus it always evaluated to true.
Loading history...
175
							$userRestrictions[] = $tmp;
176
						}
177
					}
178
					if ($hide_groups) {
179
						$tmp = $this->createGroupsRestriction($hide_groups);
180
						if ($tmp) {
0 ignored issues
show
introduced by
$tmp is of type restrictionObject, thus it always evaluated to true.
Loading history...
181
							$userRestrictions[] = $tmp;
182
						}
183
					}
184
					if ($hide_companies) {
185
						$tmp = $this->createCompanyRestriction($hide_companies);
186
						if ($tmp) {
0 ignored issues
show
introduced by
$tmp is of type restrictionObject, thus it always evaluated to true.
Loading history...
187
							$userRestrictions[] = $tmp;
188
						}
189
					}
190
					$userGroupRestriction = Array(RES_AND, $userRestrictions);
191
				}
192
193
				if(!empty($searchstring)){
194
					// create restriction for search
195
					// only return users from who the displayName or the username starts with $searchstring
196
					// TODO: use PR_ANR for this restriction instead of PR_DISPLAY_NAME and PR_ACCOUNT
197
					$tempRestriction = array(RES_OR,
198
								array(
199
									// Display name of user from GAB and contacts.
200
									array(
201
										RES_CONTENT,
202
											array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
203
												ULPROPTAG => PR_DISPLAY_NAME,
204
												VALUE => $searchstring
205
											)
206
										),
207
									// fileas value of user from GAB.
208
									array(
209
										RES_CONTENT,
210
											array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
211
												ULPROPTAG => PR_ACCOUNT,
212
												VALUE => $searchstring
213
											)
214
										),
215
									// smtp_address of user from GAB.
216
									array(
217
										RES_CONTENT,
218
											array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
219
												ULPROPTAG => PR_SMTP_ADDRESS,
220
												VALUE => $searchstring
221
											)
222
										),
223
									// email_address of user from GAB and contacts.
224
									array(
225
										RES_CONTENT,
226
											array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
227
												ULPROPTAG => PR_EMAIL_ADDRESS,
228
												VALUE => $searchstring
229
											)
230
										),
231
									// department of user from GAB.
232
									array(
233
										RES_CONTENT,
234
											array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
235
												ULPROPTAG => PR_DEPARTMENT_NAME,
236
												VALUE => $searchstring
237
											)
238
										),
239
									// fileas of user from Contacts.
240
									array(
241
										RES_CONTENT,
242
											array(FUZZYLEVEL => FL_SUBSTRING|FL_IGNORECASE,
243
												ULPROPTAG => PR_ORIGINAL_DISPLAY_NAME,
244
												VALUE => $searchstring
245
											)
246
										)
247
								)
248
							);
249
 				}
250
251
				if($tempRestriction && $userGroupRestriction) {
252
					$restriction = Array(
253
								RES_AND,
254
								Array(
255
									// restriction for search/alphabet bar
256
									$tempRestriction,
257
									// restriction for hiding users/groups
258
									$userGroupRestriction,
259
					));
260
				} else if($tempRestriction) {
261
					// restriction for search/alphabet bar
262
					$restriction = $tempRestriction;
263
				} else {
264
					// restriction for hiding users/groups
265
					$restriction = $userGroupRestriction;
266
				}
267
268
				// Only add restriction when it is used
269
				if($restriction) {
270
					mapi_table_restrict($table, $restriction, TBL_BATCH);
271
				}
272
				// Only sort when asked for
273
				if ( !empty($this->sort) ) {
274
					mapi_table_sort($table, $this->sort, TBL_BATCH);
275
				}
276
277
				$rowCount = mapi_table_getrowcount($table);
278
279
				if ( is_int(MAX_GAB_RESULTS) && MAX_GAB_RESULTS > 0 && $rowCount > MAX_GAB_RESULTS ) {
280
					// Create a response that contains an error message that there are too much results
281
					$data['error'] = array('code' => 'listexceederror', 'max_gab_users' => MAX_GAB_RESULTS);
282
					$rows = mapi_table_queryrows($table, $this->properties, 0, MAX_GAB_RESULTS);
283
					$rowCount = MAX_GAB_RESULTS;
284
				} else {
285
					$rows = mapi_table_queryallrows($table, $this->properties);
286
				}
287
288
				$sharedStore = null;
289
				if (isset($action["isSharedFolder"]) && $action["isSharedFolder"] === true) {
290
					if(isset($action["sharedFolder"]) && !empty($action["sharedFolder"])) {
291
						$sharedStoreEntryID = $action["sharedFolder"]["store_entryid"];
292
						$sharedStore = $GLOBALS["mapisession"]->openMessageStore(hex2bin($sharedStoreEntryID));
293
					}
294
				}
295
296
				for ($i = 0, $len = $rowCount; $i < $len; $i++) {
297
					// Use array_shift to so we won't double memory usage!
298
					$user_data = array_shift($rows);
299
					$item = array();
300
					$item['entryid'] = bin2hex($user_data[$this->properties['entryid']]);
301
					$item['display_name'] = isset($user_data[$this->properties['display_name']]) ? $user_data[$this->properties['display_name']] : "";
302
					$item['object_type'] = isset($user_data[$this->properties['object_type']]) ? $user_data[$this->properties['object_type']] : "";
303
					$item['display_type'] = isset($user_data[PR_DISPLAY_TYPE]) ? $user_data[PR_DISPLAY_TYPE] : "";
304
					$item['title'] = isset($user_data[PR_TITLE]) ? $user_data[PR_TITLE] : "";
305
					$item['company_name'] = isset($user_data[PR_COMPANY_NAME]) ? $user_data[PR_COMPANY_NAME] : "";
306
307
					// Test whether the GUID in the entryid is from the Contact Provider
308
					if($GLOBALS['entryid']->hasContactProviderGUID( bin2hex($user_data[$this->properties['entryid']]) )){
309
						// Use the original_display_name property to fill in the fileas column
310
						$item['fileas'] = $user_data[$this->properties['original_display_name']] ?? $item['display_name'];
311
						$item['address_type'] = isset($user_data[$this->properties['address_type']]) ? $user_data[$this->properties['address_type']] : 'SMTP';
312
313
						if (isset($action["isSharedFolder"]) && $action["isSharedFolder"] === true) {
314
							if(isset($action["sharedFolder"]) && !empty($action["sharedFolder"])) {
315
								$sharedContactEntryID = $GLOBALS['entryid']->unwrapABEntryIdObj(bin2hex($user_data[$this->properties['entryid']]));
316
								// Address book record does not have 'private' property so we need to open shared contact to
317
								// get the value of 'private'  property.
318
								$contact = $GLOBALS['operations']->openMessage($sharedStore, hex2bin($sharedContactEntryID));
319
								$sharedContactProps = mapi_getprops($contact, array($this->properties['private']));
320
								// Don't show the private contact.
321
								if (isset($sharedContactProps[$this->properties['private']]) && $sharedContactProps[$this->properties['private']] === true) {
322
									continue;
323
								}
324
							}
325
						}
326
327
						switch($user_data[PR_DISPLAY_TYPE]){
328
							case DT_PRIVATE_DISTLIST:
329
								$item['email_address'] = '';
330
								break;
331
							case DT_MAILUSER:
332
							default:
333
								$item['email_address'] = $user_data[$this->properties['email_address']];
334
						}
335
					} else {
336
						// If display_type_ex is not set we can overwrite it with display_type
337
						$item['display_type_ex'] = isset($user_data[PR_DISPLAY_TYPE_EX])?$user_data[PR_DISPLAY_TYPE_EX]:$user_data[PR_DISPLAY_TYPE];
338
						$item['fileas'] = $item['display_name'];
339
						$item['mobile_telephone_number'] = isset($user_data[PR_MOBILE_TELEPHONE_NUMBER])? $user_data[PR_MOBILE_TELEPHONE_NUMBER] : '';
340
						$item['home_telephone_number'] = isset($user_data[PR_HOME_TELEPHONE_NUMBER])? $user_data[PR_HOME_TELEPHONE_NUMBER] : '';
341
						$item['pager_telephone_number'] = isset($user_data[PR_PAGER_TELEPHONE_NUMBER])? $user_data[PR_PAGER_TELEPHONE_NUMBER] : '';
342
						$item['surname'] = isset($user_data[PR_SURNAME])? $user_data[PR_SURNAME] : '';
343
						$item['given_name'] = isset($user_data[$this->properties['given_name']])? $user_data[$this->properties['given_name']] : '';
344
345
						switch($user_data[PR_DISPLAY_TYPE]){
346
							case DT_ORGANIZATION:
347
								$item['email_address'] = $user_data[$this->properties['account']];
348
								$item['address_type'] = 'EX';
349
								// The account property is used to fill in the fileas column
350
								$item['fileas'] = $user_data[$this->properties['account']];
351
								break;
352
353
							case DT_DISTLIST:
354
								// The account property is used to fill in the fileas column, private dislist does not have that
355
								$item['fileas'] = $user_data[$this->properties['account']];
356
							case DT_PRIVATE_DISTLIST:
357
								$item['email_address'] = $user_data[$this->properties['account']];
358
								// FIXME: shouldn't be needed, but atm this gives us an undefined offset error which makes the unittests fail.
359
								if($item['email_address'] !== 'Everyone') {
360
									if (isset($user_data[$this->properties['smtp_address']])) {
361
										$item['smtp_address'] = $user_data[$this->properties['smtp_address']];
362
									}
363
								}
364
								$item['address_type'] = 'EX';
365
								break;
366
367
							case DT_MAILUSER:
368
								// The account property is used to fill in the fileas column, remote mailuser does not have that
369
								$item['fileas'] = $user_data[$this->properties['account']];
370
							case DT_REMOTE_MAILUSER:
371
							default:
372
								$item['email_address'] = $user_data[$this->properties['email_address']];
373
								$item['smtp_address'] = $user_data[$this->properties['smtp_address']];
374
375
								$item['address_type'] = isset($user_data[$this->properties['address_type']]) ? $user_data[$this->properties['address_type']] : 'SMTP';
376
								$item['department_name'] = isset($user_data[$this->properties['department_name']]) ? $user_data[$this->properties['department_name']] : '';
377
								$item['office_telephone_number'] = isset($user_data[$this->properties['office_telephone_number']]) ? $user_data[$this->properties['office_telephone_number']] : '';
378
								$item['office_location'] = isset($user_data[$this->properties['office_location']]) ? $user_data[$this->properties['office_location']] : '';
379
								$item['primary_fax_number'] = isset($user_data[$this->properties['primary_fax_number']]) ? $user_data[$this->properties['primary_fax_number']] : '';
380
							break;
381
						}
382
					}
383
384
					// Create a nice full_name prop ("Lastname, Firstname Middlename")
385
					if ( isset($user_data[$this->properties['surname']]) ){
386
						$item['full_name'] = $user_data[$this->properties['surname']];
387
					} else {
388
						$item['full_name'] = '';
389
					}
390
					if ( (isset($user_data[$this->properties['given_name']]) || isset($user_data[$this->properties['middle_name']])) && !empty($item['full_name']) ){
391
						$item['full_name'] .= ', ';
392
					}
393
					if ( isset($user_data[$this->properties['given_name']]) ){
394
						$item['full_name'] .= $user_data[$this->properties['given_name']];
395
					}
396
					if ( isset($user_data[$this->properties['middle_name']]) ){
397
						$item['full_name'] .= ' ' . $user_data[$this->properties['middle_name']];
398
					}
399
					if ( empty($item['full_name']) ){
400
						$item['full_name'] = $item['display_name'];
401
					}
402
403
					if(!empty($user_data[$this->properties['search_key']])) {
404
						$item['search_key'] = bin2hex($user_data[$this->properties['search_key']]);
405
					} else {
406
						// contacts folders are not returning search keys, this should be fixed in Gromox
407
						// meanwhile this is a workaround, check ZCP-10814
408
						// if search key is not passed then we will generate it
409
						$email_address = '';
410
						if(!empty($item['smtp_address'])) {
411
							$email_address = $item['smtp_address'];
412
						} else if(!empty($item['email_address'])) {
413
							$email_address = $item['email_address'];
414
						}
415
416
						if(!empty($email_address)) {
417
							$item['search_key'] = bin2hex(strtoupper($item['address_type'] . ':' . $email_address)) . '00';
418
						}
419
					}
420
421
					array_push($items, array('props' => $item));
422
				}
423
424
				if ( !empty($sortingField) ){
425
					// Sort the items here, because full_name is not a real property, so we can not use the regular sorting
426
					// Note: This hack only works because the GAB does not work with paging!
427
					function cmpAsc($a, $b){
428
						global $sortingField;
429
						return strcasecmp($b['props'][$sortingField], $a['props'][$sortingField]);
430
					}
431
					function cmpDesc($a, $b){
432
						global $sortingField;
433
						return strcasecmp($a['props'][$sortingField], $b['props'][$sortingField]);
434
					}
435
436
					$cmpFn = $sortingDir === 'DESC' ? 'cmpDesc' : 'cmpAsc';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sortingDir does not seem to be defined for all execution paths leading up to this point.
Loading history...
437
					usort($items, $cmpFn);
438
				}
439
440
				// todo: fix paging stuff
441
				$data['page']['start'] = 0;
442
				$data['page']['rowcount'] = $rowCount;
443
				$data['page']['totalrowcount'] = $data['page']['rowcount'];
444
				$data = array_merge($data, array('item'=>$items));
445
			} else {
446
				// Provide clue that full GAB is disabled.
447
				$data = array_merge($data, array('disable_full_gab' => !ENABLE_FULL_GAB));
448
			}
449
450
			$this->addActionData('list', $data);
451
			$GLOBALS['bus']->addData($this->getResponseData());
452
453
			return true;
454
		}
455
456
		/**
457
		 *	Function will create a restriction based on parameters passed for hiding users
458
		 *	@param		Array				$hide_users		list of users that should not be shown
459
		 *	@return		restrictionObject					restriction for hiding provided users
0 ignored issues
show
Bug introduced by
The type restrictionObject was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
460
		 */
461
		function createUsersRestriction($hide_users) {
462
			$usersRestriction = null;
463
464
			// When $hide_users is true, then we globally disable
465
			// all users regardless of their subtype. Otherwise if
466
			// $hide_users is set then we start looking which subtype
467
			// is being filtered out.
468
			if ($hide_users === true) {
0 ignored issues
show
introduced by
The condition $hide_users === true is always false.
Loading history...
469
				$usersRestriction = Array(
470
							RES_AND,
471
								Array(
472
									Array(
473
										RES_PROPERTY,
474
											Array(
475
												RELOP => RELOP_NE,
476
												ULPROPTAG => PR_DISPLAY_TYPE,
477
												VALUE => Array(
478
													PR_DISPLAY_TYPE => DT_MAILUSER
479
												)
480
											)
481
									),
482
									Array(
483
										RES_PROPERTY,
484
											Array(
485
												RELOP => RELOP_NE,
486
												ULPROPTAG => PR_DISPLAY_TYPE,
487
												VALUE => Array(
488
													PR_DISPLAY_TYPE => DT_REMOTE_MAILUSER
489
												)
490
											)
491
									)
492
								)
493
				);
494
			} else if ($hide_users) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $hide_users of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
495
				$tempRestrictions = Array();
496
497
				// wrap parameters in an array
498
				if(!is_array($hide_users)) {
0 ignored issues
show
introduced by
The condition is_array($hide_users) is always true.
Loading history...
499
					$hide_users = Array($hide_users);
500
				}
501
502
				if(in_array('non_security', $hide_users)) {
503
					array_push($tempRestrictions, Array(
504
									RES_BITMASK,
505
										Array(
506
											ULTYPE => BMR_EQZ,
507
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
508
											ULMASK => DTE_FLAG_ACL_CAPABLE
509
										)
510
									)
511
							);
512
				}
513
514
				if(in_array('room', $hide_users)) {
515
					array_push($tempRestrictions, Array(
516
									RES_PROPERTY,
517
										Array(
518
											RELOP => RELOP_EQ,
519
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
520
											VALUE => Array(
521
												PR_DISPLAY_TYPE_EX => DT_ROOM
522
											)
523
										)
524
									)
525
							);
526
				}
527
528
				if(in_array('equipment', $hide_users)) {
529
					array_push($tempRestrictions, Array(
530
									RES_PROPERTY,
531
										Array(
532
											RELOP => RELOP_EQ,
533
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
534
											VALUE => Array(
535
												PR_DISPLAY_TYPE_EX => DT_EQUIPMENT
536
											)
537
										)
538
									)
539
							);
540
				}
541
542
				if(in_array('active', $hide_users)) {
543
					array_push($tempRestrictions, Array(
544
									RES_PROPERTY,
545
										Array(
546
											RELOP => RELOP_EQ,
547
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
548
											VALUE => Array(
549
												PR_DISPLAY_TYPE_EX => DTE_FLAG_ACL_CAPABLE
550
											)
551
										)
552
									)
553
							);
554
				}
555
556
				if(in_array('non_active', $hide_users)) {
557
					array_push($tempRestrictions, Array(
558
									RES_PROPERTY,
559
										Array(
560
											RELOP => RELOP_EQ,
561
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
562
											VALUE => Array(
563
												PR_DISPLAY_TYPE_EX => DT_MAILUSER
564
											)
565
										)
566
									)
567
							);
568
				}
569
570
				if(in_array('contact', $hide_users)) {
571
					array_push($tempRestrictions, Array(
572
									RES_PROPERTY,
573
										Array(
574
											RELOP => RELOP_EQ,
575
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
576
											VALUE => Array(
577
												PR_DISPLAY_TYPE_EX => DT_REMOTE_MAILUSER
578
											)
579
										)
580
									)
581
							);
582
				}
583
584
				if(in_array('system', $hide_users)) {
585
					array_push($tempRestrictions, Array(
586
									RES_CONTENT,
587
										Array(
588
											FUZZYLEVEL => FL_FULLSTRING | FL_IGNORECASE,
589
											ULPROPTAG => PR_ACCOUNT,
590
											VALUE => Array(
591
												PR_ACCOUNT => 'SYSTEM'
592
											)
593
										)
594
								)
595
							);
596
				}
597
598
				if(!empty($tempRestrictions)) {
599
					$usersRestriction = Array(
600
								RES_NOT,
601
								Array(
602
									Array(
603
										RES_AND,
604
											Array(
605
												Array(
606
													RES_OR,
607
														Array(
608
															Array(
609
																RES_PROPERTY,
610
																	Array(
611
																		RELOP => RELOP_EQ,
612
																		ULPROPTAG => PR_DISPLAY_TYPE,
613
																		VALUE => Array(
614
																			PR_DISPLAY_TYPE => DT_MAILUSER
615
																		)
616
																	)
617
															),
618
															Array(
619
																RES_PROPERTY,
620
																	Array(
621
																		RELOP => RELOP_EQ,
622
																		ULPROPTAG => PR_DISPLAY_TYPE,
623
																		VALUE => Array(
624
																			PR_DISPLAY_TYPE => DT_REMOTE_MAILUSER
625
																		)
626
																	)
627
															)
628
														)
629
												),
630
												Array(
631
													RES_OR,
632
													$tempRestrictions // all user restrictions
633
												)
634
											)
635
									)
636
								)
637
							);
638
				}
639
			}
640
641
			return $usersRestriction;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $usersRestriction also could return the type array<integer,array<inte...nteger|mixed>>|integer> which is incompatible with the documented return type restrictionObject.
Loading history...
642
		}
643
644
		/**
645
		 *	Function will create a restriction based on parameters passed for hiding groups
646
		 *	@param		Array				$hide_groups	list of groups that should not be shown
647
		 *	@return		restrictionObject					restriction for hiding provided users
648
		 */
649
		function createGroupsRestriction($hide_groups) {
650
			$groupsRestriction = null;
651
652
			// When $hide_groups is true, then we globally disable
653
			// all groups regardless of their subtype. Otherwise if
654
			// $hide_groups is set then we start looking which subtype
655
			// is being filtered out.
656
			if ($hide_groups === true) {
0 ignored issues
show
introduced by
The condition $hide_groups === true is always false.
Loading history...
657
				$groupsRestriction = Array(
658
							RES_AND,
659
								Array(
660
									Array(
661
										RES_PROPERTY,
662
											Array(
663
												RELOP => RELOP_NE,
664
												ULPROPTAG => PR_DISPLAY_TYPE,
665
												VALUE => Array(
666
													PR_DISPLAY_TYPE => DT_DISTLIST
667
												)
668
											)
669
									),
670
									Array(
671
										RES_PROPERTY,
672
											Array(
673
												RELOP => RELOP_NE,
674
												ULPROPTAG => PR_DISPLAY_TYPE,
675
												VALUE => Array(
676
													PR_DISPLAY_TYPE => DT_PRIVATE_DISTLIST
677
												)
678
											)
679
									)
680
								)
681
						);
682
			} else if($hide_groups) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $hide_groups of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
683
				$tempRestrictions = Array();
684
685
				// wrap parameters in an array
686
				if(!is_array($hide_groups)) {
0 ignored issues
show
introduced by
The condition is_array($hide_groups) is always true.
Loading history...
687
					$hide_groups = Array($hide_groups);
688
				}
689
690
				if(in_array('non_security', $hide_groups)) {
691
					array_push($tempRestrictions, Array(
692
									RES_BITMASK,
693
										Array(
694
											ULTYPE => BMR_EQZ,
695
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
696
											ULMASK => DTE_FLAG_ACL_CAPABLE
697
										)
698
									)
699
							);
700
				}
701
702
				if(in_array('normal', $hide_groups)) {
703
					array_push($tempRestrictions, Array(
704
									RES_PROPERTY,
705
										Array(
706
											RELOP => RELOP_EQ,
707
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
708
											VALUE => Array(
709
												PR_DISPLAY_TYPE_EX => DT_DISTLIST
710
											)
711
										)
712
									)
713
							);
714
				}
715
716
				if(in_array('security', $hide_groups)) {
717
					array_push($tempRestrictions, Array(
718
									RES_PROPERTY,
719
										Array(
720
											RELOP => RELOP_EQ,
721
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
722
											VALUE => Array(
723
												PR_DISPLAY_TYPE_EX => (DT_SEC_DISTLIST | DTE_FLAG_ACL_CAPABLE)
724
											)
725
										)
726
									)
727
							);
728
				}
729
730
				if(in_array('dynamic', $hide_groups)) {
731
					array_push($tempRestrictions, Array(
732
									RES_PROPERTY,
733
										Array(
734
											RELOP => RELOP_EQ,
735
											ULPROPTAG => PR_DISPLAY_TYPE_EX,
736
											VALUE => Array(
737
												PR_DISPLAY_TYPE_EX => DT_AGENT
738
											)
739
										)
740
									)
741
							);
742
				}
743
744
				if(in_array('distribution_list', $hide_groups)) {
745
					array_push($tempRestrictions, Array(
746
									RES_PROPERTY,
747
										Array(
748
											RELOP => RELOP_EQ,
749
											ULPROPTAG => PR_DISPLAY_TYPE,
750
											VALUE => Array(
751
												PR_DISPLAY_TYPE => DT_PRIVATE_DISTLIST
752
											)
753
										)
754
									)
755
							);
756
				}
757
758
				if(in_array('everyone', $hide_groups)) {
759
					array_push($tempRestrictions, Array(
760
									RES_CONTENT,
761
										Array(
762
											FUZZYLEVEL => FL_FULLSTRING | FL_IGNORECASE,
763
											ULPROPTAG => PR_ACCOUNT,
764
											VALUE => Array(
765
												PR_ACCOUNT => 'Everyone'
766
											)
767
										)
768
									)
769
							);
770
				}
771
772
				if(!empty($tempRestrictions)) {
773
					$groupsRestriction = Array(
774
								RES_NOT,
775
								Array(
776
									Array(
777
										RES_AND,
778
										Array(
779
											Array(
780
												RES_OR,
781
												Array(
782
													Array(
783
														RES_PROPERTY,
784
														Array(
785
															RELOP => RELOP_EQ,
786
															ULPROPTAG => PR_DISPLAY_TYPE,
787
															VALUE => Array(
788
																PR_DISPLAY_TYPE => DT_DISTLIST
789
															)
790
														)
791
													),
792
													Array(
793
														RES_PROPERTY,
794
														Array(
795
															RELOP => RELOP_EQ,
796
															ULPROPTAG => PR_DISPLAY_TYPE,
797
															VALUE => Array(
798
																PR_DISPLAY_TYPE => DT_PRIVATE_DISTLIST
799
															)
800
														)
801
													)
802
												)
803
											),
804
											Array(
805
												RES_OR,
806
												$tempRestrictions     // all group restrictions
807
											)
808
										)
809
									)
810
								)
811
					);
812
				}
813
			}
814
815
			return $groupsRestriction;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $groupsRestriction also could return the type array<integer,array<inte...nteger|mixed>>|integer> which is incompatible with the documented return type restrictionObject.
Loading history...
816
		}
817
818
		/**
819
		 *	Function will create a restriction to get company information
820
		 *	@param		Boolean				$hide_companies	true/false
821
		 *	@return		restrictionObject		restriction for getting company info
822
		 */
823
		function createCompanyRestriction($hide_companies) {
824
			$companyRestriction = false;
825
826
			if($hide_companies) {
827
				$companyRestriction = Array(
828
							RES_PROPERTY,
829
								Array(
830
									RELOP => RELOP_NE,
831
									ULPROPTAG => PR_DISPLAY_TYPE,
832
									VALUE => Array(
833
											PR_DISPLAY_TYPE => DT_ORGANIZATION
834
									)
835
								)
836
				);
837
			}
838
839
			return $companyRestriction;
840
		}
841
842
		function getHierarchy($action)
843
		{
844
			$hideContacts = false;
845
			// Check if hide_contacts is set in the restriction
846
			if(isset($action['restriction']) && isset($action['restriction']['hide_contacts'])){
847
				$hideContacts = $action['restriction']['hide_contacts'];
848
			}
849
850
			$folders = $this->getAddressbookHierarchy($hideContacts);
851
			$data = array( 'item' => $folders );
852
			$this->addActionData('list', $data);
853
			$GLOBALS['bus']->addData($this->getResponseData());
854
855
			return true;
856
		}
857
858
		/**
859
		* Get addressbook hierarchy
860
		*
861
		* This function returns the entire hierarchy of the addressbook, with global addressbooks, and contacts
862
		* folders.
863
		*
864
		* The output array contains an associative array for each found contact folder. Each entry contains
865
		* "display_name" => Name of the folder, "entryid" => entryid of the folder, "parent_entryid" => parent entryid
866
		* "storeid" => store entryid, "type" => gab | contacts
867
		*
868
		* @param array Associative array with store information
0 ignored issues
show
Bug introduced by
The type Associative was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
869
		* @return array Array of associative arrays with addressbook container information
870
		* @todo Fix bizarre input parameter format
871
		*/
872
		function getAddressbookHierarchy($hideContacts = false)
873
		{
874
			$ab = $GLOBALS["mapisession"]->getAddressbook(false, true);
875
			$dir = mapi_ab_openentry($ab);
876
			$table = mapi_folder_gethierarchytable($dir, MAPI_DEFERRED_ERRORS | CONVENIENT_DEPTH);
877
878
			if($hideContacts){
879
				// Restrict on the addressbook provider GUID if the contact folders need to be hidden
880
				$restriction = array(RES_PROPERTY,
881
					array(
882
						RELOP => RELOP_EQ,
883
						ULPROPTAG => PR_AB_PROVIDER_ID,
884
						VALUE => array(
885
							PR_AB_PROVIDER_ID => MUIDECSAB
886
						)
887
					)
888
				);
889
				mapi_table_restrict($table, $restriction);
890
			}
891
892
			$items = mapi_table_queryallrows($table, array(PR_DISPLAY_NAME, PR_ENTRYID, PR_PARENT_ENTRYID, PR_DEPTH, PR_AB_PROVIDER_ID));
893
894
			$folders = array();
895
896
			$parent = false;
897
			foreach($items as $item){
898
				// TODO: fix for missing PR_PARENT_ENTRYID, see #2190
899
				if ($item[PR_DEPTH]==0)
900
					$parent = $item[PR_ENTRYID];
901
902
				$item[PR_PARENT_ENTRYID] = $parent;
903
904
				$folders[] = array(
905
					"props" => array(
906
						"display_name"	=> $item[PR_DISPLAY_NAME] ?? '',
907
						"entryid"		=> bin2hex($item[PR_ENTRYID]),
908
						"parent_entryid"=> bin2hex($item[PR_PARENT_ENTRYID]),
909
						"depth"			=> $item[PR_DEPTH],
910
						"type"			=> $item[PR_AB_PROVIDER_ID] == MUIDECSAB ? "gab" : 'contacts',
911
						"object_type"	=> MAPI_ABCONT
912
					)
913
				);
914
			}
915
916
			return $folders;
917
		}
918
919
	}
920
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
921