Issues (4868)

mail/inc/class.mail_acl.inc.php (13 issues)

1
<?php
2
/**
3
 * EGroupware - Mail Folder ACL- interface class
4
 *
5
 * @link http://www.egroupware.org
6
 * @package mail
7
 * @author Hadi Nategh [[email protected]]
8
 * @copyright (c) 2013-16 by EGroupware GmbH <info-AT-egroupware.org>
9
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10
 * @version $Id$
11
 */
12
13
/*
14
 * Reference: RFC 4314 DOCUMENTATION - RIGHTS (https://tools.ietf.org/html/rfc4314)
15
 *
16
 * Standard Rights:
17
 *
18
 * The currently defined standard rights are (note that the list below
19
 * doesn't list all commands that use a particular right):
20
 *
21
 * l - lookup (mailbox is visible to LIST/LSUB commands, SUBSCRIBE mailbox)
22
 * r - read (SELECT the mailbox, perform STATUS)
23
 * s - keep seen/unseen information across sessions (set or clear \SEEN flag
24
 *     via STORE, also set \SEEN during APPEND/COPY/ FETCH BODY[...])
25
 * w - write (set or clear flags other than \SEEN and \DELETED via
26
 *     STORE, also set them during APPEND/COPY)
27
 * i - insert (perform APPEND, COPY into mailbox)
28
 * p - post (send mail to submission address for mailbox,
29
 *     not enforced by IMAP4 itself)
30
 * k - create mailboxes (CREATE new sub-mailboxes in any
31
 *     implementation-defined hierarchy, parent mailbox for the new
32
 *     mailbox name in RENAME)
33
 * x - delete mailbox (DELETE mailbox, old mailbox name in RENAME)
34
 * t - delete messages (set or clear \DELETED flag via STORE, set
35
 *     \DELETED flag during APPEND/COPY)
36
 * e - perform EXPUNGE and expunge as a part of CLOSE
37
 * a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS)
38
 *
39
 *
40
 *
41
 * Obsolete Rights:
42
 *
43
 * Due to ambiguity in RFC 2086, some existing RFC 2086 server
44
 * implementations use the "c" right to control the DELETE command.
45
 * Others chose to use the "d" right to control the DELETE command.  For
46
 * the former group, let's define the "create" right as union of the "k"
47
 * and "x" rights, and the "delete" right as union of the "e" and "t"
48
 * rights.  For the latter group, let's define the "create" rights as a
49
 * synonym to the "k" right, and the "delete" right as union of the "e",
50
 * "t", and "x" rights.
51
 * For compatibility with RFC 2086, this section defines two virtual
52
 * rights "d" and "c".
53
 * If a client includes the "d" right in a rights list, then it MUST be
54
 * treated as if the client had included every member of the "delete"
55
 * right.  (It is not an error for a client to specify both the "d"
56
 * right and one or more members of the "delete" right, but the effect
57
 * is no different than if just the "d" right or all members of the
58
 * "delete" right had been specified.)
59
 *
60
 */
