2015-07-20 18:41:50 +02:00
< ? php
/**
* EGroupware - Mail - tree worker class
*
* @ link http :// www . egroupware . org
* @ package mail
2016-10-08 14:32:58 +02:00
* @ author Hadi Nategh [ hn @ egroupware . org ]
* @ copyright ( c ) 2015 - 16 by EGroupware GmbH < info - AT - egroupware . org >
2015-07-20 18:41:50 +02:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id : $
*/
2016-05-03 21:17:44 +02:00
use EGroupware\Api ;
2016-03-28 20:51:38 +02:00
use EGroupware\Api\Mail ;
use EGroupware\Api\Etemplate\Widget\Tree ;
2015-07-20 18:41:50 +02:00
/**
* Mail tree worker class
* - provides backend functionality for folder tree
* - provides classes that may be used by other apps too
*
*/
class mail_tree
{
/**
2016-03-28 20:51:38 +02:00
* delimiter - used to separate acc_id from mailbox / folder - tree - structure
2015-07-20 18:41:50 +02:00
*
* @ var string
*/
2016-03-28 20:51:38 +02:00
const DELIMITER = Mail :: DELIMITER ;
2015-08-21 10:01:42 +02:00
2018-09-25 15:00:01 +02:00
/**
* bit flag : ident_realname
*/
const IDENT_NAME = 1 ;
/**
* bit flag : ident_email
*/
const IDENT_EMAIL = 2 ;
/**
* bit flag : ident_org
*/
const IDENT_ORG = 4 ;
/**
* bit flag : ident_name
*/
const IDENT_NAME_IDENTITY = 8 ;
2021-12-10 10:41:04 +01:00
/**
* bit flag : org | name email
*/
const ORG_NAME_EMAIL = 16 ;
2015-07-21 15:24:25 +02:00
/**
* Icons used for nodes different states
*
* @ var array
*/
static $leafImages = array (
2016-02-29 14:45:44 +01:00
'folderNoSelectClosed' => " folderNoSelectClosed " ,
'folderNoSelectOpen' => " folderNoSelectOpen " ,
'folderOpen' => " folderOpen " ,
'folderClosed' => " MailFolderClosed " ,
2024-07-26 13:22:48 +02:00
'folderLeaf' => " MailFolderClosed " ,
2016-02-29 14:45:44 +01:00
'folderHome' => " kfm_home " ,
'folderAccount' => " thunderbird " ,
2015-07-21 15:24:25 +02:00
);
2015-08-21 10:01:42 +02:00
2016-03-28 20:51:38 +02:00
/**
* Instance of mail_ui class
*
* @ var mail_ui
*/
var $ui ;
2015-07-21 15:24:25 +02:00
/**
* Mail tree constructor
*
2016-03-28 20:51:38 +02:00
* @ param mail_ui $mail_ui
2015-07-21 15:24:25 +02:00
*/
2016-03-28 20:51:38 +02:00
function __construct ( mail_ui $mail_ui )
2016-02-29 14:45:44 +01:00
{
2015-07-20 18:41:50 +02:00
$this -> ui = $mail_ui ;
2016-02-29 14:45:44 +01:00
// check images available in png or svg
foreach ( self :: $leafImages as & $image )
{
if ( strpos ( $image , '.' ) === false )
{
2024-02-16 19:06:39 +01:00
$image = Api\Image :: find ( 'mail' , 'dhtmlxtree/' . $image );
2016-02-29 14:45:44 +01:00
}
}
2015-07-20 18:41:50 +02:00
}
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
/**
*
* Structs an array of fake INBOX to show as an error node
* @ param string $_profileID icServer profile id
* @ param string $_err error message to be shown on tree node
* @ param mixed $_path
* @ param mixed $_parent
* @ return array returns an array of tree node
*/
static function treeLeafNoConnectionArray ( $_profileID , $_err , $_path , $_parent )
{
$baseNode = array ( 'id' => $_profileID );
$leaf = array (
2016-03-28 20:51:38 +02:00
'id' => $_profileID . self :: DELIMITER . 'INBOX' ,
2015-07-20 18:41:50 +02:00
'text' => $_err ,
'tooltip' => $_err ,
2015-07-21 15:24:25 +02:00
'im0' => self :: $leafImages [ " folderNoSelectClosed " ],
2016-02-29 14:45:44 +01:00
'im1' => self :: $leafImages [ " folderNoSelectOpen " ],
2015-07-21 15:24:25 +02:00
'im2' => self :: $leafImages [ " folderNoSelectClosed " ],
2015-07-20 18:41:50 +02:00
'path' => $_path ,
'parent' => $_parent
);
2016-03-28 20:51:38 +02:00
self :: setOutStructure ( $leaf , $baseNode , self :: DELIMITER );
2015-07-20 18:41:50 +02:00
return ( $baseNode ? $baseNode : array ( // fallback not connected array
'id' => 0 ,
'item' => array (
'text' => 'INBOX' ,
'tooltip' => 'INBOX' . ' ' . lang ( '(not connected)' ),
2015-07-21 15:24:25 +02:00
'im0' => self :: $leafImages [ 'folderHome' ]
2015-07-20 18:41:50 +02:00
)
)
);
}
2015-08-21 10:01:42 +02:00
2015-07-27 19:46:45 +02:00
/**
* Check if a given node has children attribute set
*
* @ param array $_node array of a node
* @ return int returns 1 if it has children flag set otherwise 0
*/
private static function nodeHasChildren ( $_node )
{
$hasChildren = 0 ;
if ( in_array ( '\haschildren' , $_node [ 'ATTRIBUTES' ]) ||
in_array ( '\Haschildren' , $_node [ 'ATTRIBUTES' ]) ||
in_array ( '\HasChildren' , $_node [ 'ATTRIBUTES' ])) $hasChildren = 1 ;
return $hasChildren ;
}
2015-08-21 10:01:42 +02:00
2015-07-31 16:21:31 +02:00
/**
* Check if the given tree id is account node ( means root )
*
* @ param type $_node a tree id node
* @ return boolean returns true if the node is account node otherwise false
*/
private static function isAccountNode ( $_node )
{
2021-10-05 14:11:11 +02:00
list (, $leaf ) = explode ( self :: DELIMITER , $_node ) + [ null , null ];
2015-07-31 16:21:31 +02:00
if ( $leaf || $_node == null ) return false ;
return true ;
}
2015-08-21 10:01:42 +02:00
2015-07-31 16:21:31 +02:00
/**
* Calculate node level form the root
* @ param type $_path tree node full path , e . g . INBOX / Drafts
*
* @ return int returns node level distance from the root ,
* returns false if something goes wrong
*/
private static function getNodeLevel ( $_path , $_delimiter = '.' )
{
$parts = explode ( $_delimiter , $_path );
if ( is_array ( $parts ))
{
return count ( $parts );
}
return false ;
}
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
/**
* getTree provides tree structure regarding to selected node
*
2015-07-23 15:26:43 +02:00
* @ param string $_parent = null no parent node means root with the first level of folders
* @ param string $_profileID = '' icServer id
* @ param int | boolean $_openTopLevel = 1 Open top level folders on load if it ' s set to 1 | true ,
* false | 0 leaves them in closed state
2015-07-27 19:46:45 +02:00
* @ param $_noCheckboxNS = false no checkbox for namesapaces makes sure to not put checkbox for namespaces node
2015-07-31 16:21:31 +02:00
* @ param boolean $_subscribedOnly = false get only subscribed folders
2015-08-03 16:33:18 +02:00
* @ param boolean $_allInOneGo = false , true will get all folders ( dependes on subscribedOnly option ) of the account in one go
2015-08-10 16:54:38 +02:00
* @ param boolean $_checkSubscribed = true , pre - check checkboxes of subscribed folders
2015-07-23 15:26:43 +02:00
*
2015-07-20 18:41:50 +02:00
* @ return array returns an array of mail tree structure according to provided node
*/
2015-08-10 16:54:38 +02:00
function getTree ( $_parent = null , $_profileID = '' , $_openTopLevel = 1 , $_noCheckboxNS = false , $_subscribedOnly = false , $_allInOneGo = false , $_checkSubscribed = true )
2015-07-20 18:41:50 +02:00
{
//Init mail folders
2016-03-28 20:51:38 +02:00
$tree = array ( Tree :: ID => $_parent ? $_parent : 0 , Tree :: CHILDREN => array ());
2016-06-14 10:50:04 +02:00
if ( ! isset ( $this -> ui -> mail_bo )) throw new Api\Exception\WrongUserinput ( lang ( 'Initialization of mail failed. Please use the Wizard to cope with the problem' ));
2015-07-21 15:24:25 +02:00
$hDelimiter = $this -> ui -> mail_bo -> getHierarchyDelimiter ();
2015-08-21 10:01:42 +02:00
2016-03-28 20:51:38 +02:00
if ( $_parent ) list ( $_profileID ) = explode ( self :: DELIMITER , $_parent );
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
if ( is_numeric ( $_profileID ) && $_profileID != $this -> ui -> mail_bo -> profileID )
{
try
{
$this -> ui -> changeProfile ( $_profileID );
} catch ( Exception $ex ) {
return self :: treeLeafNoConnectionArray ( $_profileID , $ex -> getMessage (), array ( $_profileID ), '' );
}
}
2015-08-21 10:01:42 +02:00
2015-08-03 16:33:18 +02:00
try
2015-07-20 18:41:50 +02:00
{
2016-06-02 12:33:50 +02:00
// *** Note: Should not apply any imap transaction, because in case of exception it will stop the
// process of rendering root node
2015-08-03 16:33:18 +02:00
if ( $_parent && ! self :: isAccountNode ( $_parent )) // Single node loader
2015-07-20 18:41:50 +02:00
{
2016-03-28 20:51:38 +02:00
$nodeInfo = Mail :: pathToFolderData ( $_parent , $hDelimiter );
2015-08-03 16:33:18 +02:00
$folders = $this -> ui -> mail_bo -> getFolderArrays ( $nodeInfo [ 'mailbox' ], false , $_allInOneGo ? 0 : 2 , $_subscribedOnly );
2015-08-21 10:01:42 +02:00
2015-08-03 16:33:18 +02:00
$childrenNode = array ();
foreach ( $folders as & $node )
{
2016-03-28 20:51:38 +02:00
$nodeId = $_profileID . self :: DELIMITER . $node [ 'MAILBOX' ];
$nodeData = Mail :: pathToFolderData ( $nodeId , $node [ 'delimiter' ]);
2015-08-03 16:33:18 +02:00
$childrenNode [] = array (
2016-03-28 20:51:38 +02:00
Tree :: ID => $nodeId ,
Tree :: AUTOLOAD_CHILDREN => $_allInOneGo ? false : self :: nodeHasChildren ( $node ),
Tree :: CHILDREN => array (),
Tree :: LABEL => $nodeData [ 'text' ],
Tree :: TOOLTIP => $nodeData [ 'tooltip' ],
Tree :: IMAGE_LEAF => self :: $leafImages [ 'folderLeaf' ],
Tree :: IMAGE_FOLDER_OPEN => self :: $leafImages [ 'folderOpen' ],
Tree :: IMAGE_FOLDER_CLOSED => self :: $leafImages [ 'folderClosed' ],
Tree :: CHECKED => $_checkSubscribed ? $node [ 'SUBSCRIBED' ] : false ,
2015-08-03 16:33:18 +02:00
'parent' => $_parent
);
}
2016-03-28 20:51:38 +02:00
$tree [ Tree :: CHILDREN ] = $childrenNode ;
2015-07-20 18:41:50 +02:00
}
2015-08-03 16:33:18 +02:00
else //Top Level Nodes loader
2015-07-20 18:41:50 +02:00
{
2015-08-03 16:33:18 +02:00
if ( self :: isAccountNode ( $_parent )) // An account called for open
{
$_openTopLevel = 1 ;
$tree = self :: getAccountsRootNode ( $_profileID , $_noCheckboxNS , $_openTopLevel );
}
else // Initial accounts|root nodes
{
$tree = self :: getAccountsRootNode ( $_profileID , $_noCheckboxNS , $_openTopLevel );
if ( ! $_profileID && ! $_openTopLevel ) return $tree ;
}
2015-07-31 16:21:31 +02:00
2015-08-03 16:33:18 +02:00
//List of folders
2015-10-06 12:51:35 +02:00
$foldersList = $this -> ui -> mail_bo -> getFolderArrays ( null , true , $_allInOneGo ? 0 : 2 , $_subscribedOnly , false );
2016-06-02 12:33:50 +02:00
// User defined folders based on account
$definedFolders = array (
'Trash' => $this -> ui -> mail_bo -> getTrashFolder ( false ),
'Templates' => $this -> ui -> mail_bo -> getTemplateFolder ( false ),
'Drafts' => $this -> ui -> mail_bo -> getDraftFolder ( false ),
'Sent' => $this -> ui -> mail_bo -> getSentFolder ( false ),
'Junk' => $this -> ui -> mail_bo -> getJunkFolder ( false ),
'Outbox' => $this -> ui -> mail_bo -> getOutboxFolder ( false ),
2017-06-09 16:06:03 +02:00
'Ham' => $this -> ui -> mail_bo -> icServer -> acc_folder_ham
2016-06-02 12:33:50 +02:00
);
2015-08-03 16:33:18 +02:00
foreach ( $foldersList as & $folder )
{
$path = $parent = $parts = explode ( $folder [ 'delimiter' ], $folder [ 'MAILBOX' ]);
array_pop ( $parent );
array_unshift ( $path , $_profileID );
2015-07-31 16:21:31 +02:00
2015-08-03 16:33:18 +02:00
$data = array (
2016-03-28 20:51:38 +02:00
Tree :: ID => $_profileID . self :: DELIMITER . $folder [ 'MAILBOX' ],
Tree :: AUTOLOAD_CHILDREN => $_allInOneGo ? false : self :: nodeHasChildren ( $folder ),
Tree :: CHILDREN => array (),
Tree :: LABEL => lang ( $folder [ 'MAILBOX' ]),
Tree :: OPEN => self :: getNodeLevel ( $folder [ 'MAILBOX' ], $folder [ 'delimiter' ]) <= $_openTopLevel ? 1 : 0 ,
Tree :: TOOLTIP => lang ( $folder [ 'MAILBOX' ]),
Tree :: CHECKED => $_checkSubscribed ? $folder [ 'SUBSCRIBED' ] : false ,
Tree :: NOCHECKBOX => 0 ,
'parent' => $parent ? $_profileID . self :: DELIMITER . implode ( $folder [ 'delimiter' ], $parent ) : $_profileID ,
2015-08-03 16:33:18 +02:00
'path' => $path ,
'folderarray' => $folder
);
// Set Acl capability for INBOX
if ( $folder [ 'MAILBOX' ] === " INBOX " )
{
$data [ 'data' ] = array ( 'acl' => $this -> ui -> mail_bo -> icServer -> queryCapability ( 'ACL' ));
2016-03-28 20:51:38 +02:00
$data [ Tree :: NOCHECKBOX ] = $_noCheckboxNS ;
2015-08-03 16:33:18 +02:00
}
2015-08-07 09:47:28 +02:00
else
{
//Do not open Initially other folders but INBOX
2016-03-28 20:51:38 +02:00
$data [ Tree :: OPEN ] = 0 ;
2015-08-07 09:47:28 +02:00
}
2015-08-03 16:33:18 +02:00
self :: setOutStructure ( $data , $tree , $folder [ 'delimiter' ], true , $this -> ui -> mail_bo -> _getNameSpaces (), $definedFolders );
}
// Structs children of account root node. Used for mail index tree when we do autoloading on account id
if ( self :: isAccountNode ( $_parent ))
2015-07-20 18:41:50 +02:00
{
2015-08-03 16:33:18 +02:00
$tree = array (
2016-03-28 20:51:38 +02:00
Tree :: ID => ( string ) $_parent ,
Tree :: CHILDREN => $tree [ Tree :: CHILDREN ][ 0 ][ Tree :: CHILDREN ],
Tree :: LABEL => $tree [ Tree :: CHILDREN ][ 0 ][ Tree :: LABEL ],
Tree :: IMAGE_LEAF => $tree [ Tree :: CHILDREN ][ 0 ][ Tree :: IMAGE_LEAF ],
Tree :: IMAGE_FOLDER_OPEN => $tree [ Tree :: CHILDREN ][ 0 ][ Tree :: IMAGE_FOLDER_OPEN ],
Tree :: IMAGE_FOLDER_CLOSED => $tree [ Tree :: CHILDREN ][ 0 ][ Tree :: IMAGE_FOLDER_CLOSED ],
Tree :: OPEN => 1 ,
Tree :: TOOLTIP => $tree [ Tree :: CHILDREN ][ 0 ][ Tree :: TOOLTIP ],
Tree :: AUTOLOAD_CHILDREN => 1 ,
'data' => $tree [ Tree :: CHILDREN ][ 0 ][ 'data' ]
2015-08-03 16:33:18 +02:00
);
2015-07-20 18:41:50 +02:00
}
}
}
2015-08-03 16:33:18 +02:00
catch ( Exception $ex ) // Catch exceptions
{
//mail_ui::callWizard($ex->getMessage(), false, 'error');
return self :: treeLeafNoConnectionArray ( $_profileID , $ex -> getMessage (), array ( $_profileID ), '' );
}
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
return $tree ;
}
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
/**
* setOutStructure - helper function to transform the folderObjectList to dhtmlXTreeObject requirements
*
* @ param array $data data to be processed
* @ param array & $out , out array
* @ param string $del needed as glue for parent / child operation / comparsion
* @ param boolean $createMissingParents a missing parent , instead of throwing an exception
* @ param array $nameSpace used to check on creation of nodes in namespaces other than personal
* as clearance for access may be limited to a single branch - node of a tree
* @ return void
*/
2015-07-31 16:21:31 +02:00
static function setOutStructure ( $data , & $out , $del = '.' , $createMissingParents = true , $nameSpace = array (), $definedFolders = array ())
2015-07-20 18:41:50 +02:00
{
//error_log(__METHOD__."(".array2string($data).', '.array2string($out).", '$del')");
$components = $data [ 'path' ];
array_pop ( $components ); // remove own name
$insert = & $out ;
$parents = array ();
foreach ( $components as $component )
{
if ( count ( $parents ) > 1 )
{
$helper = array_slice ( $parents , 1 , null , true );
2016-03-28 20:51:38 +02:00
$parent = $parents [ 0 ] . self :: DELIMITER . implode ( $del , $helper );
2015-07-20 18:41:50 +02:00
if ( $parent ) $parent .= $del ;
}
else
{
2016-03-28 20:51:38 +02:00
$parent = implode ( self :: DELIMITER , $parents );
if ( $parent ) $parent .= self :: DELIMITER ;
2015-07-20 18:41:50 +02:00
}
if ( ! is_array ( $insert ) || ! isset ( $insert [ 'item' ]))
{
// throwing an exeption here seems to be unrecoverable,
// even if the cause is a something that can be handeled by the mailserver
2020-07-27 08:07:45 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . ':' . __LINE__ . " id= $data[id] : Parent ' $parent ' of ' $component ' not found! " );
2015-07-20 18:41:50 +02:00
// should we hit the break? if in personal: sure, something is wrong with the folderstructure
// if in shared or others we may proceed as access to folders may very well be limited to
// a single folder within the tree
$break = true ;
foreach ( $nameSpace as $nsp )
{
// if (appropriately padded) namespace prefix of (others or shared) is the leading part of parent
// we want to create the node in question as we meet the above considerations
2016-03-28 20:51:38 +02:00
if ( $nsp [ 'type' ] != 'personal' && $nsp [ 'prefix_present' ] && stripos ( $parent , $data [ 'path' ][ 0 ] . self :: DELIMITER . $nsp [ 'prefix' ]) === 0 )
2015-07-20 18:41:50 +02:00
{
2020-07-27 08:07:45 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' about to create:' . $parent . ' in ' . $data [ 'path' ][ 0 ] . self :: DELIMITER . $nsp [ 'prefix' ]);
2015-07-20 18:41:50 +02:00
$break = false ;
}
}
if ( $break ) break ;
}
if ( $insert [ 'item' ])
{
foreach ( $insert [ 'item' ] as & $item )
{
if ( $item [ 'id' ] == $parent . $component )
{
$insert =& $item ;
break ;
}
}
}
if ( $item [ 'id' ] != $parent . $component )
{
if ( $createMissingParents )
{
unset ( $item );
2016-02-29 14:45:44 +01:00
$item = array (
'id' => $parent . $component ,
'text' => $component ,
2024-07-26 13:22:48 +02:00
'im0' => self :: $leafImages [ " folderClosed " ],
'im1' => self :: $leafImages [ " folderOpen " ],
'im2' => self :: $leafImages [ " folderClosed " ],
2016-02-29 14:45:44 +01:00
'tooltip' => lang ( 'no access' )
);
2015-07-20 18:41:50 +02:00
$insert [ 'item' ][] =& $item ;
$insert =& $item ;
}
else
{
2016-05-03 21:17:44 +02:00
throw new Api\Exception\AssertionFailed ( __METHOD__ . ':' . __LINE__ . " : id= $data[id] : Parent ' $parent ' ' $component ' not found! " );
2015-07-20 18:41:50 +02:00
}
}
$parents [] = $component ;
}
2021-10-05 14:11:11 +02:00
if ( ! empty ( $data [ 'folderarray' ][ 'delimiter' ]) && ! empty ( $data [ 'folderarray' ][ 'MAILBOX' ]))
2015-07-31 16:21:31 +02:00
{
$path = explode ( $data [ 'folderarray' ][ 'delimiter' ], $data [ 'folderarray' ][ 'MAILBOX' ]);
$folderName = array_pop ( $path );
2015-08-21 10:01:42 +02:00
2015-07-31 16:21:31 +02:00
if ( $data [ 'folderarray' ][ 'MAILBOX' ] === " INBOX " )
{
2016-03-28 20:51:38 +02:00
$data [ Tree :: IMAGE_LEAF ] = self :: $leafImages [ 'folderHome' ];
$data [ Tree :: IMAGE_FOLDER_OPEN ] = self :: $leafImages [ 'folderHome' ];
$data [ Tree :: IMAGE_FOLDER_CLOSED ] = self :: $leafImages [ 'folderHome' ];
$data [ Tree :: LABEL ] = lang ( $folderName );
$data [ Tree :: TOOLTIP ] = lang ( $folderName );
2015-07-31 16:21:31 +02:00
}
// User defined folders may get different icons
// plus they need to be translated too
2015-08-04 17:50:28 +02:00
elseif (( $key = array_search ( $data [ 'folderarray' ][ 'MAILBOX' ], $definedFolders , true )) !== false )
2015-07-31 16:21:31 +02:00
{
2016-03-28 20:51:38 +02:00
$data [ Tree :: LABEL ] = lang ( $key );
2017-09-07 16:42:05 +02:00
$data [ Tree :: TOOLTIP ] = $key ;
2015-07-31 16:21:31 +02:00
//User defined folders icons
2016-03-28 20:51:38 +02:00
$data [ Tree :: IMAGE_LEAF ] =
$data [ Tree :: IMAGE_FOLDER_OPEN ] =
2024-02-16 19:06:39 +01:00
$data [ Tree :: IMAGE_FOLDER_CLOSED ] = Api\Image :: find ( 'mail' , 'dhtmlxtree/' . " MailFolder " . $key );
2015-07-31 16:21:31 +02:00
}
2021-10-05 14:11:11 +02:00
elseif ( ! empty ( $data [ 'folderarray' ][ 'attributes' ]) && stripos ( array2string ( $data [ 'folderarray' ][ 'attributes' ]), '\noselect' ) !== false )
2015-07-31 16:21:31 +02:00
{
2016-03-28 20:51:38 +02:00
$data [ Tree :: IMAGE_LEAF ] = self :: $leafImages [ 'folderNoSelectClosed' ];
$data [ Tree :: IMAGE_FOLDER_OPEN ] = self :: $leafImages [ 'folderNoSelectOpen' ];
$data [ Tree :: IMAGE_FOLDER_CLOSED ] = self :: $leafImages [ 'folderNoSelectClosed' ];
2015-07-31 16:21:31 +02:00
}
elseif ( $data [ 'parent' ])
{
2016-03-28 20:51:38 +02:00
$data [ Tree :: LABEL ] = $folderName ;
$data [ Tree :: TOOLTIP ] = $folderName ;
$data [ Tree :: IMAGE_LEAF ] = self :: $leafImages [ 'folderLeaf' ];
$data [ Tree :: IMAGE_FOLDER_OPEN ] = self :: $leafImages [ 'folderOpen' ];
$data [ Tree :: IMAGE_FOLDER_CLOSED ] = self :: $leafImages [ 'folderClosed' ];
2015-07-31 16:21:31 +02:00
}
2015-08-21 10:01:42 +02:00
2015-08-05 12:22:29 +02:00
// Contains unseen mails for the folder
2021-10-05 14:11:11 +02:00
$unseen = $data [ 'folderarray' ][ 'counter' ][ 'UNSEEN' ] ? ? 0 ;
2015-08-21 10:01:42 +02:00
2015-08-05 12:22:29 +02:00
// if there's unseen mails then change the label and style
// accordingly to indicate useen mails
if ( $unseen > 0 )
{
2016-03-28 20:51:38 +02:00
$data [ Tree :: LABEL ] = $data [ Tree :: LABEL ] . '(' . $unseen . ')' ;
2015-08-05 12:22:29 +02:00
$data [ 'style' ] = 'font-weight: bold' ;
}
2015-07-31 16:21:31 +02:00
}
//Remove extra data from tree structure
unset ( $data [ 'folderarray' ]);
2015-07-20 18:41:50 +02:00
unset ( $data [ 'path' ]);
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
$insert [ 'item' ][] = $data ;
}
2015-08-21 10:01:42 +02:00
2015-07-31 16:21:31 +02:00
/**
* Get accounts root node , fetches all or an accounts for a user
*
* @ param type $_profileID = null Null means all accounts and giving profileid means fetches node for the account
* @ param type $_noCheckbox = false option to switch checkbox of
* @ param type $_openTopLevel = 0 option to either start the node opened ( 1 ) or closed ( 0 )
*
* @ return array an array of baseNodes of accounts
*/
static function getAccountsRootNode ( $_profileID = null , $_noCheckbox = false , $_openTopLevel = 0 )
{
2016-03-28 20:51:38 +02:00
$roots = array ( Tree :: ID => 0 , Tree :: CHILDREN => array ());
2015-08-21 10:01:42 +02:00
2022-09-15 15:57:29 +02:00
foreach ( Mail\Account :: search ( true , 'params' ) as $acc_id => $params )
2015-07-31 16:21:31 +02:00
{
2022-09-15 15:57:29 +02:00
try {
$accObj = new Mail\Account ( $params );
if ( ! $accObj -> is_imap () || $_profileID && $acc_id != $_profileID ) continue ;
$identity = self :: getIdentityName ( Mail\Account :: identity_name ( $accObj , true , $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ], true ));
// Open top level folders for active account
$openActiveAccount = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ] == $acc_id ? 1 : 0 ;
$baseNode = array (
Tree :: ID => ( string ) $acc_id ,
Tree :: LABEL => str_replace ( array ( '<' , '>' ), array ( '[' , ']' ), $identity ),
Tree :: TOOLTIP => '(' . $acc_id . ') ' . htmlspecialchars_decode ( $identity ),
Tree :: IMAGE_LEAF => self :: $leafImages [ 'folderAccount' ],
Tree :: IMAGE_FOLDER_OPEN => self :: $leafImages [ 'folderAccount' ],
Tree :: IMAGE_FOLDER_CLOSED => self :: $leafImages [ 'folderAccount' ],
'path' => array ( $acc_id ),
Tree :: CHILDREN => array (), // dynamic loading on unfold
Tree :: AUTOLOAD_CHILDREN => true ,
'parent' => '' ,
Tree :: OPEN => $_openTopLevel ? : $openActiveAccount ,
// mark on account if Sieve is enabled
'data' => array (
'sieve' => $accObj -> imapServer () -> acc_sieve_enabled ,
'spamfolder' => $accObj -> imapServer () -> acc_folder_junk && ( strtolower ( $accObj -> imapServer () -> acc_folder_junk ) != 'none' ) ? true : false ,
'archivefolder' => $accObj -> imapServer () -> acc_folder_archive && ( strtolower ( $accObj -> imapServer () -> acc_folder_archive ) != 'none' ) ? true : false
),
Tree :: NOCHECKBOX => $_noCheckbox
);
}
catch ( \Exception $ex ) {
$baseNode = array (
Tree :: ID => ( string ) $acc_id ,
Tree :: LABEL => lang ( 'Error' ) . ': ' . lang ( $ex -> getMessage ()),
Tree :: TOOLTIP => '(' . $acc_id . ') ' . htmlspecialchars_decode ( $params [ 'acc_name' ]),
Tree :: IMAGE_LEAF => self :: $leafImages [ 'folderAccount' ],
Tree :: IMAGE_FOLDER_OPEN => self :: $leafImages [ 'folderAccount' ],
Tree :: IMAGE_FOLDER_CLOSED => self :: $leafImages [ 'folderAccount' ],
'path' => array ( $acc_id ),
Tree :: CHILDREN => array (), // dynamic loading on unfold
Tree :: AUTOLOAD_CHILDREN => false ,
'parent' => '' ,
Tree :: OPEN => false ,
Tree :: NOCHECKBOX => true
);
}
2016-03-28 20:51:38 +02:00
self :: setOutStructure ( $baseNode , $roots , self :: DELIMITER );
2015-07-31 16:21:31 +02:00
}
return $roots ;
}
2015-08-21 10:01:42 +02:00
2015-08-04 10:21:23 +02:00
/**
* Initialization tree for index sidebox menu
*
* This function gets all accounts root nodes and then
* fill the active accounts with its children .
*
* @ param string $_parent = null no parent node means root with the first level of folders
2015-08-21 10:01:42 +02:00
* @ param string $_profileID = '' active profile / acc_id
2015-08-04 10:21:23 +02:00
* @ param int | boolean $_openTopLevel = 1 Open top level folders on load if it ' s set to 1 | true ,
* false | 0 leaves them in closed state
* @ param boolean $_subscribedOnly = false get only subscribed folders
* @ param boolean $_allInOneGo = false , true will get all folders ( dependes on subscribedOnly option ) of the account in one go
* @ return type an array of tree
*/
function getInitialIndexTree ( $_parent = null , $_profileID = '' , $_openTopLevel = 1 , $_subscribedOnly = false , $_allInOneGo = false )
{
2015-08-21 10:01:42 +02:00
$tree = $this -> getTree ( $_parent , '' , $_openTopLevel , false , $_subscribedOnly , $_allInOneGo );
$branches = $this -> getTree ( $_profileID , $_profileID , 1 , false , $_subscribedOnly , $_allInOneGo );
2016-03-28 20:51:38 +02:00
foreach ( $tree [ Tree :: CHILDREN ] as & $account )
2015-08-04 10:21:23 +02:00
{
2016-03-28 20:51:38 +02:00
if ( $account [ Tree :: ID ] == $_profileID )
2015-08-04 10:21:23 +02:00
{
2016-06-03 10:29:49 +02:00
$account = array_merge ( $account , $branches );
2015-08-04 10:21:23 +02:00
}
}
return $tree ;
}
2018-09-25 15:00:01 +02:00
/**
* Build folder tree parent identity label
*
* @ param array $_account
2022-01-10 14:03:14 +01:00
* @ param bool $_fullString = true full or false = NamePart only is returned
2018-09-25 15:00:01 +02:00
* @ return string
*/
2022-01-10 14:03:14 +01:00
static function getIdentityName ( $_account , bool $_fullString = true )
2018-09-25 15:00:01 +02:00
{
$identLabel = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'identLabel' ];
$name = array ();
if ( $identLabel & self :: IDENT_NAME_IDENTITY )
{
$name [] = $_account [ 'ident_name' ];
}
if ( $identLabel & self :: IDENT_NAME )
{
$name [] = $_account [ 'ident_realname' ] . ' ' ;
}
if ( $identLabel & self :: IDENT_ORG )
{
$name [] = $_account [ 'ident_org' ];
}
2021-12-10 10:41:04 +01:00
if ( $identLabel & self :: ORG_NAME_EMAIL )
{
2022-01-10 14:03:14 +01:00
$name [] = $_account [ 'ident_org' ] . " | " . $_account [ 'ident_realname' ] . ( $_fullString ? ' ' . ' <' . $_account [ 'ident_email' ] . '>' : '' );
2021-12-10 10:41:04 +01:00
}
2018-09-25 15:00:01 +02:00
if ( $identLabel & self :: IDENT_EMAIL || empty ( $name ))
{
2022-04-26 18:46:23 +02:00
if ( $_fullString && trim ( $_account [ 'ident_email' ]))
2018-09-25 15:00:01 +02:00
{
$name [] = ' <' . $_account [ 'ident_email' ] . '>' ;
}
2022-04-26 18:46:23 +02:00
elseif ( ! empty ( $_account [ 'acc_imap_username' ]) && trim ( $_account [ 'acc_imap_username' ]))
2018-09-25 15:00:01 +02:00
{
$name [] = ' <' . $_account [ 'acc_imap_username' ] . '>' ;
}
}
return implode ( ' ' , $name );
}
2022-04-26 18:46:23 +02:00
}