1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
require_once BASE_PATH . 'server/includes/core/class.properties.php'; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* MAPI session handling. |
7
|
|
|
* |
8
|
|
|
* This class handles MAPI authentication and stores |
9
|
|
|
*/ |
10
|
|
|
class MAPISession { |
11
|
|
|
/** |
12
|
|
|
* @var resource This holds the MAPI Session |
13
|
|
|
*/ |
14
|
|
|
private $session; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @var resource This can hold the addressbook resource |
18
|
|
|
*/ |
19
|
|
|
private $ab; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var array List with all the currently opened stores |
23
|
|
|
*/ |
24
|
|
|
private $stores; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var string The entryid (binary) of the default store |
28
|
|
|
*/ |
29
|
|
|
private $defaultstore; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var string The entryid (binary) of the public store |
33
|
|
|
*/ |
34
|
|
|
private $publicStore; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var array Information about the current session (username/email/password/etc) |
38
|
|
|
*/ |
39
|
|
|
private $session_info; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var array Mapping username -> entryid for other stores |
43
|
|
|
*/ |
44
|
|
|
private $userstores; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var int Makes sure retrieveUserData is called only once |
48
|
|
|
*/ |
49
|
|
|
private $userDataRetrieved; |
50
|
|
|
|
51
|
|
|
public function __construct() { |
52
|
|
|
$this->stores = []; |
53
|
|
|
$this->defaultstore = 0; |
54
|
|
|
$this->publicStore = 0; |
55
|
|
|
$this->session = false; |
|
|
|
|
56
|
|
|
$this->ab = false; |
|
|
|
|
57
|
|
|
$this->userstores = []; |
58
|
|
|
$this->userDataRetrieved = false; |
|
|
|
|
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Logon to via php_mapi extension. |
63
|
|
|
* |
64
|
|
|
* Logs on to Gromox with the specified username and password. If the server is not specified, |
65
|
|
|
* it will logon to the local server. |
66
|
|
|
* |
67
|
|
|
* @param string $username the username of the user |
68
|
|
|
* @param string $password the password of the user |
69
|
|
|
* @param string $server the server address |
70
|
|
|
* @param string $sslcert_file the optional ssl certificate file |
71
|
|
|
* @param string $sslcert_pass the optional ssl certificate password |
72
|
|
|
* @param string $flags the optional logon flags |
73
|
|
|
* |
74
|
|
|
* @return int 0 on no error, otherwise a MAPI error code |
75
|
|
|
*/ |
76
|
|
|
public function logon($username = '', $password = '', $server = DEFAULT_SERVER, $sslcert_file = '', $sslcert_pass = '', $flags = 0) { |
77
|
|
|
$result = NOERROR; |
78
|
|
|
$username = (string) $username; |
79
|
|
|
$password = (string) $password; |
80
|
|
|
$flags |= 1; // Always disable notifications |
81
|
|
|
|
82
|
|
|
try { |
83
|
|
|
$webapp_version = 'WebApp-' . trim(file_get_contents(BASE_PATH . 'version')); |
84
|
|
|
$browser_version = $_SERVER['HTTP_USER_AGENT'] ?? ''; |
85
|
|
|
$this->session = mapi_logon_zarafa( |
86
|
|
|
$username, |
87
|
|
|
$password, |
88
|
|
|
$server, |
89
|
|
|
$sslcert_file, |
90
|
|
|
$sslcert_pass, |
91
|
|
|
$flags, |
92
|
|
|
$webapp_version, |
93
|
|
|
$browser_version |
94
|
|
|
); |
95
|
|
|
if ($this->session !== false) { |
96
|
|
|
$this->session_info["username"] = $username; |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
catch (MAPIException $e) { |
100
|
|
|
$result = $e->getCode(); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
return $result; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Logons to gromox using the access token. |
108
|
|
|
* |
109
|
|
|
* @param mixed $email the username/email of the user |
110
|
|
|
* @param mixed $token the access token |
111
|
|
|
* |
112
|
|
|
* @return int 0 on no error, otherwise a MAPI error code |
113
|
|
|
*/ |
114
|
|
|
public function logon_token($email = null, $token = null) { |
115
|
|
|
$result = NOERROR; |
116
|
|
|
$email = (string) $email; |
117
|
|
|
$token = (string) $token; |
118
|
|
|
|
119
|
|
|
try { |
120
|
|
|
$this->session = mapi_logon_token($token); |
121
|
|
|
if ($this->session !== false) { |
122
|
|
|
$this->session_info["username"] = $email; |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
catch (MAPIException $e) { |
126
|
|
|
$result = $e->getCode(); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return $result; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Get the user MAPI Object. |
134
|
|
|
* |
135
|
|
|
* @param string $userEntryid The user entryid which is going to open. default is false. |
136
|
|
|
* |
137
|
|
|
* @return object an user MAPI object |
138
|
|
|
*/ |
139
|
|
|
public function getUser($userEntryid = false) { |
140
|
|
|
if ($userEntryid === false) { |
141
|
|
|
// get user entryid |
142
|
|
|
$store_props = mapi_getprops($this->getDefaultMessageStore(), [PR_USER_ENTRYID]); |
143
|
|
|
$userEntryid = $store_props[PR_USER_ENTRYID]; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
// open the user entry |
147
|
|
|
return mapi_ab_openentry($this->getAddressbook(true), $userEntryid); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Get logged-in user information. |
152
|
|
|
* |
153
|
|
|
* This function populates the 'session_info' property of this class with the following information: |
154
|
|
|
* - userentryid: the MAPI entryid of the current user |
155
|
|
|
* - fullname: the fullname of the current user |
156
|
|
|
* - emailaddress: the email address of the current user |
157
|
|
|
* |
158
|
|
|
* The function only populates the information once, subsequent calls will return without error and without |
159
|
|
|
* doing anything. |
160
|
|
|
* |
161
|
|
|
* @return array Array of information about the currently logged-on user |
162
|
|
|
*/ |
163
|
|
|
public function retrieveUserData() { |
164
|
|
|
if ($this->userDataRetrieved) { |
165
|
|
|
return; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$result = NOERROR; |
169
|
|
|
|
170
|
|
|
try { |
171
|
|
|
$store_props = mapi_getprops($this->getDefaultMessageStore(), [PR_USER_ENTRYID]); |
172
|
|
|
$user = $this->getUser($store_props[PR_USER_ENTRYID]); |
173
|
|
|
|
174
|
|
|
// receive userdata |
175
|
|
|
$user_props = [PR_ASSISTANT, PR_ASSISTANT_TELEPHONE_NUMBER, PR_BUSINESS2_TELEPHONE_NUMBER, PR_BUSINESS_TELEPHONE_NUMBER, |
176
|
|
|
PR_COMPANY_NAME, PR_COUNTRY, PR_DEPARTMENT_NAME, PR_DISPLAY_NAME, |
177
|
|
|
PR_EMAIL_ADDRESS, PR_EMS_AB_THUMBNAIL_PHOTO, PR_GIVEN_NAME, PR_HOME2_TELEPHONE_NUMBER, |
178
|
|
|
PR_STREET_ADDRESS, PR_HOME_TELEPHONE_NUMBER, PR_INITIALS, PR_LOCALITY, |
179
|
|
|
PR_MOBILE_TELEPHONE_NUMBER, PR_OFFICE_LOCATION, PR_PAGER_TELEPHONE_NUMBER, PR_POSTAL_CODE, |
180
|
|
|
PR_PRIMARY_FAX_NUMBER, PR_PRIMARY_TELEPHONE_NUMBER, PR_SEARCH_KEY, PR_SMTP_ADDRESS, |
181
|
|
|
PR_STATE_OR_PROVINCE, PR_SURNAME, PR_TITLE]; |
182
|
|
|
|
183
|
|
|
$user_props = mapi_getprops($user, $user_props); |
184
|
|
|
|
185
|
|
|
if (is_array($user_props) && isset($user_props[PR_DISPLAY_NAME], $user_props[PR_SMTP_ADDRESS])) { |
186
|
|
|
$this->session_info["userentryid"] = $store_props[PR_USER_ENTRYID]; |
187
|
|
|
$this->session_info["fullname"] = $user_props[PR_DISPLAY_NAME]; |
188
|
|
|
$this->session_info["smtpaddress"] = $user_props[PR_SMTP_ADDRESS]; |
189
|
|
|
$this->session_info["emailaddress"] = $user_props[PR_EMAIL_ADDRESS]; |
190
|
|
|
$this->session_info["searchkey"] = $user_props[PR_SEARCH_KEY]; |
191
|
|
|
$this->session_info["userimage"] = isset($user_props[PR_EMS_AB_THUMBNAIL_PHOTO]) ? "data:image/jpeg;base64," . base64_encode((string) $user_props[PR_EMS_AB_THUMBNAIL_PHOTO]) : ""; |
192
|
|
|
|
193
|
|
|
$this->session_info["given_name"] = $user_props[PR_GIVEN_NAME] ?? ''; |
194
|
|
|
$this->session_info["initials"] = $user_props[PR_INITIALS] ?? ''; |
195
|
|
|
$this->session_info["surname"] = $user_props[PR_SURNAME] ?? ''; |
196
|
|
|
$this->session_info["street_address"] = $user_props[PR_STREET_ADDRESS] ?? ''; |
197
|
|
|
$this->session_info["locality"] = $user_props[PR_LOCALITY] ?? ''; |
198
|
|
|
$this->session_info["state_or_province"] = $user_props[PR_STATE_OR_PROVINCE] ?? ''; |
199
|
|
|
$this->session_info["postal_code"] = $user_props[PR_POSTAL_CODE] ?? ''; |
200
|
|
|
$this->session_info["country"] = $user_props[PR_COUNTRY] ?? ''; |
201
|
|
|
$this->session_info["title"] = $user_props[PR_TITLE] ?? ''; |
202
|
|
|
$this->session_info["company_name"] = $user_props[PR_COMPANY_NAME] ?? ''; |
203
|
|
|
$this->session_info["department_name"] = $user_props[PR_DEPARTMENT_NAME] ?? ''; |
204
|
|
|
$this->session_info["office_location"] = $user_props[PR_OFFICE_LOCATION] ?? ''; |
205
|
|
|
$this->session_info["assistant"] = $user_props[PR_ASSISTANT] ?? ''; |
206
|
|
|
$this->session_info["assistant_telephone_number"] = $user_props[PR_ASSISTANT_TELEPHONE_NUMBER] ?? ''; |
207
|
|
|
$this->session_info["office_telephone_number"] = $user_props[PR_PRIMARY_TELEPHONE_NUMBER] ?? ''; |
208
|
|
|
$this->session_info["business_telephone_number"] = $user_props[PR_BUSINESS_TELEPHONE_NUMBER] ?? ''; |
209
|
|
|
$this->session_info["business2_telephone_number"] = $user_props[PR_BUSINESS2_TELEPHONE_NUMBER] ?? ''; |
210
|
|
|
$this->session_info["primary_fax_number"] = $user_props[PR_PRIMARY_FAX_NUMBER] ?? ''; |
211
|
|
|
$this->session_info["home_telephone_number"] = $user_props[PR_HOME_TELEPHONE_NUMBER] ?? ''; |
212
|
|
|
$this->session_info["home2_telephone_number"] = $user_props[PR_HOME2_TELEPHONE_NUMBER] ?? ''; |
213
|
|
|
$this->session_info["mobile_telephone_number"] = $user_props[PR_MOBILE_TELEPHONE_NUMBER] ?? ''; |
214
|
|
|
$this->session_info["pager_telephone_number"] = $user_props[PR_PAGER_TELEPHONE_NUMBER] ?? ''; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$this->userDataRetrieved = true; |
|
|
|
|
218
|
|
|
} |
219
|
|
|
catch (MAPIException $e) { |
220
|
|
|
$result = $e->getCode(); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
return $result; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Get MAPI session object. |
228
|
|
|
* |
229
|
|
|
* @return mapisession Current MAPI session |
230
|
|
|
*/ |
231
|
|
|
public function getSession() { |
232
|
|
|
return $this->session; |
|
|
|
|
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Set MAPI session object. |
237
|
|
|
* |
238
|
|
|
* @param mapisession The MAPI session |
239
|
|
|
* @param mixed $session |
240
|
|
|
*/ |
241
|
|
|
public function setSession($session) { |
242
|
|
|
$this->session = $session; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Get MAPI addressbook object. |
247
|
|
|
* |
248
|
|
|
* @param bool $providerless When set to true it will return an addressbook resource |
249
|
|
|
* without any Contact Provider set on it, defaults to false |
250
|
|
|
* @param bool $loadSharedContactsProvider when set to true it denotes that shared folders are |
251
|
|
|
* required to be configured to load the contacts from |
252
|
|
|
* |
253
|
|
|
* @return mixed An addressbook object to be used with mapi_ab_* or an error code |
254
|
|
|
*/ |
255
|
|
|
public function getAddressbook($providerless = false, $loadSharedContactsProvider = false) { |
256
|
|
|
if ($providerless) { |
257
|
|
|
try { |
258
|
|
|
return mapi_openaddressbook($this->session); |
259
|
|
|
} |
260
|
|
|
catch (MAPIException $e) { |
261
|
|
|
return $e->getCode(); |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
$result = NOERROR; |
266
|
|
|
|
267
|
|
|
if ($this->ab === false) { |
|
|
|
|
268
|
|
|
$this->setupContactProviderAddressbook($loadSharedContactsProvider); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
try { |
272
|
|
|
if ($this->ab === false) { |
|
|
|
|
273
|
|
|
$this->ab = mapi_openaddressbook($this->session); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
if ($this->ab !== false) { |
|
|
|
|
277
|
|
|
$result = $this->ab; |
278
|
|
|
} |
279
|
|
|
} |
280
|
|
|
catch (MAPIException $e) { |
281
|
|
|
$result = $e->getCode(); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
return $result; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Get logon status |
289
|
|
|
* NOTE: This function only exists for backward compatibility with older plugins. |
290
|
|
|
* Currently the preferred way to check if a user is logged in, is using |
291
|
|
|
* the isAuthenticated() method of WebAppAuthentication. |
292
|
|
|
* |
293
|
|
|
* @return bool true on logged on, false on not logged on |
294
|
|
|
*/ |
295
|
|
|
public function isLoggedOn() { |
296
|
|
|
trigger_error("isLoggedOn is deprecated, use WebAppAuthentication::isAuthenticated()", E_USER_NOTICE); |
297
|
|
|
|
298
|
|
|
return WebAppAuthentication::isAuthenticated(); |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Get current session id. |
303
|
|
|
* |
304
|
|
|
* @deprecated 2.2.0 This function only exists for backward compatibility with |
305
|
|
|
* older plugins that want to send the session id as a GET parameter with |
306
|
|
|
* requests that they make to grommunio.php. The script grommunio.php does not |
307
|
|
|
* expect this parameter anymore, but plugins that are not updated might |
308
|
|
|
* still call this function. |
309
|
|
|
* |
310
|
|
|
* @return string Always empty |
311
|
|
|
*/ |
312
|
|
|
public function getSessionID() { |
313
|
|
|
return ''; |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Get current user entryid. |
318
|
|
|
* |
319
|
|
|
* @return string Current user's entryid |
320
|
|
|
*/ |
321
|
|
|
public function getUserEntryID() { |
322
|
|
|
$this->retrieveUserData(); |
323
|
|
|
|
324
|
|
|
return $this->session_info["userentryid"] ?? ''; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* Get current username. |
329
|
|
|
* |
330
|
|
|
* @return string Current user's username (equal to username passed in logon() ) |
331
|
|
|
*/ |
332
|
|
|
public function getUserName() { |
333
|
|
|
$encryptionStore = EncryptionStore::getInstance(); |
334
|
|
|
|
335
|
|
|
return $encryptionStore->get('username') ?: ''; |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* Get current user's full name. |
340
|
|
|
* |
341
|
|
|
* @return string User's full name |
342
|
|
|
*/ |
343
|
|
|
public function getFullName() { |
344
|
|
|
$this->retrieveUserData(); |
345
|
|
|
|
346
|
|
|
return array_key_exists("fullname", $this->session_info) ? $this->session_info["fullname"] : false; |
|
|
|
|
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Get current user's smtp address. |
351
|
|
|
* |
352
|
|
|
* @return string User's smtp address |
353
|
|
|
*/ |
354
|
|
|
public function getSMTPAddress() { |
355
|
|
|
$this->retrieveUserData(); |
356
|
|
|
|
357
|
|
|
return array_key_exists("smtpaddress", $this->session_info) ? $this->session_info["smtpaddress"] : false; |
|
|
|
|
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* Get current user's email address. |
362
|
|
|
* |
363
|
|
|
* @return string User's email address |
364
|
|
|
*/ |
365
|
|
|
public function getEmailAddress() { |
366
|
|
|
$this->retrieveUserData(); |
367
|
|
|
|
368
|
|
|
return array_key_exists("emailaddress", $this->session_info) ? $this->session_info["emailaddress"] : false; |
|
|
|
|
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* Get current user's image from the LDAP server. |
373
|
|
|
* |
374
|
|
|
* @return string A base64 encoded string (data url) |
375
|
|
|
*/ |
376
|
|
|
public function getUserImage() { |
377
|
|
|
$this->retrieveUserData(); |
378
|
|
|
|
379
|
|
|
return array_key_exists("userimage", $this->session_info) ? $this->session_info["userimage"] : false; |
|
|
|
|
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
public function setUserImage($user_image) { |
383
|
|
|
if ($this->userDataRetrieved && is_array($this->session_info)) { |
384
|
|
|
$this->session_info["userimage"] = $user_image; |
385
|
|
|
} |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
public function getGivenName() { |
389
|
|
|
$this->retrieveUserData(); |
390
|
|
|
|
391
|
|
|
return array_key_exists("given_name", $this->session_info) ? $this->session_info["given_name"] : false; |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
public function getInitials() { |
395
|
|
|
$this->retrieveUserData(); |
396
|
|
|
|
397
|
|
|
return array_key_exists("initials", $this->session_info) ? $this->session_info["initials"] : false; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
public function getSurname() { |
401
|
|
|
$this->retrieveUserData(); |
402
|
|
|
|
403
|
|
|
return array_key_exists("surname", $this->session_info) ? $this->session_info["surname"] : false; |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
public function getStreetAddress() { |
407
|
|
|
$this->retrieveUserData(); |
408
|
|
|
|
409
|
|
|
return array_key_exists("street_address", $this->session_info) ? $this->session_info["street_address"] : false; |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
public function getLocality() { |
413
|
|
|
$this->retrieveUserData(); |
414
|
|
|
|
415
|
|
|
return array_key_exists("locality", $this->session_info) ? $this->session_info["locality"] : false; |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
public function getStateOrProvince() { |
419
|
|
|
$this->retrieveUserData(); |
420
|
|
|
|
421
|
|
|
return array_key_exists("state_or_province", $this->session_info) ? $this->session_info["state_or_province"] : false; |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
public function getPostalCode() { |
425
|
|
|
$this->retrieveUserData(); |
426
|
|
|
|
427
|
|
|
return array_key_exists("postal_code", $this->session_info) ? $this->session_info["postal_code"] : false; |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
public function getCountry() { |
431
|
|
|
$this->retrieveUserData(); |
432
|
|
|
|
433
|
|
|
return array_key_exists("country", $this->session_info) ? $this->session_info["country"] : false; |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
public function getTitle() { |
437
|
|
|
$this->retrieveUserData(); |
438
|
|
|
|
439
|
|
|
return array_key_exists("title", $this->session_info) ? $this->session_info["title"] : false; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
public function getCompanyName() { |
443
|
|
|
$this->retrieveUserData(); |
444
|
|
|
|
445
|
|
|
return array_key_exists("company_name", $this->session_info) ? $this->session_info["company_name"] : false; |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
public function getDepartmentName() { |
449
|
|
|
$this->retrieveUserData(); |
450
|
|
|
|
451
|
|
|
return array_key_exists("department_name", $this->session_info) ? $this->session_info["department_name"] : false; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
public function getOfficeLocation() { |
455
|
|
|
$this->retrieveUserData(); |
456
|
|
|
|
457
|
|
|
return array_key_exists("office_location", $this->session_info) ? $this->session_info["office_location"] : false; |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
public function getAssistant() { |
461
|
|
|
$this->retrieveUserData(); |
462
|
|
|
|
463
|
|
|
return array_key_exists("assistant", $this->session_info) ? $this->session_info["assistant"] : false; |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
public function getAssistantTelephoneNumber() { |
467
|
|
|
$this->retrieveUserData(); |
468
|
|
|
|
469
|
|
|
return array_key_exists("assistant_telephone_number", $this->session_info) ? $this->session_info["assistant_telephone_number"] : false; |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
public function getOfficeTelephoneNumber() { |
473
|
|
|
$this->retrieveUserData(); |
474
|
|
|
|
475
|
|
|
return array_key_exists("office_telephone_number", $this->session_info) ? $this->session_info["office_telephone_number"] : false; |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
public function getBusinessTelephoneNumber() { |
479
|
|
|
$this->retrieveUserData(); |
480
|
|
|
|
481
|
|
|
return array_key_exists("business_telephone_number", $this->session_info) ? $this->session_info["business_telephone_number"] : false; |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
public function getBusiness2TelephoneNumber() { |
485
|
|
|
$this->retrieveUserData(); |
486
|
|
|
|
487
|
|
|
return array_key_exists("business2_telephone_number", $this->session_info) ? $this->session_info["business2_telephone_number"] : false; |
488
|
|
|
} |
489
|
|
|
|
490
|
|
|
public function getPrimaryFaxNumber() { |
491
|
|
|
$this->retrieveUserData(); |
492
|
|
|
|
493
|
|
|
return array_key_exists("primary_fax_number", $this->session_info) ? $this->session_info["primary_fax_number"] : false; |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
public function getHomeTelephoneNumber() { |
497
|
|
|
$this->retrieveUserData(); |
498
|
|
|
|
499
|
|
|
return array_key_exists("home_telephone_number", $this->session_info) ? $this->session_info["home_telephone_number"] : false; |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
public function getHome2TelephoneNumber() { |
503
|
|
|
$this->retrieveUserData(); |
504
|
|
|
|
505
|
|
|
return array_key_exists("home2_telephone_number", $this->session_info) ? $this->session_info["home2_telephone_number"] : false; |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
public function getMobileTelephoneNumber() { |
509
|
|
|
$this->retrieveUserData(); |
510
|
|
|
|
511
|
|
|
return array_key_exists("mobile_telephone_number", $this->session_info) ? $this->session_info["mobile_telephone_number"] : false; |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
public function getPagerTelephoneNumber() { |
515
|
|
|
$this->retrieveUserData(); |
516
|
|
|
|
517
|
|
|
return array_key_exists("pager_telephone_number", $this->session_info) ? $this->session_info["pager_telephone_number"] : false; |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
/** |
521
|
|
|
* Checks whether the user is enabled for grommunio-web. |
522
|
|
|
* |
523
|
|
|
* @return bool |
524
|
|
|
*/ |
525
|
|
|
public function isGwebEnabled() { |
526
|
|
|
$store_props = mapi_getprops($this->getDefaultMessageStore(), [PR_EC_ENABLED_FEATURES_L]); |
527
|
|
|
|
528
|
|
|
return $store_props[PR_EC_ENABLED_FEATURES_L] & UP_WEB; |
|
|
|
|
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
/** |
532
|
|
|
* @return bool true if webapp is disabled feature else return false |
533
|
|
|
*/ |
534
|
|
|
public function isWebappDisableAsFeature() { |
535
|
|
|
return !$this->isGwebEnabled(); |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* Magic method to get properties from the session_info. When a method of this class if called |
540
|
|
|
* and there is no method of this name defined this function will be called |
541
|
|
|
* It creates getter methods for the properties stored in $session_info using the following syntax: |
542
|
|
|
* getSomeUserProperty() will look return a property called some_user_property if it exists and |
543
|
|
|
* throw an exception otherwise. |
544
|
|
|
* |
545
|
|
|
* @param string $methodName The name of the method that was called |
546
|
|
|
* @param array $arguments The arguments that were passed in the call |
547
|
|
|
* |
548
|
|
|
* @return string The requested property if it exists |
549
|
|
|
* |
550
|
|
|
* @throws Exception |
551
|
|
|
*/ |
552
|
|
|
public function __call($methodName, $arguments) { |
553
|
|
|
if (!preg_match('/^get(.+)$/', $methodName, $matches)) { |
554
|
|
|
// We don't know this function, so let's throw an error |
555
|
|
|
throw new Exception('Method ' . $methodName . ' does not exist'); |
556
|
|
|
} |
557
|
|
|
$this->retrieveUserData(); |
558
|
|
|
$propertyName = strtolower((string) preg_replace('/([^A-Z])([A-Z])/', '$1_$2', $matches[1])); |
559
|
|
|
if (!array_key_exists($propertyName, $this->session_info)) { |
560
|
|
|
// We don't know this function, so let's throw an error |
561
|
|
|
throw new Exception('Method ' . $methodName . ' does not exist ' . $propertyName); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
return $this->session_info[$propertyName]; |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
/** |
568
|
|
|
* Returns a hash with information about the user that is logged in. |
569
|
|
|
* |
570
|
|
|
* @return array |
571
|
|
|
*/ |
572
|
|
|
public function getUserInfo() { |
573
|
|
|
return [ |
574
|
|
|
'username' => $this->getUserName(), |
575
|
|
|
'fullname' => $this->getFullName(), |
576
|
|
|
'entryid' => bin2hex($this->getUserEntryid()), |
577
|
|
|
'email_address' => $this->getEmailAddress(), |
578
|
|
|
'smtp_address' => $this->getSMTPAddress(), |
579
|
|
|
'search_key' => bin2hex($this->getSearchKey()), |
580
|
|
|
'user_image' => $this->getUserImage(), |
581
|
|
|
'given_name' => $this->getGivenName(), |
582
|
|
|
'initials' => $this->getInitials(), |
583
|
|
|
'surname' => $this->getSurname(), |
584
|
|
|
'street_address' => $this->getStreetAddress(), |
585
|
|
|
'locality' => $this->getLocality(), |
586
|
|
|
'state_or_province' => $this->getStateOrProvince(), |
587
|
|
|
'postal_code' => $this->getPostalCode(), |
588
|
|
|
'country' => $this->getCountry(), |
589
|
|
|
'title' => $this->getTitle(), |
590
|
|
|
'company_name' => $this->getCompanyName(), |
591
|
|
|
'department_name' => $this->getDepartmentName(), |
592
|
|
|
'office_location' => $this->getOfficeLocation(), |
593
|
|
|
'assistant' => $this->getAssistant(), |
594
|
|
|
'assistant_telephone_number' => $this->getAssistantTelephoneNumber(), |
595
|
|
|
'office_telephone_number' => $this->getOfficeTelephoneNumber(), |
596
|
|
|
'business_telephone_number' => $this->getBusinessTelephoneNumber(), |
597
|
|
|
'business2_telephone_number' => $this->getBusiness2TelephoneNumber(), |
598
|
|
|
'primary_fax_number' => $this->getPrimaryFaxNumber(), |
599
|
|
|
'home_telephone_number' => $this->getHomeTelephoneNumber(), |
600
|
|
|
'home2_telephone_number' => $this->getHome2TelephoneNumber(), |
601
|
|
|
'mobile_telephone_number' => $this->getMobileTelephoneNumber(), |
602
|
|
|
'pager_telephone_number' => $this->getPagerTelephoneNumber(), |
603
|
|
|
]; |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
/** |
607
|
|
|
* Get current user's search key. |
608
|
|
|
* |
609
|
|
|
* @return string Current user's searchkey |
610
|
|
|
*/ |
611
|
|
|
public function getSearchKey() { |
612
|
|
|
$this->retrieveUserData(); |
613
|
|
|
|
614
|
|
|
return $this->session_info["searchkey"] ?? ''; |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
/** |
618
|
|
|
* Get the message stores from the message store table from your session. Standard stores |
619
|
|
|
* like the default store and the public store are made them easily accessible through the |
620
|
|
|
* defaultstore and publicStore properties. |
621
|
|
|
*/ |
622
|
|
|
public function loadMessageStoresFromSession() { |
623
|
|
|
$storestables = mapi_getmsgstorestable($this->session); |
624
|
|
|
$rows = mapi_table_queryallrows($storestables, [PR_ENTRYID, PR_DEFAULT_STORE, PR_MDB_PROVIDER]); |
625
|
|
|
foreach ($rows as $row) { |
626
|
|
|
if (!$row[PR_ENTRYID]) { |
627
|
|
|
continue; |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
if (isset($row[PR_DEFAULT_STORE]) && $row[PR_DEFAULT_STORE] == true) { |
631
|
|
|
$this->defaultstore = $row[PR_ENTRYID]; |
632
|
|
|
} |
633
|
|
|
elseif ($row[PR_MDB_PROVIDER] == ZARAFA_STORE_PUBLIC_GUID) { |
634
|
|
|
$this->publicStore = $row[PR_ENTRYID]; |
635
|
|
|
} |
636
|
|
|
elseif ($row[PR_MDB_PROVIDER] == ZARAFA_STORE_DELEGATE_GUID) { |
637
|
|
|
$eidObj = $GLOBALS["entryid"]->createMsgStoreEntryIdObj($row[PR_ENTRYID]); |
638
|
|
|
if (isset($eidObj['MailboxDN'])) { |
639
|
|
|
$this->openMessageStore($row[PR_ENTRYID], strtolower($eidObj['MailboxDN'])); |
640
|
|
|
} |
641
|
|
|
} |
642
|
|
|
} |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* Get the current user's default message store. |
647
|
|
|
* |
648
|
|
|
* The store is opened only once, subsequent calls will return the previous store object |
649
|
|
|
* |
650
|
|
|
* @param bool reopen force re-open |
|
|
|
|
651
|
|
|
* @param mixed $reopen |
652
|
|
|
* |
653
|
|
|
* @return mapistore User's default message store object |
|
|
|
|
654
|
|
|
*/ |
655
|
|
|
public function getDefaultMessageStore($reopen = false) { |
656
|
|
|
// Return cached default store if we have one |
657
|
|
|
if (!$reopen && isset($this->defaultstore, $this->stores[$this->defaultstore])) { |
658
|
|
|
return $this->stores[$this->defaultstore]; |
659
|
|
|
} |
660
|
|
|
|
661
|
|
|
$this->loadMessageStoresFromSession(); |
662
|
|
|
|
663
|
|
|
return $this->openMessageStore($this->defaultstore, 'Default store'); |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
/** |
667
|
|
|
* The default messagestore entryid. |
668
|
|
|
* |
669
|
|
|
* @return string the entryid of the default messagestore |
670
|
|
|
*/ |
671
|
|
|
public function getDefaultMessageStoreEntryId() { |
672
|
|
|
if (!isset($this->defaultstore)) { |
673
|
|
|
$this->loadMessageStoresFromSession(); |
674
|
|
|
} |
675
|
|
|
|
676
|
|
|
return bin2hex($this->defaultstore); |
677
|
|
|
} |
678
|
|
|
|
679
|
|
|
/** |
680
|
|
|
* Get single store if we are opening full store. |
681
|
|
|
* |
682
|
|
|
* @param object $store the store of the user |
683
|
|
|
* @param array $storeOptions contains folder_type of which folder to open |
684
|
|
|
* It is mapped to username, If folder_type is 'all' (i.e. Open Entire Inbox) |
685
|
|
|
* then we will open full store. |
686
|
|
|
* @param string $username The username |
687
|
|
|
* |
688
|
|
|
* @return array storeArray The array of stores containing user's store |
689
|
|
|
*/ |
690
|
|
|
public function getSingleMessageStores($store, $storeOptions, $username) { |
|
|
|
|
691
|
|
|
return [$store]; |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
/** |
695
|
|
|
* Get the public message store. |
696
|
|
|
* |
697
|
|
|
* The store is opened only once, subsequent calls will return the previous store object |
698
|
|
|
* |
699
|
|
|
* @return mapistore Public message store object |
700
|
|
|
*/ |
701
|
|
|
public function getPublicMessageStore() { |
702
|
|
|
// Return cached public store if we have one |
703
|
|
|
if (isset($this->publicStore, $this->stores[$this->publicStore])) { |
704
|
|
|
return $this->stores[$this->publicStore]; |
705
|
|
|
} |
706
|
|
|
|
707
|
|
|
$this->loadMessageStoresFromSession(); |
708
|
|
|
|
709
|
|
|
return $this->openMessageStore($this->publicStore, 'Public store'); |
710
|
|
|
} |
711
|
|
|
|
712
|
|
|
/** |
713
|
|
|
* Get all message stores currently open in the session. |
714
|
|
|
* |
715
|
|
|
* @return array Associative array with entryid -> mapistore of all open stores (private, public, delegate) |
716
|
|
|
*/ |
717
|
|
|
public function getAllMessageStores() { |
718
|
|
|
$this->getDefaultMessageStore(); |
719
|
|
|
$this->getPublicMessageStore(); |
720
|
|
|
// The cache now contains all the stores in our profile. Next, add the stores |
721
|
|
|
// for other users. |
722
|
|
|
$this->getOtherUserStore(); |
723
|
|
|
|
724
|
|
|
// Just return all the stores in our cache, even if we have some error in mapi |
725
|
|
|
return $this->stores; |
726
|
|
|
} |
727
|
|
|
|
728
|
|
|
/** |
729
|
|
|
* Open the message store with entryid $entryid. |
730
|
|
|
* |
731
|
|
|
* @param string $entryid string representation of the binary entryid of the store |
732
|
|
|
* @param string $name The name of the store. Will be logged when opening fails. |
733
|
|
|
* |
734
|
|
|
* @return mapistore The opened store on success, false otherwise |
735
|
|
|
*/ |
736
|
|
|
public function openMessageStore($entryid, $name = '') { |
737
|
|
|
// Check the cache before opening |
738
|
|
|
foreach ($this->stores as $storeEntryId => $storeObj) { |
739
|
|
|
if ($GLOBALS["entryid"]->compareEntryIds(bin2hex($entryid), bin2hex($storeEntryId))) { |
740
|
|
|
return $storeObj; |
741
|
|
|
} |
742
|
|
|
} |
743
|
|
|
|
744
|
|
|
try { |
745
|
|
|
$store = mapi_openmsgstore($this->session, $entryid); |
746
|
|
|
$store_props = mapi_getprops($store, [PR_ENTRYID]); |
747
|
|
|
$entryid = $store_props[PR_ENTRYID]; |
748
|
|
|
|
749
|
|
|
// Cache the store for later use |
750
|
|
|
$this->stores[$entryid] = $store; |
751
|
|
|
$this->userstores[$name] = $entryid; |
752
|
|
|
} |
753
|
|
|
catch (MAPIException $e) { |
754
|
|
|
error_log('Failed to open store. ' . $this->session_info["username"] . |
755
|
|
|
' requested ' . bin2hex($entryid) . ($name ? " ({$name})" : '')); |
756
|
|
|
|
757
|
|
|
return $e->getCode(); |
|
|
|
|
758
|
|
|
} |
759
|
|
|
catch (Exception $e) { |
760
|
|
|
// mapi_openmsgstore seems to throw another exception than MAPIException |
761
|
|
|
// sometimes, so we add a safety net. |
762
|
|
|
error_log('Failed to open store. ' . $this->session_info["username"] . |
763
|
|
|
' requested ' . bin2hex($entryid) . ($name ? " ({$name})" : '')); |
764
|
|
|
|
765
|
|
|
return $e->getCode(); |
|
|
|
|
766
|
|
|
} |
767
|
|
|
|
768
|
|
|
return $store; |
769
|
|
|
} |
770
|
|
|
|
771
|
|
|
/** |
772
|
|
|
* Get all the available shared stores. |
773
|
|
|
* |
774
|
|
|
* The store is opened only once, subsequent calls will return the previous store object |
775
|
|
|
*/ |
776
|
|
|
public function getOtherUserStore() { |
777
|
|
|
$otherusers = $this->retrieveOtherUsersFromSettings(); |
778
|
|
|
$otherUsersStores = []; |
779
|
|
|
|
780
|
|
|
foreach ($otherusers as $username => $folder) { |
781
|
|
|
if (isset($this->userstores[$username])) { |
782
|
|
|
continue; |
783
|
|
|
} |
784
|
|
|
$storeOk = true; |
785
|
|
|
|
786
|
|
|
if (is_array($folder) && !empty($folder)) { |
787
|
|
|
try { |
788
|
|
|
$user_entryid = mapi_msgstore_createentryid($this->getDefaultMessageStore(), $username); |
789
|
|
|
|
790
|
|
|
$sharedStore = $this->openMessageStore($user_entryid, $username); |
791
|
|
|
if ($sharedStore === false && $sharedStore === ecLoginPerm && |
792
|
|
|
$sharedStore === MAPI_E_CALL_FAILED && $sharedStore === MAPI_E_NOT_FOUND) { |
793
|
|
|
$storeOk = false; |
794
|
|
|
} |
795
|
|
|
} |
796
|
|
|
catch (MAPIException $e) { |
797
|
|
|
if ($e->getCode() == MAPI_E_NOT_FOUND) { |
798
|
|
|
// The user or the corresponding store couldn't be found, |
799
|
|
|
// print an error to the log, and remove the user from the settings. |
800
|
|
|
dump('Failed to load store for user ' . $username . ', user was not found. Removing it from settings.'); |
801
|
|
|
$GLOBALS["settings"]->delete("zarafa/v1/contexts/hierarchy/shared_stores/" . bin2hex($username), true); |
802
|
|
|
} |
803
|
|
|
else { |
804
|
|
|
// That is odd, something else went wrong. Lets not be hasty and preserve |
805
|
|
|
// the user in the settings, but do print something to the log to indicate |
806
|
|
|
// something happened... |
807
|
|
|
dump('Failed to load store for user ' . $username . '. ' . $e->getDisplayMessage()); |
808
|
|
|
} |
809
|
|
|
} |
810
|
|
|
finally { |
811
|
|
|
if (!$storeOk && ($sharedStore == ecLoginPerm || $sharedStore == MAPI_E_NOT_FOUND)) { |
|
|
|
|
812
|
|
|
// The user or the corresponding store couldn't be opened |
813
|
|
|
// (e.g. the user was deleted or permissions revoked), |
814
|
|
|
// print an error to the log, and remove the user from the settings. |
815
|
|
|
dump(sprintf("The user %s failed to load store of the user %s. Removing it from settings.", $this->session_info["username"], $username)); |
816
|
|
|
$GLOBALS["settings"]->delete("zarafa/v1/contexts/hierarchy/shared_stores/" . bin2hex($username), true); |
817
|
|
|
} |
818
|
|
|
} |
819
|
|
|
} |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
foreach ($this->userstores as $entryid) { |
823
|
|
|
$otherUsersStores[$entryid] = $this->stores[$entryid]; |
824
|
|
|
} |
825
|
|
|
|
826
|
|
|
return $otherUsersStores; |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
/** |
830
|
|
|
* Resolve the username strictly by opening that user's store and returning the |
831
|
|
|
* PR_MAILBOX_OWNER_ENTRYID. This can be used for resolving an username without the risk of |
832
|
|
|
* ambiguity since mapi_ab_resolve() does not strictly resolve on the username. |
833
|
|
|
* |
834
|
|
|
* @param string $username The username |
835
|
|
|
* |
836
|
|
|
* @return Binary|int Entryid of the user on success otherwise the hresult error code |
|
|
|
|
837
|
|
|
*/ |
838
|
|
|
public function resolveStrictUserName($username) { |
839
|
|
|
$storeEntryid = mapi_msgstore_createentryid($this->getDefaultMessageStore(), $username); |
840
|
|
|
$store = $this->openMessageStore($storeEntryid, $username); |
841
|
|
|
$storeProps = mapi_getprops($store, [PR_MAILBOX_OWNER_ENTRYID]); |
842
|
|
|
|
843
|
|
|
return $storeProps[PR_MAILBOX_OWNER_ENTRYID]; |
844
|
|
|
} |
845
|
|
|
|
846
|
|
|
/** |
847
|
|
|
* Get other users from settings. |
848
|
|
|
* |
849
|
|
|
* @return array Array of usernames of delegate stores |
850
|
|
|
*/ |
851
|
|
|
public function retrieveOtherUsersFromSettings() { |
852
|
|
|
$other_users = $GLOBALS["settings"]->get("zarafa/v1/contexts/hierarchy/shared_stores", []); |
853
|
|
|
$result = []; |
854
|
|
|
foreach ($other_users as $username => $folders) { |
855
|
|
|
// No folders are being shared, the store has probably been closed by the user, |
856
|
|
|
// but the username is still lingering in the settings... |
857
|
|
|
if (!isset($folders) || empty($folders)) { |
858
|
|
|
continue; |
859
|
|
|
} |
860
|
|
|
|
861
|
|
|
$username = strtolower(hex2bin((string) $username)); |
862
|
|
|
if (!isset($result[$username])) { |
863
|
|
|
$result[$username] = []; |
864
|
|
|
} |
865
|
|
|
|
866
|
|
|
foreach ($folders as $folder) { |
867
|
|
|
if (is_array($folder)) { |
868
|
|
|
$result[$username][$folder["folder_type"]] = []; |
869
|
|
|
$result[$username][$folder["folder_type"]]["folder_type"] = $folder["folder_type"]; |
870
|
|
|
$result[$username][$folder["folder_type"]]["show_subfolders"] = $folder["show_subfolders"]; |
871
|
|
|
} |
872
|
|
|
} |
873
|
|
|
} |
874
|
|
|
|
875
|
|
|
return $result; |
876
|
|
|
} |
877
|
|
|
|
878
|
|
|
/** |
879
|
|
|
* Add the store of another user to the list of other user stores. |
880
|
|
|
* |
881
|
|
|
* @param string $username The username whose store should be added to the list of other users' stores |
882
|
|
|
* |
883
|
|
|
* @return mapistore The store of the user or false on error; |
884
|
|
|
*/ |
885
|
|
|
public function addUserStore($username) { |
886
|
|
|
$user_entryid = mapi_msgstore_createentryid($this->getDefaultMessageStore(), $username); |
887
|
|
|
|
888
|
|
|
if ($user_entryid) { |
889
|
|
|
// mapi_msgstore_createentryid and mapi_getprops(PR_ENTRYID) have different |
890
|
|
|
// values for shared stores, so save the one from mapi_getprops(PR_ENTRYID) |
891
|
|
|
// $this->userstores[$username] = $user_entryid; |
892
|
|
|
|
893
|
|
|
return $this->openMessageStore($user_entryid, $username); |
894
|
|
|
} |
895
|
|
|
} |
896
|
|
|
|
897
|
|
|
/** |
898
|
|
|
* Remove the store of another user from the list of other user stores. |
899
|
|
|
* |
900
|
|
|
* @param string $username The username whose store should be deleted from the list of other users' stores |
901
|
|
|
* |
902
|
|
|
* @return string The entryid of the store which was removed |
903
|
|
|
*/ |
904
|
|
|
public function removeUserStore($username) { |
905
|
|
|
// Remove the reference to the store if we had one |
906
|
|
|
if (isset($this->userstores[$username])) { |
907
|
|
|
$entryid = $this->userstores[$username]; |
908
|
|
|
unset($this->userstores[$username], $this->stores[$entryid]); |
909
|
|
|
|
910
|
|
|
return $entryid; |
911
|
|
|
} |
912
|
|
|
} |
913
|
|
|
|
914
|
|
|
/** |
915
|
|
|
* Get the store entryid of the specified user. |
916
|
|
|
* |
917
|
|
|
* The store must have been previously added via addUserStores. |
918
|
|
|
* |
919
|
|
|
* @param string $username The username whose store is being looked up |
920
|
|
|
* |
921
|
|
|
* @return string The entryid of the store of the user |
922
|
|
|
*/ |
923
|
|
|
public function getStoreEntryIdOfUser($username) { |
924
|
|
|
return $this->userstores[$username]; |
925
|
|
|
} |
926
|
|
|
|
927
|
|
|
/** |
928
|
|
|
* Get the username of the user store. |
929
|
|
|
* |
930
|
|
|
* @param string $username the loginname of whom we want to full name |
931
|
|
|
* |
932
|
|
|
* @return string the display name of the user |
933
|
|
|
*/ |
934
|
|
|
public function getDisplayNameofUser($username) { |
935
|
|
|
$user_entryid = $this->getStoreEntryIdOfUser($username); |
936
|
|
|
$store = $this->openMessageStore($user_entryid, $username); |
937
|
|
|
$props = mapi_getprops($store, [PR_DISPLAY_NAME]); |
938
|
|
|
|
939
|
|
|
return str_replace('Inbox - ', '', $props[PR_DISPLAY_NAME]); |
940
|
|
|
} |
941
|
|
|
|
942
|
|
|
/** |
943
|
|
|
* Get the username of the owner of the specified store. |
944
|
|
|
* |
945
|
|
|
* The store must have been previously added via addUserStores. |
946
|
|
|
* |
947
|
|
|
* @param string $entryid EntryID of the store |
948
|
|
|
* |
949
|
|
|
* @return string Username of the specified store or false if it is not found |
950
|
|
|
*/ |
951
|
|
|
public function getUserNameOfStore($entryid) { |
952
|
|
|
foreach ($this->userstores as $username => $storeentryid) { |
953
|
|
|
if ($GLOBALS["entryid"]->compareEntryIds(bin2hex((string) $storeentryid), bin2hex($entryid))) { |
954
|
|
|
return $username; |
955
|
|
|
} |
956
|
|
|
} |
957
|
|
|
|
958
|
|
|
return false; |
|
|
|
|
959
|
|
|
} |
960
|
|
|
|
961
|
|
|
/** |
962
|
|
|
* Open a MAPI message using session object. |
963
|
|
|
* The function is used to open message when we don't know |
964
|
|
|
* the specific store and we want to open message using entryid. |
965
|
|
|
* |
966
|
|
|
* @param string $entryid entryid of the message |
967
|
|
|
* |
968
|
|
|
* @return object MAPI Message |
969
|
|
|
*/ |
970
|
|
|
public function openMessage($entryid) { |
971
|
|
|
return mapi_openentry($this->session, $entryid); |
972
|
|
|
} |
973
|
|
|
|
974
|
|
|
/** |
975
|
|
|
* Setup the contact provider for the addressbook. It asks getContactFoldersForABContactProvider |
976
|
|
|
* for the entryids and display names for the contact folders in the user's store. |
977
|
|
|
* |
978
|
|
|
* @param bool $loadSharedContactsProvider when set to true it denotes that shared folders are |
979
|
|
|
* required to be configured to load the contacts from |
980
|
|
|
*/ |
981
|
|
|
public function setupContactProviderAddressbook($loadSharedContactsProvider) { |
982
|
|
|
$profsect = mapi_openprofilesection($GLOBALS['mapisession']->getSession(), pbGlobalProfileSectionGuid); |
983
|
|
|
if ($profsect) { |
984
|
|
|
// Get information about all contact folders from own store, shared stores and public store |
985
|
|
|
$defaultStore = $this->getDefaultMessageStore(); |
986
|
|
|
$contactFolders = $this->getContactFoldersForABContactProvider($defaultStore); |
987
|
|
|
|
988
|
|
|
// include shared contact folders in addressbook if shared contact folders are enabled |
989
|
|
|
if (ENABLE_SHARED_CONTACT_FOLDERS && $loadSharedContactsProvider) { |
990
|
|
|
if (empty($this->userstores)) { |
991
|
|
|
$this->getOtherUserStore(); |
992
|
|
|
} |
993
|
|
|
|
994
|
|
|
$sharedSetting = $GLOBALS["settings"]->get("zarafa/v1/contexts/hierarchy/shared_stores", []); |
995
|
|
|
// Find available contact folders from all user stores, one by one. |
996
|
|
|
foreach ($this->userstores as $username => $storeEntryID) { |
997
|
|
|
$userContactFolders = []; |
998
|
|
|
$sharedUserSetting = []; |
999
|
|
|
$openedUserStore = $this->openMessageStore($storeEntryID, $username); |
1000
|
|
|
|
1001
|
|
|
// Get settings of respective shared folder of given user |
1002
|
|
|
if (array_key_exists(strtolower(bin2hex($username)), $sharedSetting)) { |
1003
|
|
|
$sharedUserSetting = $sharedSetting[strtolower(bin2hex($username))]; |
1004
|
|
|
} |
1005
|
|
|
|
1006
|
|
|
// Only add opened shared folders into addressbook contacts provider. |
1007
|
|
|
// If entire inbox is opened then add each and every contact folders of that particular user. |
1008
|
|
|
if (isset($sharedUserSetting['all'])) { |
1009
|
|
|
$userContactFolders = $this->getContactFoldersForABContactProvider($openedUserStore); |
1010
|
|
|
} |
1011
|
|
|
elseif (isset($sharedUserSetting['contact'])) { |
1012
|
|
|
// Add respective default contact folder which is opened. |
1013
|
|
|
// Get entryid of default contact folder from root. |
1014
|
|
|
$root = mapi_msgstore_openentry($openedUserStore); |
1015
|
|
|
$rootProps = mapi_getprops($root, [PR_IPM_CONTACT_ENTRYID]); |
1016
|
|
|
|
1017
|
|
|
// Just add the default contact folder only. |
1018
|
|
|
$defaultContactFolder = [ |
1019
|
|
|
PR_STORE_ENTRYID => $storeEntryID, |
1020
|
|
|
PR_ENTRYID => $rootProps[PR_IPM_CONTACT_ENTRYID], |
1021
|
|
|
PR_DISPLAY_NAME => _("Contacts"), |
1022
|
|
|
]; |
1023
|
|
|
array_push($userContactFolders, $defaultContactFolder); |
1024
|
|
|
|
1025
|
|
|
// Go for sub folders only if configured in settings |
1026
|
|
|
if ($sharedUserSetting['contact']['show_subfolders'] == true) { |
1027
|
|
|
$subContactFolders = $this->getContactFolders($openedUserStore, $rootProps[PR_IPM_CONTACT_ENTRYID], true); |
|
|
|
|
1028
|
|
|
if (is_array($subContactFolders)) { |
1029
|
|
|
$userContactFolders = array_merge($userContactFolders, $subContactFolders); |
1030
|
|
|
} |
1031
|
|
|
} |
1032
|
|
|
} |
1033
|
|
|
|
1034
|
|
|
// Postfix display name of every contact folder with respective owner name |
1035
|
|
|
// it is mandatory to keep display-name different |
1036
|
|
|
$userStoreProps = mapi_getprops($openedUserStore, [PR_MAILBOX_OWNER_NAME]); |
1037
|
|
|
for ($i = 0,$len = count($userContactFolders); $i < $len; ++$i) { |
1038
|
|
|
$userContactFolders[$i][PR_DISPLAY_NAME] = $userContactFolders[$i][PR_DISPLAY_NAME] . " - " . $userStoreProps[PR_MAILBOX_OWNER_NAME]; |
1039
|
|
|
} |
1040
|
|
|
|
1041
|
|
|
$contactFolders = array_merge($contactFolders, $userContactFolders); |
1042
|
|
|
} |
1043
|
|
|
} |
1044
|
|
|
|
1045
|
|
|
// Include public contact folders in addressbook if public folders and public contacts folders are enabled |
1046
|
|
|
if (ENABLE_PUBLIC_CONTACT_FOLDERS && ENABLE_PUBLIC_FOLDERS) { |
1047
|
|
|
$publicStore = $this->getPublicMessageStore(); |
1048
|
|
|
if ($publicStore !== false) { |
|
|
|
|
1049
|
|
|
$contactFolders = array_merge($contactFolders, $this->getContactFoldersForABContactProvider($publicStore)); |
1050
|
|
|
} |
1051
|
|
|
} |
1052
|
|
|
// TODO: The shared stores are not opened as there still is a bug that does not allow resolving from shared contact folders |
1053
|
|
|
|
1054
|
|
|
// These lists will be used to put set in the profile section |
1055
|
|
|
$contact_store_entryids = []; |
1056
|
|
|
$contact_folder_entryids = []; |
1057
|
|
|
$contact_folder_names = []; |
1058
|
|
|
|
1059
|
|
|
// Create the lists of store entryids, folder entryids and folder names to be added |
1060
|
|
|
// to the profile section |
1061
|
|
|
for ($i = 0, $len = count($contactFolders); $i < $len; ++$i) { |
1062
|
|
|
$contact_store_entryids[] = $contactFolders[$i][PR_STORE_ENTRYID]; |
1063
|
|
|
$contact_folder_entryids[] = $contactFolders[$i][PR_ENTRYID]; |
1064
|
|
|
$contact_folder_names[] = $contactFolders[$i][PR_DISPLAY_NAME]; |
1065
|
|
|
} |
1066
|
|
|
|
1067
|
|
|
if (!empty($contact_store_entryids)) { |
1068
|
|
|
// add the defaults contacts folder in the addressbook hierarchy under 'Contacts Folders' |
1069
|
|
|
mapi_setprops($profsect, [PR_ZC_CONTACT_STORE_ENTRYIDS => $contact_store_entryids, |
1070
|
|
|
PR_ZC_CONTACT_FOLDER_ENTRYIDS => $contact_folder_entryids, |
1071
|
|
|
PR_ZC_CONTACT_FOLDER_NAMES => $contact_folder_names, ]); |
1072
|
|
|
} |
1073
|
|
|
} |
1074
|
|
|
} |
1075
|
|
|
|
1076
|
|
|
/** |
1077
|
|
|
* Get the store entryid, folder entryid and display name of the contact folders in the |
1078
|
|
|
* user's store. It returns an array prepared by getContactFolders. |
1079
|
|
|
* |
1080
|
|
|
* @param mapiStore $store The mapi store to look for folders in |
|
|
|
|
1081
|
|
|
* |
1082
|
|
|
* @return array Contact folder information |
1083
|
|
|
*/ |
1084
|
|
|
public function getContactFoldersForABContactProvider($store) { |
1085
|
|
|
$storeProps = mapi_getprops($store, [PR_ENTRYID, PR_MDB_PROVIDER, PR_IPM_SUBTREE_ENTRYID, PR_IPM_PUBLIC_FOLDERS_ENTRYID]); |
1086
|
|
|
$contactFolders = []; |
|
|
|
|
1087
|
|
|
|
1088
|
|
|
try { |
1089
|
|
|
// Only searches one level deep, otherwise deleted contact folders will also be included. |
1090
|
|
|
$contactFolders = $this->getContactFolders($store, $storeProps[PR_IPM_SUBTREE_ENTRYID], $storeProps[PR_MDB_PROVIDER] === ZARAFA_STORE_PUBLIC_GUID ? true : false); |
|
|
|
|
1091
|
|
|
} |
1092
|
|
|
catch (Exception) { |
1093
|
|
|
return $contactFolders; |
1094
|
|
|
} |
1095
|
|
|
|
1096
|
|
|
// Need to search all the contact-subfolders within first level contact folders. |
1097
|
|
|
if ($storeProps[PR_MDB_PROVIDER] != ZARAFA_STORE_PUBLIC_GUID) { |
1098
|
|
|
$firstLevelHierarchyNodes = $contactFolders; |
1099
|
|
|
foreach ($firstLevelHierarchyNodes as $firstLevelNode) { |
1100
|
|
|
// To search for multiple levels CONVENIENT_DEPTH needs to be passed as well. |
1101
|
|
|
$contactFolders = array_merge($contactFolders, $this->getContactFolders($store, $firstLevelNode[PR_ENTRYID], true)); |
|
|
|
|
1102
|
|
|
} |
1103
|
|
|
} |
1104
|
|
|
|
1105
|
|
|
return $contactFolders; |
1106
|
|
|
} |
1107
|
|
|
|
1108
|
|
|
/** |
1109
|
|
|
* Get the store entryid, folder entryid and display name of the contact folders from within given folder, in the |
1110
|
|
|
* user's store. It provides an array where each item contains the information of a folder |
1111
|
|
|
* formatted like this: |
1112
|
|
|
* Array( |
1113
|
|
|
* PR_STORE_ENTRYID => '1234567890ABCDEF', |
1114
|
|
|
* PR_ENTRYID => '1234567890ABCDEF', |
1115
|
|
|
* PR_DISPLAY_NAME => 'Contact folder' |
1116
|
|
|
* ). |
1117
|
|
|
* |
1118
|
|
|
* @param mapiStore $store The mapi store of the user |
1119
|
|
|
* @param string $folderEntryid EntryID of the folder to look for contact folders in |
1120
|
|
|
* @param int $depthSearch flag to search into all the folder levels |
1121
|
|
|
* |
1122
|
|
|
* @return array an array in which founded contact-folders will be pushed |
1123
|
|
|
*/ |
1124
|
|
|
public function getContactFolders($store, $folderEntryid, $depthSearch) { |
1125
|
|
|
$restriction = [RES_CONTENT, |
1126
|
|
|
[ |
1127
|
|
|
// Fuzzylevel PF_PREFIX also allows IPF.Contact.Custom folders to be included. |
1128
|
|
|
// Otherwise FL_FULLSTRING would only allow IPF.Contact folders. |
1129
|
|
|
FUZZYLEVEL => FL_PREFIX, |
1130
|
|
|
ULPROPTAG => PR_CONTAINER_CLASS, |
1131
|
|
|
VALUE => [ |
1132
|
|
|
PR_CONTAINER_CLASS => "IPF.Contact", |
1133
|
|
|
], |
1134
|
|
|
], |
1135
|
|
|
]; |
1136
|
|
|
|
1137
|
|
|
// Set necessary flag(s) to search considering all the sub folders or not |
1138
|
|
|
$depthFlag = MAPI_DEFERRED_ERRORS; |
1139
|
|
|
if ($depthSearch) { |
1140
|
|
|
$depthFlag |= CONVENIENT_DEPTH; |
1141
|
|
|
} |
1142
|
|
|
|
1143
|
|
|
$hierarchyFolder = mapi_msgstore_openentry($store, $folderEntryid); |
1144
|
|
|
|
1145
|
|
|
// Filter-out contact folders only |
1146
|
|
|
$contactFolderTable = mapi_folder_gethierarchytable($hierarchyFolder, $depthFlag); |
1147
|
|
|
mapi_table_restrict($contactFolderTable, $restriction, TBL_BATCH); |
1148
|
|
|
|
1149
|
|
|
return mapi_table_queryallrows($contactFolderTable, [PR_STORE_ENTRYID, PR_ENTRYID, PR_DISPLAY_NAME, PR_PARENT_ENTRYID, PR_DEPTH]); |
1150
|
|
|
} |
1151
|
|
|
|
1152
|
|
|
/** |
1153
|
|
|
* Obtains server version from the PR_EC_SERVER_VERSION property. |
1154
|
|
|
*/ |
1155
|
|
|
public function getServerVersion() { |
1156
|
|
|
$props = mapi_getprops($this->getDefaultMessageStore(), [PR_EC_SERVER_VERSION]); |
1157
|
|
|
if (propIsError(PR_EC_SERVER_VERSION, $props) === MAPI_E_NOT_FOUND) { |
1158
|
|
|
return ''; |
1159
|
|
|
} |
1160
|
|
|
|
1161
|
|
|
return $props[PR_EC_SERVER_VERSION]; |
1162
|
|
|
} |
1163
|
|
|
|
1164
|
|
|
/** |
1165
|
|
|
* Checks if the entryid is of the public store. |
1166
|
|
|
* |
1167
|
|
|
* @param string $entryid |
1168
|
|
|
* |
1169
|
|
|
* @return bool true if public store entryid false otherwise |
1170
|
|
|
*/ |
1171
|
|
|
public function isPublicStore($entryid) { |
1172
|
|
|
return $GLOBALS["entryid"]->compareEntryIds(bin2hex($this->publicStore), $entryid); |
1173
|
|
|
} |
1174
|
|
|
} |
1175
|
|
|
|
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..