61
62
63
use EGroupware\Api;
64
use EGroupware\Api\Framework;
65
use EGroupware\Api\Etemplate;
66
use EGroupware\Api\Mail;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Mail. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
67
68
class mail_acl
69
{
70
	/**
71
	 * Methods callable via menuaction
72
	 *
73
	 * @var array
74
	 */
75
	var $public_functions = array(
76
		'edit'	=> True,
77
	);
78
79
	/**
80
	 * static used define abbreviations for common access rights
81
	 *
82
	 * @array
83
	 *
84
	 */
85
	var $aclRightsAbbrvs = array(
86
		'lrs'		=> array('label'=>'readable','title'=>'Allows a user to read the contents of the mailbox.'),
87
		'lprs'		=> array('label'=>'post','title'=>'Allows a user to read the mailbox and post to it through the delivery system by sending mail to the submission address of the mailbox.'),
88
		'ilprs'		=> array('label'=>'append','title'=>'Allows a user to read the mailbox and append messages to it, either via IMAP or through the delivery system.'),
89
		'ilprsw'	=> array('label'=>'write','title'=>'Allows a user to read and write the maibox, post to it, append messages to it.'),
90
		'eilprswtk'	=> array('label'=>'write & delete','title'=>'Allows a user to read, write and create folders and mails, post to it, append messages to it and delete messages.'),
91
		'aeiklprstwx'=> array('label'=>'all','title'=>'The user has all possible rights on the mailbox. This is usually granted to users only on the mailboxes they own.'),
92
		'custom'	=> array('label'=>'custom','title'=>'User defined combination of rights for the ACL'),
93
	);
94
95
	/**
96
	 * imap object instantiated in constructor for account to edit
97
	 *
98
	 * @var Mail\Imap
99
	 */
100
	var $imap;
101
102
	/**
103
	 *
104
	 * @var mail_account
0 ignored issues
show
The type mail_account was not found. Maybe you did not declare it correctly or list all dependencies?

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

filter:
    dependency_paths: ["lib/*"]

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

Loading history...
105
	 */
106
	var $current_account;
107
108
	/**
109
	 * Edit folder ACLs of account(s)
110
	 *
111
	 * @param array $content = null
112
	 * @param string $msg = ''
113
	 *
114
	 */
115
	function edit(array $content=null ,$msg='')
116
	{
117
		$tmpl = new Etemplate('mail.acl');
118
		if (!is_array($content))
119
		{
120
			$acc_id = $_GET['acc_id']?$_GET['acc_id']:$GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'];
121
			if (isset($_GET['account_id']) && !isset($GLOBALS['egw_info']['user']['apps']['admin']))
122
			{
123
				Framework::window_close(lang('Permission denied'));
124
			}
125
			$account_id = $_GET['account_id'];
126
		}
127
		else
128
		{
129
			$acc_id = $content['acc_id'];
130
			$account_id = $content['account_id'];
131
		}
132
		$account = Mail\Account::read($acc_id, $account_id);
133
		$this->imap = $account->imapServer(isset($account_id) ? (int)$account_id : false);
134
135
		$mailbox = $_GET['mailbox']? base64_decode($_GET['mailbox']): self::_extract_mailbox($content['mailbox'], $acc_id);
136
		if (empty($mailbox))
137
		{
138
			$mailbox = $this->imap->isAdminConnection ? $this->imap->getUserMailboxString($account_id) : 'INBOX';
139
		}
140
		if (!$this->imap->isAdminConnection)
141
		{
142
			$tmpl->setElementAttribute('mailbox', 'autocomplete_url', 'mail.mail_compose.ajax_searchFolder');
143
			$tmpl->setElementAttribute('mailbox', 'autocomplete_params', array('mailaccount' => $acc_id));
144
		}
145
		else
146
		{
147
			//Todo: Implement autocomplete_url function with admin stuffs consideration
148
		}
149
		// Unset the content if folder is changed, in order to read acl rights for new selected folder
150
		if (!is_array($content['button']) && self::_extract_mailbox($content['mailbox'], $acc_id) && !is_array($content['grid']['delete'])) unset($content);
151
152
		if (!is_array($content))
153
		{
154
			if (!empty($mailbox))
155
			{
156
				$content['mailbox'] = $mailbox;
157
				$acl = (array)$this->retrieve_acl($mailbox, $msg);
158
				if ($acl[0] === FALSE)
159
				{
160
					Api\Framework::window_close($msg);
161
				}
162
				$n = 1;
163
				foreach ($acl as $key => $value)
164
				{
165
					$virtuals = array_pop(array_values((array)$value));
0 ignored issues
show
array_values((array)$value) cannot be passed to array_pop() as the parameter $array expects a reference. ( Ignorable by Annotation )

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

165
					$virtuals = array_pop(/** @scrutinizer ignore-type */ array_values((array)$value));
Loading history...
166
					$rights = array_shift(array_values((array)$value));
167
168
					foreach ($rights as $right)
169
					{
170
						$content['grid'][$n]['acl_'. $right] = true;
171
					}
172
					$virtualD = array('e','t');
173
					$content['grid'][$n]['acl_c'] = array_diff($virtuals['c'],array_intersect($rights,$virtuals['c']))? false: true; //c=kx more information rfc4314, Obsolote Rights
174
					$content['grid'][$n]['acl_d'] = array_diff($virtualD,array_intersect($rights,$virtuals['d']))? false: true; //d=et more information rfc4314, Obsolote Rights
175
176
					sort($rights);
177
					$acl_abbrvs = implode('',$rights);
178
179
					if (array_key_exists($acl_abbrvs, $this->aclRightsAbbrvs))
180
					{
181
						$content['grid'][$n]['acl'] = $acl_abbrvs;
182
					}
183
					else
184
					{
185
						$content['grid'][$n]['acl'] = 'custom';
186
					}
187
					if (($user = $this->imap->getMailBoxAccountId($key)))
188
					{
189
						$content['grid'][$n++]['acc_id'] = $user;
190
					}
191
					else
192
					{
193
						$content['grid'][$n++]['acc_id'] = $key;
194
					}
195
				}
196
				//error_log(__METHOD__."() acl=".array2string($acl).' --> grid='.array2string($content['grid']));
197
			}
198
			//Set the acl entry in the last row with lrs as default ACL
199
			array_push($content['grid'], array(
200
				'acc_id'=>'',
201
				'acl_l' => true,
202
				'acl_r' => true,
203
				'acl_s' => true));
204
		}
205
		else
206
		{
207
			$button = @key($content['button']);
208
			if (!empty ($content['grid']['delete']))
209
			{
210
				$button = 'delete';
211
			}
212
			$data = $content;
213
			$data['mailbox'] = self::_extract_mailbox($content['mailbox'], $acc_id);
214
			switch ($button)
215
			{
216
				case 'save':
217
				case 'apply':
218
					if ($content)
219
					{
220
						$validation_err = $this->update_acl($data,$msg);
221
						if ($validation_err)
0 ignored issues
show
Bug Best Practice introduced by
The expression $validation_err of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
222
						{
223
							foreach ($validation_err as &$row)
224
							{
225
								$tmpl->set_validation_error('grid['.$row.']'.'[acc_id]', "You must fill this field!");
226
							}
227
						}
228
229
						//Add new row at the end
230
						if ($content['grid'][count($content['grid'])]['acc_id'])
231
							array_push($content['grid'], array('acc_id'=>''));
232
					}
233
					else
234
					{
235
						$msg .= "\n".lang("Error: Could not save ACL").' '.lang("reason!");
236
					}
237
					//Send message
238
					Framework::message($msg);
239
					if ($button == "apply") break;
240
					Framework::window_close();
241
					exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
242
243
				case 'delete':
244
					$aclRvmCnt = $this->remove_acl($data, $msg);
245
					if (is_array($aclRvmCnt))
246
					{
247
						$content['grid'] = $aclRvmCnt;
248
					}
249
					else
250
					{
251
						error_log(__METHOD__.__LINE__. "()" . "The remove_acl suppose to return an array back, something is wrong there");
252
					}
253
					Framework::message($msg);
254
			}
255
		}
256
		$readonlys = $sel_options = array();
257
		$sel_options['acl'] = $this->aclRightsAbbrvs;
258
259
		//Make the account owner's fields all readonly as owner has all rights and should not be able to change them
260
		foreach($content['grid'] as $key => $fields)
261
		{
262
			if (self::_extract_acc_id($fields['acc_id']) == $this->imap->acc_imap_username ||
263
					$this->imap->getMailBoxUserName(self::_extract_acc_id($fields['acc_id'])) == $this->imap->acc_imap_username)
264
			{
265
				foreach (array_keys($fields) as $index)
266
				{
267
					$readonlys['grid'][$key][$index] = true;
268
				}
269
				$readonlys['grid']['delete['.$key.']'] = true;
270
				$readonlys['grid'][$key]['acl_recursive'] = true;
271
				$preserv ['grid'][$key] = $fields;
272
				$preserv['grid'][$key]['acl_recursive'] = false;
273
			}
274
			if (count($content['grid']) != $key)
275
			{
276
				$preserv ['grid'][$key]['acc_id'] = self::_extract_acc_id($fields['acc_id']);
277
				$preserv['grid'][$key]['acl_recursive'] = false;
278
				$readonlys['grid'][$key]['acc_id'] = true;
279
			}
280
		}
281
		//Make entry row's delete button readonly
282
		$readonlys['grid']['delete['.count($content['grid']).']'] = true;
283
284
		$preserv['mailbox'] = $content['mailbox'];
285
		$preserv['acc_id'] = $acc_id;
286
		$preserv['account_id'] = $account_id;
287
		$content['grid']['account_type'] = $this->imap->supportsGroupAcl() ? 'both' : 'accounts';
288
289
		// set a custom autocomplete method for mailbox taglist
290
		if ($account_id)
291
		{
292
			$tmpl->setElementAttribute('mailbox', 'autocomplete_url', __CLASS__.'::ajax_folders');
293
			$tmpl->setElementAttribute('mailbox', 'autocomplete_params', array(
294
				'acc_id' => $acc_id,
295
				'account_id' => $account_id,
296
			));
297
		}
298
299
		$tmpl->exec('mail.mail_acl.edit', $content, $sel_options, $readonlys, $preserv,2);
300
	}
301
302
	/**
303
	 * Autocomplete for folder taglist
304
	 *
305
	 * @throws Api\Exception\NoPermission\Admin
306
	 */
307
	public static function ajax_folders()
308
	{
309
		if (!empty($_GET['account_id']) && !$GLOBALS['egw_info']['user']['apps']['admin'])
310
		{
311
			throw new Api\Exception\NoPermission\Admin;
312
		}
313
		$account = Mail\Account::read($_GET['acc_id'], $_GET['account_id']);
314
		$imap = $account->imapServer(!empty($_GET['account_id']) ? (int)$_GET['account_id'] : false);
315
		$mailbox = $imap->isAdminConnection ? $imap->getUserMailboxString($imap->isAdminConnection) : 'INBOX';
316
317
		$folders = array();
318
		foreach(self::getSubfolders($mailbox, $imap) as $folder)
319
		{
320
			if (stripos($folder, $_GET['query']) !== false)
321
			{
322
				$folders[] = array(
323
					'id' => $folder,
324
					'label' => $folder,
325
				);
326
			}
327
		}
328
		// switch regular JSON response handling off
329
		Api\Json\Request::isJSONRequest(false);
330
331
		header('Content-Type: application/json; charset=utf-8');
332
		echo json_encode($folders);
333
334
		exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
335
	}
336
337
    /**
338
     * Update ACL rights of a folder or including subfolders for an account(s)
339
     *
340
     * @param array $content content including the acl rights
341
     * @param string $msg Message
342
     *
343
     * @return Array | void return array of validation messages or nothing
344
     */
345
	function update_acl ($content, &$msg)
346
	{
347
		$validator = array();
348
349
		foreach ($content['grid'] as $keys => $value)
350
		{
351
			$recursive = $value['acl_recursive'];
352
			unset($value['acc_id']);
353
			unset($value['acl_recursive']);
354
			unset($value['acl']);
355
356
			$options = array();
357
			foreach (array_keys($value) as $key)
358
			{
359
				if ($value[$key] == true)
360
				{
361
					$right = explode("acl_" ,$key);
362
					if ($right[1] === 'c') $right[1] = 'kx'; // c = kx , rfc 4314
363
					if ($right[1] === 'd') $right[1] = 'et'; // d = et , rfc 4314
364
					$options['rights'] .=  $right[1];
365
				}
366
			}
367
			$username = self::_extract_acc_id($content['grid'][$keys]['acc_id']);
368
369
			//error_log(__METHOD__."(".__LINE__.") setACL($content[mailbox], $username, ".array2string($options).", $recursive)");
370
			if (is_numeric($username) && ($u = $this->imap->getMailBoxUserName($username)))
371
			{
372
				$username = $u;
373
			}
374
			if (!empty($username))
375
			{
376
				//error_log(__METHOD__."() setACL($content[mailbox], $username, ".array2string($options).", $recursive)");
377
				if (($ret=$this->setACL($content['mailbox'], $username, $options, $recursive, $msg)))
0 ignored issues
show
The assignment to $ret is dead and can be removed.
Loading history...
378
				{
379
					$msg = lang("The Folder %1 's ACLs saved", $content['mailbox']);
0 ignored issues
show
The call to lang() has too many arguments starting with $content['mailbox']. ( Ignorable by Annotation )

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

379
					$msg = /** @scrutinizer ignore-call */ lang("The Folder %1 's ACLs saved", $content['mailbox']);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
380
381
				}
382
				else
383
				{
384
					$msg = lang('Error while setting ACL for folder %1!', $content['mailbox']).' '.$msg;
385
				}
386
			}
387
			else
388
			{
389
				if($keys !== count($content['grid']))
390
				{
391
					array_push($validator, $keys);
392
					$msg = lang("Could not save the ACL because some names are empty");
393
				}
394
			}
395
		}
396
		if (is_array($validator))
0 ignored issues
show
The condition is_array($validator) is always true.
Loading history...
397
		{
398
			return $validator;
399
		}
400
	}
401
402
	/**
403
	 * Retrieve Folder ACL rights
404
     * @param string $mailbox
405
     * @param string &$msg
406
	 *
407
     * @return Array | Boolean returns array of acl or false on failure
408
     * @todo rights 'c' and 'd' should be fixed
409
	 */
410
	function retrieve_acl ($mailbox, &$msg)
411
	{
412
		if (($acl = $this->getACL($mailbox)))
413
		 {
414
			$msg = lang('ACL rights retrieved successfully');
415
			return $acl;
416
		 }
417
		 else
418
		 {
419
			$msg = lang('Get ACL rights failed from IMAP server!');
420
			return false;
421
		 }
422
	}
423
424
	/**
425
	 * remove_acl
426
	 * This method take content of acl rights, and will delete the one from ACL IMAP,
427
	 * for selected folder and/or its subfolders
428
	 *
429
	 * @param Array $content content array of popup window
430
	 * @param string $msg message
431
	 *
432
	 * @return Array | Boolean An array as new content for grid or false in case of error
433
	 */
434
	function remove_acl($content, &$msg)
435
	{
436
		$row_num = array_keys($content['grid']['delete'],"pressed");
437
		if ($row_num) $row_num = $row_num[0];
0 ignored issues
show
Bug Best Practice introduced by
The expression $row_num of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
438
		$recursive = $content['grid'][$row_num]['acl_recursive'];
439
		$identifier = self::_extract_acc_id($content['grid'][$row_num]['acc_id']);
440
		$content['mailbox'] = is_array($content['mailbox'])? $content['mailbox'][0] : $content['mailbox'];
441
		if (is_numeric($identifier) && ($u = $this->imap->getMailBoxUserName($identifier)))
442
		{
443
			$identifier = $u;
444
		}
445
		//error_log(__METHOD__.__LINE__."(".$content['mailbox'].", ".$identifier.", ".$recursive.")");
446
		if(($res = $this->deleteACL($content['mailbox'], $identifier,$recursive)))
0 ignored issues
show
The assignment to $res is dead and can be removed.
Loading history...
447
		{
448
			unset($content['grid'][$row_num]);
449
			unset($content['grid']['delete']);
450
			if ($recursive)
451
			{
452
				$msg = lang("The %1 's acl, including its subfolders, removed from the %2",$content['mailbox'],$identifier);
0 ignored issues
show
The call to lang() has too many arguments starting with $content['mailbox']. ( Ignorable by Annotation )

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

452
				$msg = /** @scrutinizer ignore-call */ lang("The %1 's acl, including its subfolders, removed from the %2",$content['mailbox'],$identifier);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
453
			}
454
			else
455
			{
456
				$msg = lang("The %1 's acl removed from the %2",$content['mailbox'],$identifier);
457
			}
458
459
			return array_combine(range(1, count($content['grid'])), array_values($content['grid']));
460
		}
461
		else
462
		{
463
			$msg = lang("An error happend while trying to remove ACL rights from the account %1!",$identifier);
464
			return false;
465
		}
466
	}
467
468
	/**
469
	 * Delete ACL rights of a folder or including subfolders from an account
470
	 *
471
	 * @param String $mailbox folder name that needs to be edited
472
	 * @param String $identifier The identifier to delete.
473
	 * @param Boolean $recursive boolean flag FALSE|TRUE. If it is FALSE, only the folder take in to account, but in case of TRUE
474
	 *		the mailbox including all its subfolders will be considered.
475
	 *
476
	 * @return Boolean FALSE in case of any exceptions and TRUE in case of success
477
	 */
478
	function deleteACL ($mailbox, $identifier, $recursive)
479
	{
480
		if ($recursive)
481
		{
482
			$folders = self::getSubfolders($mailbox, $this->imap);
483
		}
484
		else
485
		{
486
			$folders = (array)$mailbox;
487
		}
488
		foreach($folders as $sbFolders)
489
		{
490
			try
491
			{
492
				$this->imap->deleteACL($sbFolders, $identifier);
493
			}
494
			catch (Exception $e)
495
			{
496
				error_log(__METHOD__. "Could not delete ACL rights of folder " . $mailbox . " for account ". $identifier ."." .$e->getMessage());
497
				return false;
498
			}
499
		}
500
		return true;
501
	}
502
503
	/**
504
	 * Get subfolders of a mailbox
505
	 *
506
	 * @param string $mailbox structural folder name
507
	 * @param Mail\Imap $imap
508
	 * @return Array an array including all subfolders of given mailbox| returns an empty array in case of no subfolders
509
	 */
510
	protected static function getSubfolders($mailbox, Mail\Imap $imap)
511
	{
512
		$delimiter = $imap->getDelimiter();
513
		$nameSpace = $imap->getNameSpace();
514
		$prefix = $imap->getFolderPrefixFromNamespace($nameSpace, $mailbox);
515
		if (($subFolders = $imap->getMailBoxesRecursive($mailbox, $delimiter, $prefix)))
516
		{
517
			return $subFolders;
518
		}
519
		else
520
		{
521
			return array();
522
		}
523
	}
524
525
	/**
526
	 * Set ACL rights of a folder or including subfolders to an account
527
	 * @param String $mailbox folder name that needs to be edited
528
	 * @param String $identifier The identifier to set.
529
	 * @param Array $options Additional options:
530
	 * 				- rights: (string) The rights to alter or set.
531
	 * 				- action: (string, optional) If 'add' or 'remove', adds or removes the
532
	 * 				specified rights. Sets the rights otherwise.
533
	 * @param Boolean $recursive boolean flag FALSE|TRUE. If it is FALSE, only the folder take in to account, but in case of TRUE
534
	 *		the mailbox including all its subfolders will be considered.
535
	 * @param String $msg message
536
	 * @return Boolean FALSE in case of any exceptions and TRUE in case of success,
537
	 *
538
	 */
539
	function setACL($mailbox, $identifier,$options, $recursive, &$msg)
540
	{
541
		if ($recursive)
542
		{
543
			$folders = self::getSubfolders($mailbox, $this->imap);
544
		}
545
		else
546
		{
547
			$folders = (array)$mailbox;
548
		}
549
		foreach($folders as $sbFolders)
550
		{
551
			try
552
			{
553
				$this->imap->setACL($sbFolders,$identifier,$options);
554
			}
555
			catch (Exception $e)
556
			{
557
				$msg = $e->getMessage();
558
				error_log(__METHOD__. "Could not set ACL rights on folder " . $mailbox . " for account ". $identifier . "." .$e->getMessage());
559
				return false;
560
			}
561
		}
562
		return true;
563
	}
564
565
	/**
566
	 * Get ACL rights of a folder from an account
567
	 *
568
	 * @param String $mailbox folder name that needs to be read
569
	 * @return Array|Boolean FALSE in case of any exceptions and returns Array in case of success,
570
	 */
571
	function getACL ($mailbox)
572
	{
573
		try
574
		{
575
			return $this->imap->getACL($mailbox);
576
		} catch (Exception $e) {
577
			error_log(__METHOD__. "Could not get ACL rights from folder " . $mailbox . "." .$e->getMessage());
578
			return false;
579
		}
580
	}
581
582
	/**
583
	 * Method to get acc_id id value whether if is a flat value or an array
584
	 *
585
	 * @param type $acc_id acc_id value comming from client-side
586
	 *
587
	 * @return string returns acc_id in flat format
588
	 */
589
	private static function _extract_acc_id ($acc_id)
590
	{
591
		return is_array($acc_id)?$acc_id[0]:$acc_id;
0 ignored issues
show
The condition is_array($acc_id) is always false.
Loading history...
592
	}
593
594
    /**
595
     * @param string | array $mailbox
596
     * @param string $acc_id
597
     *
598
     * @return string | NULL return sanitate mailbox of acc id and delimiter and return it as string
599
     */
600
	private static function _extract_mailbox ($mailbox, $acc_id)
601
    {
602
        $mailbox = is_array($mailbox) ? $mailbox[0] : $mailbox;
603
        return preg_replace("/^".$acc_id."::/",'', $mailbox);
604
    }
605
}
606