|
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..