mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-27 02:14:45 +01:00
* Mail/tree: Performance improvement for mail index folderTree
- Autoloading mail folders when show all folders is on (performance improvement) - Get folder status for opened folders only (performance improvement) - Styling hovered over mail folder
This commit is contained in:
parent
6f52ff858c
commit
df179a3859
@ -1071,6 +1071,8 @@ class emailadmin_imapbase
|
||||
* @param ignoreStatusCache bool ignore the cache used for counters
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws egw_exception
|
||||
*/
|
||||
function _getStatus($folderName,$ignoreStatusCache=false)
|
||||
{
|
||||
@ -1133,7 +1135,7 @@ class emailadmin_imapbase
|
||||
// does the folder exist???
|
||||
if (is_null($folderInfoCache) || !isset($folderInfoCache[$_folderName]))
|
||||
{
|
||||
$ret = $this->icServer->getMailboxes('', $_folderName, true);
|
||||
$ret = $this->icServer->getMailboxes($_folderName, 1, true);
|
||||
//error_log(__METHOD__.' ('.__LINE__.') '.$_folderName.' '.array2string($ret));
|
||||
if (is_array($ret))
|
||||
{
|
||||
@ -1373,7 +1375,7 @@ class emailadmin_imapbase
|
||||
$sortResult = (is_array($_thisUIDOnly) ? $_thisUIDOnly:(array)$_thisUIDOnly);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// fetch the data for the selected messages
|
||||
if (self::$debug||self::$debugTimes) $starttime = microtime(true);
|
||||
try
|
||||
@ -2254,6 +2256,7 @@ class emailadmin_imapbase
|
||||
* @param string _folderName the new foldername
|
||||
*
|
||||
* @return mixed name of the newly created folder or false on error
|
||||
* @throws egw_exception
|
||||
*/
|
||||
function renameFolder($_oldFolderName, $_parent, $_folderName)
|
||||
{
|
||||
@ -2289,6 +2292,7 @@ class emailadmin_imapbase
|
||||
* @param string _folderName the name of the folder to be deleted
|
||||
*
|
||||
* @return bool true on success, PEAR Error on failure
|
||||
* @throws egw_exception
|
||||
*/
|
||||
function deleteFolder($_folderName)
|
||||
{
|
||||
@ -2623,19 +2627,25 @@ class emailadmin_imapbase
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IMAP folder for a mailbox
|
||||
* Get IMAP folders for a mailbox
|
||||
*
|
||||
* @param $_nodePath = null folder name to fetch from IMAP,
|
||||
* @param string $_nodePath = null folder name to fetch from IMAP,
|
||||
* null means all folders
|
||||
* @param $_onlyTopLevel if set to true only top level objects
|
||||
* @param boolean $_onlyTopLevel if set to true only top level objects
|
||||
* will be return and nodePath would be ignored
|
||||
* @param int $_search = 2 search restriction in given mailbox
|
||||
* 0:All folders recursively from the $_nodePath
|
||||
* 1:Only folder of specified $_nodePath
|
||||
* 2:All folders of $_nodePath in the same heirachy level
|
||||
* @return array an array of folder
|
||||
*
|
||||
* @param boolean $_subscribedOnly = false Command to fetch only the subscribed folders
|
||||
* @param boolean $_getCounter = false Command to fetch mailbox counter
|
||||
*
|
||||
* @return array arrays of folders
|
||||
*
|
||||
* @todo Sorting autofolders and no autofolders
|
||||
*/
|
||||
function getFolderArray ($_nodePath = null, $_onlyTopLevel = false, $_search= 2)
|
||||
function getFolderArrays ($_nodePath = null, $_onlyTopLevel = false, $_search= 2, $_subscribedOnly = false, $_getCounter = false)
|
||||
{
|
||||
// delimiter
|
||||
$delimiter = $this->getHierarchyDelimiter();
|
||||
@ -2651,10 +2661,54 @@ class emailadmin_imapbase
|
||||
{
|
||||
$pattern = "/\\".$delimiter."/";
|
||||
$reference = preg_replace($pattern, '', $node['MAILBOX']);
|
||||
$mainFolder = $this->icServer->getMailboxes($reference, 1, true);
|
||||
$subFolders = $this->icServer->getMailboxes($node['MAILBOX'].$node['delimiter'], 2, true);
|
||||
$folders[$node['MAILBOX']] = array_merge((array)$mainFolder, (array)$subFolders);
|
||||
ksort($folders[$node['MAILBOX']]);
|
||||
$mainFolder = $subFolders = array();
|
||||
|
||||
// Get special use folders
|
||||
if (!isset(self::$specialUseFolders)) $this->getSpecialUseFolders (); // Set self::$sepecialUseFolders
|
||||
// Create autofolders if they all not created yet
|
||||
if (count(self::$autoFolders) > count(self::$specialUseFolders)) $this->check_create_autofolders(self::$specialUseFolders);
|
||||
// Merge of all auto folders and specialusefolders
|
||||
$autoFoldersTmp = array_unique((array_merge(self::$autoFolders, array_values(self::$specialUseFolders))));
|
||||
|
||||
if ($_subscribedOnly)
|
||||
{
|
||||
$mainFolder = $this->icServer->listSubscribedMailboxes($reference, 1, true);
|
||||
$subFolders = $this->icServer->listSubscribedMailboxes($node['MAILBOX'].$node['delimiter'], $_search, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$mainFolder = $this->icServer->getMailboxes($reference, 1, true);
|
||||
$subFolders = $this->icServer->getMailboxes($node['MAILBOX'].$node['delimiter'], $_search, true);
|
||||
}
|
||||
if (is_array($mainFolder['INBOX']))
|
||||
{
|
||||
// Array container of auto folders
|
||||
$aFolders = array();
|
||||
|
||||
// Array container of non auto folders
|
||||
$nFolders = array();
|
||||
|
||||
foreach ($subFolders as $path => $folder)
|
||||
{
|
||||
$folderInfo = mail_tree::pathToFolderData($folder['MAILBOX'], $folder['delimiter']);
|
||||
if (in_array(trim($folderInfo['name']), $autoFoldersTmp))
|
||||
{
|
||||
$aFolders [$path] = $folder;
|
||||
}
|
||||
else
|
||||
{
|
||||
$nFolders [$path] = $folder;
|
||||
}
|
||||
}
|
||||
if (is_array($aFolders)) uasort ($aFolders, array($this,'sortByAutofolder'));
|
||||
ksort($aFolders);
|
||||
$subFolders = array_merge($aFolders,$nFolders);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($subFolders)) ksort($subFolders);
|
||||
}
|
||||
$folders = array_merge($folders,(array)$mainFolder, (array)$subFolders);
|
||||
}
|
||||
}
|
||||
elseif ($_nodePath) // single node
|
||||
@ -2672,13 +2726,36 @@ class emailadmin_imapbase
|
||||
$path = $_nodePath;
|
||||
break;
|
||||
}
|
||||
$folders = $this->icServer->getMailboxes($path, $_search, true);
|
||||
if ($_subscribedOnly)
|
||||
{
|
||||
$folders = $this->icServer->listSubscribedMailboxes($path, $_search, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$folders = $this->icServer->getMailboxes($path, $_search, true);
|
||||
}
|
||||
|
||||
ksort($folders);
|
||||
return $folders;
|
||||
}
|
||||
elseif(!$_nodePath)
|
||||
elseif(!$_nodePath) // all
|
||||
{
|
||||
$folders = $this->icServer->getMailboxes('', 0, true);
|
||||
if ($_subscribedOnly)
|
||||
{
|
||||
$folders = $this->icServer->listSubscribedMailboxes('', 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$folders = $this->icServer->getMailboxes('', 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Get counter information and add them to each fetched folders array
|
||||
if ($_getCounter)
|
||||
{
|
||||
foreach ($folders as &$folder)
|
||||
{
|
||||
$folder['counter'] = $this->icServer->getMailboxCounters($folder['MAILBOX']);
|
||||
}
|
||||
}
|
||||
return $folders;
|
||||
}
|
||||
@ -2722,7 +2799,42 @@ class emailadmin_imapbase
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sortByName
|
||||
*
|
||||
* Helper function to sort folders array by name
|
||||
* @param array $a
|
||||
* @param array $b array of folders
|
||||
* @return int expect values (0, 1 or -1)
|
||||
*/
|
||||
function sortByName($a,$b)
|
||||
{
|
||||
$a = mail_tree::pathToFolderData($a['MAILBOX'], $a['delimiter']);
|
||||
$b = mail_tree::pathToFolderData($b['MAILBOX'], $b['delimiter']);
|
||||
// 0, 1 und -1
|
||||
return strcasecmp($a['name'],$b['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* sortByAutoFolderPos
|
||||
*
|
||||
* Helper function to sort folder-objects by auto Folder Position
|
||||
* @param array $a
|
||||
* @param array $b
|
||||
* @return int expect values (0, 1 or -1)
|
||||
*/
|
||||
function sortByAutoFolder($a,$b)
|
||||
{
|
||||
// 0, 1 und -1
|
||||
$a = mail_tree::pathToFolderData($a['MAILBOX'], $a['delimiter']);
|
||||
$b = mail_tree::pathToFolderData($b['MAILBOX'], $b['delimiter']);
|
||||
$pos1 = array_search(trim($a['name']),self::$autoFolders);
|
||||
$pos2 = array_search(trim($b['name']),self::$autoFolders);
|
||||
if ($pos1 == $pos2) return 0;
|
||||
return ($pos1 < $pos2) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* sortByDisplayName
|
||||
*
|
||||
@ -2819,7 +2931,7 @@ class emailadmin_imapbase
|
||||
if (is_array($mbx[$mbxkeys[0]]["ATTRIBUTES"]) && (in_array('\HasChildren',$mbx[$mbxkeys[0]]["ATTRIBUTES"]) || in_array('\Haschildren',$mbx[$mbxkeys[0]]["ATTRIBUTES"]) || in_array('\haschildren',$mbx[$mbxkeys[0]]["ATTRIBUTES"]))) {
|
||||
// if there are children fetch them
|
||||
//echo $mbx[$mbxkeys[0]]['MAILBOX']."<br>";
|
||||
|
||||
|
||||
$buff = $this->icServer->getMailboxes($mbx[$mbxkeys[0]]['MAILBOX'].($mbx[$mbxkeys[0]]['MAILBOX'] == $prefix ? '':$delimiter),2,false);
|
||||
//$buff = $this->icServer->getMailboxes($mbx[$mbxkeys[0]]['MAILBOX'],2,false);
|
||||
//_debug_array($buff);
|
||||
@ -3206,6 +3318,7 @@ class emailadmin_imapbase
|
||||
* @param string _forceDeleteMethod - "no", or deleteMethod like 'move_to_trash',"mark_as_deleted","remove_immediately"
|
||||
*
|
||||
* @return bool true, as we do not handle return values yet
|
||||
* @throws egw_exception
|
||||
*/
|
||||
function deleteMessages($_messageUID, $_folder=NULL, $_forceDeleteMethod='no')
|
||||
{
|
||||
@ -3529,6 +3642,7 @@ class emailadmin_imapbase
|
||||
* @param int $_targetProfileID - target profile ID, should only be handed over when target server is different from source
|
||||
*
|
||||
* @return mixed/bool true,false or new uid
|
||||
* @throws egw_exception
|
||||
*/
|
||||
function moveMessages($_foldername, $_messageUID, $deleteAfterMove=true, $currentFolder = Null, $returnUIDs = false, $_sourceProfileID = Null, $_targetProfileID = Null)
|
||||
{
|
||||
@ -3825,7 +3939,7 @@ class emailadmin_imapbase
|
||||
case 'BASE64':
|
||||
// use imap_base64 to decode, not any longer, as it is strict, and fails if it encounters invalid chars
|
||||
return base64_decode($_mimeMessage);
|
||||
|
||||
|
||||
case 'QUOTED-PRINTABLE':
|
||||
// use imap_qprint to decode
|
||||
return quoted_printable_decode($_mimeMessage);
|
||||
@ -5386,6 +5500,7 @@ class emailadmin_imapbase
|
||||
* @param string _flags = '\\Recent'the imap flags to set for the saved message
|
||||
*
|
||||
* @return the id of the message appended or exception
|
||||
* @throws egw_exception_wrong_userinput
|
||||
*/
|
||||
function appendMessage($_folderName, $_header, $_body, $_flags='\\Recent')
|
||||
{
|
||||
@ -5774,6 +5889,8 @@ class emailadmin_imapbase
|
||||
* @param string $IDtoAddToFileName id to enrich the returned tmpfilename
|
||||
* @param string $reqMimeType /(default message/rfc822, if set to false, mimetype check will not be performed
|
||||
* @return mixed $fullPathtoFile or exception
|
||||
*
|
||||
* @throws egw_exception_wrong_userinput
|
||||
*/
|
||||
static function checkFileBasics(&$_formData, $IDtoAddToFileName='', $reqMimeType='message/rfc822')
|
||||
{
|
||||
@ -5940,7 +6057,7 @@ class emailadmin_imapbase
|
||||
$basedir = 'vfs://default';
|
||||
$needTempFile = false;
|
||||
}
|
||||
|
||||
|
||||
// If it is an inline image url, we need to fetch the actuall attachment
|
||||
// content and later on to be able to store its content as temp file
|
||||
if (strpos($myUrl, '/index.php?menuaction=mail.mail_ui.displayImage') !== false)
|
||||
@ -5948,7 +6065,7 @@ class emailadmin_imapbase
|
||||
$URI_params = array();
|
||||
// Strips the url and store it into a temp for further procss
|
||||
$tmp_url = html_entity_decode($myUrl);
|
||||
|
||||
|
||||
parse_str(parse_url($tmp_url, PHP_URL_QUERY),$URI_params);
|
||||
if ($URI_params['mailbox'] && $URI_params['uid'] && $URI_params['cid'])
|
||||
{
|
||||
@ -5963,7 +6080,7 @@ class emailadmin_imapbase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( strlen($basedir) > 1 && substr($basedir,-1) != '/' && $myUrl[0]!='/') { $basedir .= '/'; }
|
||||
if ($needTempFile && !$attachment) $data = file_get_contents($basedir.urldecode($myUrl));
|
||||
}
|
||||
@ -6073,7 +6190,7 @@ class emailadmin_imapbase
|
||||
$AltBody = ($html_body = $mailObject->findBody('html')) ? $html_body->getContents() : null;
|
||||
//error_log(__METHOD__.' ('.__LINE__.') '.' AltBody:'.$AltBody);
|
||||
//error_log(__METHOD__.' ('.__LINE__.') '.array2string($mailObject->GetReplyTo()));
|
||||
|
||||
|
||||
// Fetch ReplyTo - Address if existing to check if we are to replace it
|
||||
$replyTo = $mailObject->getReplyTo();
|
||||
if (isset($replyTo['replace@import.action']))
|
||||
@ -6289,7 +6406,7 @@ class emailadmin_imapbase
|
||||
*
|
||||
* @param egw_mailer $mailer instance of SMTP Mailer object
|
||||
* @param string|ressource|Horde_Mime_Part $message string or resource containing the RawMessage / object Mail_mimeDecoded message (part))
|
||||
* @throws egw_exception_assertion_failed when the required Horde_Mail_Part not found
|
||||
* @throws egw_exception_wrong_parameter when the required Horde_Mail_Part not found
|
||||
*/
|
||||
function parseRawMessageIntoMailObject(egw_mailer $mailer, $message)
|
||||
{
|
||||
@ -6396,7 +6513,7 @@ class emailadmin_imapbase
|
||||
function addAccount($_hookValues)
|
||||
{
|
||||
error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE YET!' . ' hookValue = '. $_hookValues);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6410,7 +6527,7 @@ class emailadmin_imapbase
|
||||
function deleteAccount($_hookValues)
|
||||
{
|
||||
error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE YET!' . ' hookValue = '. $_hookValues);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6424,6 +6541,6 @@ class emailadmin_imapbase
|
||||
function updateAccount($_hookValues)
|
||||
{
|
||||
error_log(__METHOD__.' ('.__LINE__.') '.' NOT DONE YET!' . ' hookValue = '. $_hookValues);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,18 @@ var et2_tree = et2_inputWidget.extend(
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "comma-separated names of icons for a leaf, closed and opend folder (default: leaf.gif,folderClosed.gif,folderOpen.gif), images with extension get loaded from image_path, just 'image' or 'appname/image' are allowed too"
|
||||
},
|
||||
"multimarking": {
|
||||
"name": "multimarking",
|
||||
"type": "any",
|
||||
"default": false,
|
||||
"description": "Allow marking multiple nodes, default is false which means disabled multiselection, true or 'strict' activates it and 'strict' makes it strick to only same level marking"
|
||||
},
|
||||
highlighting:{
|
||||
"name": "highlighting",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Add highlighting class on hovered over item, highlighting is disabled by default"
|
||||
}
|
||||
},
|
||||
|
||||
@ -218,6 +230,13 @@ var et2_tree = et2_inputWidget.extend(
|
||||
widget.input.setXMLAutoLoading(egw.link(url));
|
||||
widget.input.setDataMode('JSON');
|
||||
}
|
||||
|
||||
if (widget.options.multimarking)
|
||||
{
|
||||
widget.input.enableMultiselection(!!widget.options.multimarking, widget.options.multimarking === 'strict');
|
||||
}
|
||||
// Enable/Disable highlighting
|
||||
widget.input.enableHighlighting(widget.options.highlighting?true:false);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -99,6 +99,7 @@ class mail_tree
|
||||
*/
|
||||
static function pathToFolderData ($_path, $_hDelimiter)
|
||||
{
|
||||
if (!strpos($_path, self::$delimiter)) $_path = self::$delimiter.$_path;
|
||||
list(,$path) = explode(self::$delimiter, $_path);
|
||||
$path_chain = $parts = explode($_hDelimiter, $path);
|
||||
$name = array_pop($parts);
|
||||
@ -126,7 +127,37 @@ class mail_tree
|
||||
in_array('\HasChildren', $_node['ATTRIBUTES'])) $hasChildren = 1;
|
||||
return $hasChildren;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
list(,$leaf) = explode(self::$delimiter, $_node);
|
||||
if ($leaf || $_node == null) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* getTree provides tree structure regarding to selected node
|
||||
*
|
||||
@ -135,10 +166,13 @@ class mail_tree
|
||||
* @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 $_noCheckboxNS = false no checkbox for namesapaces makes sure to not put checkbox for namespaces node
|
||||
* @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
|
||||
* @param boolean $_checkSubscribed = true, pre-check checkboxes of subscribed folders
|
||||
*
|
||||
* @return array returns an array of mail tree structure according to provided node
|
||||
*/
|
||||
function getTree ($_parent = null, $_profileID = '', $_openTopLevel = 1, $_noCheckboxNS = false)
|
||||
function getTree ($_parent = null, $_profileID = '', $_openTopLevel = 1, $_noCheckboxNS = false, $_subscribedOnly= false, $_allInOneGo = false, $_checkSubscribed = true)
|
||||
{
|
||||
//Init mail folders
|
||||
$tree = array(tree::ID=> $_parent?$_parent:0,tree::CHILDREN => array());
|
||||
@ -156,166 +190,114 @@ class mail_tree
|
||||
}
|
||||
}
|
||||
|
||||
if ($_parent) // Single node loader
|
||||
try
|
||||
{
|
||||
try
|
||||
// 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),
|
||||
);
|
||||
if ($_parent && !self::isAccountNode($_parent)) // Single node loader
|
||||
{
|
||||
$nodeInfo = self::pathToFolderData($_parent, $hDelimiter);
|
||||
$folders = $this->ui->mail_bo->getFolderArray($nodeInfo['mailbox'],false,2);
|
||||
} catch (Exception $ex) {
|
||||
return self::treeLeafNoConnectionArray($_profileID, $ex->getMessage(),array($_profileID), '');
|
||||
}
|
||||
|
||||
$childrenNode = array();
|
||||
foreach ($folders as &$node)
|
||||
{
|
||||
$nodeId = $_profileID.self::$delimiter.$node['MAILBOX'];
|
||||
$nodeData = self::pathToFolderData($nodeId, $node['delimiter']);
|
||||
$childrenNode[] = array(
|
||||
tree::ID=> $nodeId,
|
||||
tree::AUTOLOAD_CHILDREN => 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['folderClose'],
|
||||
tree::CHECKED => $node['SUBSCRIBED'],
|
||||
'parent' => $_parent
|
||||
);
|
||||
}
|
||||
$tree[tree::CHILDREN] = $childrenNode;
|
||||
}
|
||||
else //Top Level Nodes loader
|
||||
{
|
||||
$baseNode = array('id' => 0);
|
||||
foreach(emailadmin_account::search(true, false) as $acc_id => $accObj)
|
||||
{
|
||||
if (!$accObj->is_imap()|| $acc_id != $_profileID) continue;
|
||||
$identity = emailadmin_account::identity_name($accObj,true,$GLOBALS['egw_info']['user']['acount_id']);
|
||||
$baseNode = array(
|
||||
tree::ID=> $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,
|
||||
// mark on account if Sieve is enabled
|
||||
'data' => array(
|
||||
'sieve' => $accObj->imapServer()->acc_sieve_enabled,
|
||||
'spamfolder'=> $accObj->imapServer()->acc_folder_junk?true:false
|
||||
),
|
||||
tree::NOCHECKBOX => $_noCheckboxNS
|
||||
);
|
||||
self::setOutStructure($baseNode, $tree,self::$delimiter);
|
||||
}
|
||||
//List of folders
|
||||
$foldersList = $this->ui->mail_bo->getFolderArray(null, true);
|
||||
|
||||
// Parent node arrays
|
||||
$parentNode = $parentNodes = array();
|
||||
|
||||
foreach ($foldersList as $index => $topFolder)
|
||||
{
|
||||
$nameSpaces = $this->ui->mail_bo->_getNameSpaces();
|
||||
$noCheckbox = false;
|
||||
foreach ($nameSpaces as &$ns)
|
||||
{
|
||||
if($_noCheckboxNS && $ns['prefix'] === $index.$hDelimiter) $noCheckbox = true;
|
||||
}
|
||||
$parentNode = array(
|
||||
tree::ID=>$_profileID.self::$delimiter.$topFolder[$index]['MAILBOX'],
|
||||
tree::AUTOLOAD_CHILDREN => self::nodeHasChildren($topFolder[$index]),
|
||||
tree::CHILDREN =>array(),
|
||||
tree::LABEL =>lang($topFolder[$index]['MAILBOX']),
|
||||
tree::OPEN => $_openTopLevel,
|
||||
tree::TOOLTIP => lang($topFolder[$index]['MAILBOX']),
|
||||
tree::CHECKED => $topFolder[$index]['SUBSCRIBED'],
|
||||
tree::NOCHECKBOX => $noCheckbox
|
||||
);
|
||||
if ($index === "INBOX")
|
||||
{
|
||||
$parentNode[tree::IMAGE_LEAF] = self::$leafImages['folderHome'];
|
||||
$parentNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderHome'];
|
||||
$parentNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderHome'];
|
||||
}
|
||||
if(stripos(array2string($topFolder[$index]['ATTRIBUTES']),'\noselect')!== false)
|
||||
{
|
||||
$parentNode[tree::IMAGE_LEAF] = self::$leafImages['folderNoSelectClosed'];
|
||||
$parentNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderNoSelectOpen'];
|
||||
$parentNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderNoSelectClosed'];
|
||||
}
|
||||
// Save parentNodes
|
||||
$parentNodes []= $index;
|
||||
// Remove the parent nodes from the list
|
||||
unset ($topFolder[$index]);
|
||||
$folders = $this->ui->mail_bo->getFolderArrays($nodeInfo['mailbox'],false,$_allInOneGo?0:2, $_subscribedOnly);
|
||||
|
||||
//$parentNode[tree::CHILDREN][] =$childrenNode;
|
||||
$baseNode[tree::CHILDREN][] = $parentNode;
|
||||
}
|
||||
foreach ($parentNodes as $pIndex => $parent)
|
||||
{
|
||||
$childrenNodes = $childNode = array();
|
||||
$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),
|
||||
);
|
||||
// Iterate over childern of each top folder(namespaces)
|
||||
foreach ($foldersList[$parent] as &$node)
|
||||
$childrenNode = array();
|
||||
foreach ($folders as &$node)
|
||||
{
|
||||
// Skipe the parent node itself
|
||||
if (is_array($foldersList[$parent][$parent]) &&
|
||||
$foldersList[$parent][$parent]['MAILBOX'] === $node['MAILBOX']) continue;
|
||||
|
||||
$pathArr = explode($node['delimiter'], $node['MAILBOX']);
|
||||
$folderName = array_pop($pathArr);
|
||||
$parentPath = $_profileID.self::$delimiter.implode($pathArr,$node['delimiter']);
|
||||
|
||||
$nodeId = $_profileID.self::$delimiter.$node['MAILBOX'];
|
||||
|
||||
$childNode = array(
|
||||
tree::ID => $nodeId,
|
||||
tree::AUTOLOAD_CHILDREN => self::nodeHasChildren($node),
|
||||
tree::CHILDREN => array(),
|
||||
tree::LABEL => lang($folderName),
|
||||
'parent' => $parentPath,
|
||||
tree::CHECKED => $node['SUBSCRIBED']
|
||||
$nodeData = self::pathToFolderData($nodeId, $node['delimiter']);
|
||||
$childrenNode[] = array(
|
||||
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['folderClose'],
|
||||
tree::CHECKED => $_checkSubscribed?$node['SUBSCRIBED']:false,
|
||||
'parent' => $_parent
|
||||
);
|
||||
|
||||
if (array_search($node['MAILBOX'], $definedFolders) !== false)
|
||||
}
|
||||
$tree[tree::CHILDREN] = $childrenNode;
|
||||
}
|
||||
else //Top Level Nodes loader
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//List of folders
|
||||
$foldersList = $this->ui->mail_bo->getFolderArrays(null, true, $_allInOneGo?0:2,$_subscribedOnly, true);
|
||||
foreach ($foldersList as &$folder)
|
||||
{
|
||||
$path = $parent = $parts = explode($folder['delimiter'], $folder['MAILBOX']);
|
||||
array_pop($parent);
|
||||
|
||||
array_unshift($path, $_profileID);
|
||||
|
||||
$data = array(
|
||||
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,
|
||||
'path' => $path,
|
||||
'folderarray' => $folder
|
||||
);
|
||||
// Set Acl capability for INBOX
|
||||
if ($folder['MAILBOX'] === "INBOX")
|
||||
{
|
||||
//User defined folders icons
|
||||
$childNode[tree::IMAGE_LEAF] =
|
||||
$childNode[tree::IMAGE_FOLDER_OPEN] =
|
||||
$childNode [tree::IMAGE_FOLDER_CLOSED] = "MailFolder".$folderName.".png";
|
||||
}
|
||||
elseif(stripos(array2string($node['ATTRIBUTES']),'\noselect')!== false)
|
||||
{
|
||||
$childNode[tree::IMAGE_LEAF] = self::$leafImages['folderNoSelectClosed'];
|
||||
$childNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderNoSelectOpen'];
|
||||
$childNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderNoSelectClosed'];
|
||||
$data['data'] = array('acl' => $this->ui->mail_bo->icServer->queryCapability('ACL'));
|
||||
$data[tree::NOCHECKBOX] = $_noCheckboxNS;
|
||||
}
|
||||
else
|
||||
{
|
||||
$childNode[tree::IMAGE_LEAF] = self::$leafImages['folderLeaf'];
|
||||
$childNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderOpen'];
|
||||
$childNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderClose'];
|
||||
//Do not open Initially other folders but INBOX
|
||||
$data[tree::OPEN] = 0;
|
||||
}
|
||||
$childrenNodes[] = $childNode;
|
||||
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))
|
||||
{
|
||||
$tree = array(
|
||||
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']
|
||||
);
|
||||
}
|
||||
$baseNode[tree::CHILDREN][$pIndex][tree::CHILDREN] = $childrenNodes;
|
||||
}
|
||||
$tree[tree::CHILDREN][0] = $baseNode;
|
||||
}
|
||||
catch (Exception $ex) // Catch exceptions
|
||||
{
|
||||
//mail_ui::callWizard($ex->getMessage(), false, 'error');
|
||||
return self::treeLeafNoConnectionArray($_profileID, $ex->getMessage(),array($_profileID), '');
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
@ -330,7 +312,7 @@ class mail_tree
|
||||
* as clearance for access may be limited to a single branch-node of a tree
|
||||
* @return void
|
||||
*/
|
||||
static function setOutStructure($data, &$out, $del='.', $createMissingParents=true, $nameSpace=array())
|
||||
static function setOutStructure($data, &$out, $del='.', $createMissingParents=true, $nameSpace=array(), $definedFolders= array())
|
||||
{
|
||||
//error_log(__METHOD__."(".array2string($data).', '.array2string($out).", '$del')");
|
||||
$components = $data['path'];
|
||||
@ -400,9 +382,133 @@ class mail_tree
|
||||
}
|
||||
$parents[] = $component;
|
||||
}
|
||||
if ($data['folderarray']['delimiter'] && $data['folderarray']['MAILBOX'])
|
||||
{
|
||||
$path = explode($data['folderarray']['delimiter'], $data['folderarray']['MAILBOX']);
|
||||
$folderName = array_pop($path);
|
||||
|
||||
if ($data['folderarray']['MAILBOX'] === "INBOX")
|
||||
{
|
||||
$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);
|
||||
}
|
||||
// User defined folders may get different icons
|
||||
// plus they need to be translated too
|
||||
elseif (($key = array_search($data['folderarray']['MAILBOX'], $definedFolders, true)) !== false)
|
||||
{
|
||||
$data[tree::LABEL] = lang($key);
|
||||
$data[tree::TOOLTIP] = lang($key);
|
||||
//User defined folders icons
|
||||
$data[tree::IMAGE_LEAF] =
|
||||
$data[tree::IMAGE_FOLDER_OPEN] =
|
||||
$data [tree::IMAGE_FOLDER_CLOSED] = "MailFolder".$key.".png";
|
||||
}
|
||||
elseif(stripos(array2string($data['folderarray']['attributes']),'\noselect')!== false)
|
||||
{
|
||||
$data[tree::IMAGE_LEAF] = self::$leafImages['folderNoSelectClosed'];
|
||||
$data[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderNoSelectOpen'];
|
||||
$data[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderNoSelectClosed'];
|
||||
}
|
||||
elseif ($data['parent'])
|
||||
{
|
||||
$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['folderClose'];
|
||||
}
|
||||
|
||||
// Contains unseen mails for the folder
|
||||
$unseen = $data['folderarray']['counter']['UNSEEN'];
|
||||
|
||||
// if there's unseen mails then change the label and style
|
||||
// accordingly to indicate useen mails
|
||||
if ($unseen > 0)
|
||||
{
|
||||
$data[tree::LABEL] = $data[tree::LABEL].'('.$unseen.')';
|
||||
$data['style'] = 'font-weight: bold';
|
||||
}
|
||||
}
|
||||
//Remove extra data from tree structure
|
||||
unset($data['folderarray']);
|
||||
unset($data['path']);
|
||||
|
||||
$insert['item'][] = $data;
|
||||
//error_log(__METHOD__."() leaving with out=".array2string($out));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
$roots = array(tree::ID => 0, tree::CHILDREN => array());
|
||||
|
||||
foreach(emailadmin_account::search(true, false) as $acc_id => $accObj)
|
||||
{
|
||||
if (!$accObj->is_imap()|| $_profileID && $acc_id != $_profileID) continue;
|
||||
$identity = emailadmin_account::identity_name($accObj,true,$GLOBALS['egw_info']['user']['acount_id']);
|
||||
// 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?$_openTopLevel:$openActiveAccount,
|
||||
// mark on account if Sieve is enabled
|
||||
'data' => array(
|
||||
'sieve' => $accObj->imapServer()->acc_sieve_enabled,
|
||||
'spamfolder'=> $accObj->imapServer()->acc_folder_junk?true:false
|
||||
),
|
||||
tree::NOCHECKBOX => $_noCheckbox
|
||||
);
|
||||
self::setOutStructure($baseNode, $roots,self::$delimiter);
|
||||
}
|
||||
return $roots;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
* @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)
|
||||
{
|
||||
$tree = $this->getTree($_parent, $_profileID, $_openTopLevel, false, $_subscribedOnly, $_allInOneGo);
|
||||
$activeAccount = $GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'];
|
||||
$branches = $this->getTree($activeAccount, $activeAccount,1,false,$_subscribedOnly,$_allInOneGo);
|
||||
foreach ($tree[tree::CHILDREN] as &$account)
|
||||
{
|
||||
if ($account[tree::ID] == $activeAccount)
|
||||
{
|
||||
$account = $branches;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ class mail_ui
|
||||
*/
|
||||
function __construct($run_constructor=true)
|
||||
{
|
||||
$this->mail_tree = new mail_tree($this);
|
||||
if (!$run_constructor) return;
|
||||
|
||||
if (mail_bo::$debugTimes) $starttime = microtime (true);
|
||||
@ -142,7 +143,6 @@ class mail_ui
|
||||
//openConnection gathers SpecialUseFolderInformation and Delimiter Info
|
||||
$this->mail_bo->openConnection(self::$icServerID);
|
||||
}
|
||||
$this->mail_tree = new mail_tree($this);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
@ -203,6 +203,8 @@ class mail_ui
|
||||
*
|
||||
* @param int $_icServerID
|
||||
* @param boolean $unsetCache
|
||||
*
|
||||
* @throws egw_exception
|
||||
*/
|
||||
function changeProfile($_icServerID,$unsetCache=false)
|
||||
{
|
||||
@ -360,7 +362,7 @@ class mail_ui
|
||||
$response = egw_json_response::get();
|
||||
foreach($refreshData as $folder => &$name)
|
||||
{
|
||||
$name = $this->getFolderTree(true, $folder, true, true, false);
|
||||
$name = $this->mail_tree->getTree($folder, $profileId,1,true,true,true);
|
||||
}
|
||||
// give success/error message to opener and popup itself
|
||||
//$response->call('opener.app.mail.subscription_refresh',$refreshData);
|
||||
@ -480,7 +482,7 @@ class mail_ui
|
||||
$content[self::$nm_index]['vacationrange'] = $sel_options[self::$nm_index]['vacationrange'] = '';
|
||||
}
|
||||
//$zstarttime = microtime (true);
|
||||
$sel_options[self::$nm_index]['foldertree'] = $this->getFolderTree('initial',null,!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']);
|
||||
$sel_options[self::$nm_index]['foldertree'] = $this->mail_tree->getInitialIndexTree(null, null, null, true,!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']);
|
||||
//$zendtime = microtime(true) - $zstarttime;
|
||||
//error_log(__METHOD__.__LINE__. " time used: ".$zendtime);
|
||||
$content[self::$nm_index]['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.(!empty($this->mail_bo->sessionData['mailbox'])?$this->mail_bo->sessionData['mailbox']:'INBOX');
|
||||
@ -663,6 +665,19 @@ class mail_ui
|
||||
);
|
||||
break;
|
||||
}
|
||||
++$group; // put empty spam immediately in own group
|
||||
$junkFolder = $this->mail_bo->getJunkFolder();
|
||||
//error_log(__METHOD__.__LINE__.$junkFolder);
|
||||
if ($junkFolder && !empty($junkFolder))
|
||||
{
|
||||
$tree_actions['empty_spam'] = array(
|
||||
'caption' => 'empty junk',
|
||||
'icon' => 'dhtmlxtree/MailFolderJunk',
|
||||
'enabled' => 'javaScript:app.mail.spamfolder_enabled',
|
||||
'onExecute' => 'javaScript:app.mail.mail_emptySpam',
|
||||
'group' => $group,
|
||||
);
|
||||
}
|
||||
|
||||
// enforce global (group-specific) ACL
|
||||
if (!mail_hooks::access('aclmanagement'))
|
||||
@ -735,224 +750,19 @@ class mail_ui
|
||||
*/
|
||||
public function ajax_foldertree($_nodeID = null,$_subscribedOnly=null)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.':'.$_nodeID.'->'.$_subscribedOnly);
|
||||
$nodeID = $_GET['id'];
|
||||
if (!is_null($_nodeID)) $nodeID = $_nodeID;
|
||||
$subscribedOnly = (bool)(!is_null($_subscribedOnly)?$_subscribedOnly:!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']);
|
||||
$fetchCounters = !is_null($_nodeID);
|
||||
list($_profileID,$_folderName) = explode(self::$delimiter,$nodeID,2);
|
||||
unset($_profileID);
|
||||
|
||||
if (!empty($_folderName)) $fetchCounters = true;
|
||||
//error_log(__METHOD__.__LINE__.':'.$nodeID.'->'.array2string($fetchCounters));
|
||||
$data = $this->getFolderTree($fetchCounters, $nodeID, $subscribedOnly,true,true,false);
|
||||
//error_log(__METHOD__.__LINE__.':'.$nodeID.'->'.array2string($data));
|
||||
|
||||
$data = $this->mail_tree->getTree($nodeID,$_profileID,0, false,$subscribedOnly,!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']);
|
||||
if (!is_null($_nodeID)) return $data;
|
||||
etemplate_widget_tree::send_quote_json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* getFolderTree, get folders from server and prepare the folder tree
|
||||
* @param mixed bool/string $_fetchCounters, wether to fetch extended information on folders
|
||||
* if set to initial, only for initial level of seen (unfolded) folders
|
||||
* @param string $_nodeID nodeID to fetch and return
|
||||
* @param boolean $_subscribedOnly flag to tell wether to fetch all or only subscribed (default)
|
||||
* @param boolean $_returnNodeOnly only effective if $_nodeID is set, and $_nodeID is_nummeric
|
||||
* @param boolean _useCacheIfPossible - if set to false cache will be ignored and reinitialized
|
||||
* @param boolean $_popWizard Check if getFoldertree is called via open account (TRUE) or via tree interaction (FALSE), to control wizard popup
|
||||
* @return array something like that: array('id'=>0,
|
||||
* 'item'=>array(
|
||||
* 'text'=>'INBOX',
|
||||
* 'tooltip'=>'INBOX'.' '.lang('(not connected)'),
|
||||
* 'im0'=>'kfm_home.png'
|
||||
* 'item'=>array($MORE_ITEMS)
|
||||
* )
|
||||
* );
|
||||
*/
|
||||
function getFolderTree($_fetchCounters=false, $_nodeID=null, $_subscribedOnly=true, $_returnNodeOnly=true, $_useCacheIfPossible=true, $_popWizard=true)
|
||||
{
|
||||
if (mail_bo::$debugTimes) $starttime = microtime (true);
|
||||
if (!is_null($_nodeID) && $_nodeID != 0)
|
||||
{
|
||||
list($_profileID,$_folderName) = explode(self::$delimiter,$_nodeID,2);
|
||||
unset($_folderName);
|
||||
if (is_numeric($_profileID))
|
||||
{
|
||||
if ($_profileID && $_profileID != $this->mail_bo->profileID)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$_profileID);
|
||||
try
|
||||
{
|
||||
$this->changeProfile($_profileID);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return mail_tree::treeLeafNoConnectionArray($_profileID, $e->getMessage(), array($_profileID), '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//$starttime = microtime(true);
|
||||
$c = 0;
|
||||
try
|
||||
{
|
||||
$folderObjects = $this->mail_bo->getFolderObjects($_subscribedOnly,false,false,$_useCacheIfPossible);
|
||||
//$endtime = microtime(true) - $starttime;
|
||||
//error_log(__METHOD__.__LINE__.' Fetching folderObjects took: '.$endtime);
|
||||
$userDefinedFunctionFolders = array(
|
||||
'Trash' => $this->mail_bo->getTrashFolder(false),
|
||||
'Templates' => $this->mail_bo->getTemplateFolder(false),
|
||||
'Drafts' => $this->mail_bo->getDraftFolder(false),
|
||||
'Sent' => $this->mail_bo->getSentFolder(false),
|
||||
'Junk' => $this->mail_bo->getJunkFolder(false),
|
||||
'Outbox' => $this->mail_bo->getOutboxFolder(false),
|
||||
);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
error_log(__LINE__.': '.__METHOD__."() ".$e->getMessage());
|
||||
$folderObjects=array();
|
||||
if ($_popWizard)
|
||||
{
|
||||
self::callWizard($e->getMessage(), false, 'error');
|
||||
}
|
||||
$c = 1;
|
||||
}
|
||||
|
||||
$out = array('id' => 0);
|
||||
|
||||
//$starttime = microtime(true);
|
||||
foreach(emailadmin_account::search($only_current_user=true, false) as $acc_id => $accountObj)
|
||||
{
|
||||
if ($_profileID && $acc_id != $_profileID)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.' Fetching accounts '." $acc_id != $_profileID ".'->'.$identity_name);
|
||||
continue;
|
||||
}
|
||||
//error_log(__METHOD__.__LINE__.array2string($accountObj));
|
||||
if (!$accountObj->is_imap())
|
||||
{
|
||||
// not to be used for IMAP Foldertree, as there is no Imap host
|
||||
continue;
|
||||
}
|
||||
$identity_name = emailadmin_account::identity_name($accountObj,true,$GLOBALS['egw_info']['user']['acount_id']);
|
||||
$oA = array('id' => $acc_id,
|
||||
'text' => str_replace(array('<','>'),array('[',']'),$identity_name),// as angle brackets are quoted, display in Javascript messages when used is ugly, so use square brackets instead
|
||||
'tooltip' => '('.$acc_id.') '.htmlspecialchars_decode($identity_name),
|
||||
'im0' => 'thunderbird.png',
|
||||
'im1' => 'thunderbird.png',
|
||||
'im2' => 'thunderbird.png',
|
||||
'path'=> array($acc_id),
|
||||
'child'=> (int)($acc_id != $_profileID || $folderObjects), // dynamic loading on unfold
|
||||
'parent' => '',
|
||||
// mark on account if Sieve is enabled
|
||||
'data' => array('sieve' => $accountObj->imapServer()->acc_sieve_enabled),
|
||||
);
|
||||
mail_tree::setOutStructure($oA, $out, self::$delimiter);
|
||||
|
||||
// create a fake INBOX folder showing connection error (necessary that client UI unlocks tree!)
|
||||
if ($e && $acc_id == $_profileID && !$folderObjects)
|
||||
{
|
||||
$out = mail_tree::treeLeafNoConnectionArray($acc_id, lang($e->getMessage()), array($acc_id, 'INBOX'), $acc_id);
|
||||
}
|
||||
}
|
||||
//$endtime = microtime(true) - $starttime;
|
||||
|
||||
if (!empty($folderObjects))
|
||||
{
|
||||
$delimiter = $this->mail_bo->getHierarchyDelimiter();
|
||||
$cmb = $this->mail_bo->icServer->getCurrentMailbox();
|
||||
$cmblevels = explode($delimiter,$cmb);
|
||||
$cmblevelsCt = count($cmblevels);
|
||||
}
|
||||
//error_log(__METHOD__.__LINE__.function_backtrace());
|
||||
// needed in setOutStructure for namespace consistency in folderstructure of others and/or shared
|
||||
$nameSpace = $this->mail_bo->_getNameSpaces();
|
||||
foreach($folderObjects as $key => $obj)
|
||||
{
|
||||
// A1. Comment this part out for the moment to not get performance issue and wierd error
|
||||
// until we re-implement get folder status and mail_tree completely as getFolderTree
|
||||
// method would go anyway.
|
||||
//$fS = $this->mail_bo->getFolderStatus($key,false,($_fetchCounters?false:true));
|
||||
|
||||
//error_log(__METHOD__.__LINE__.array2string($key));
|
||||
$levels = explode($delimiter,$key);
|
||||
$levelCt = count($levels);
|
||||
$fetchCounters = (bool)$_fetchCounters;
|
||||
if ($_fetchCounters==='initial')
|
||||
{
|
||||
if ($levelCt>$cmblevelsCt+1) $fetchCounters=false;
|
||||
}
|
||||
$fFP = $folderParts = explode($obj->delimiter, $key);
|
||||
if (in_array($key,$userDefinedFunctionFolders)) $obj->shortDisplayName = lang($obj->shortDisplayName);
|
||||
//get rightmost folderpart
|
||||
array_pop($folderParts);
|
||||
|
||||
// the rest of the array is the name of the parent
|
||||
$parentName = implode((array)$folderParts,$obj->delimiter);
|
||||
$parentName = $this->mail_bo->profileID.self::$delimiter.$parentName;
|
||||
$oA =array('text'=> $obj->shortDisplayName, 'tooltip'=> $obj->folderName);
|
||||
array_unshift($fFP,$this->mail_bo->profileID);
|
||||
$oA['path'] = $fFP;
|
||||
$path = $key;
|
||||
if ($path=='INBOX')
|
||||
{
|
||||
$oA['im0'] = $oA['im1']= $oA['im2'] = "kfm_home.png";
|
||||
// mark on inbox if ACL is supported
|
||||
$oA['data'] = array('acl' => $this->mail_bo->icServer->queryCapability('ACL'));
|
||||
}
|
||||
elseif (($_key = array_search($obj->folderName, $userDefinedFunctionFolders)) !== false)
|
||||
{
|
||||
$oA['text'] = lang($_key);
|
||||
|
||||
$oA['im0'] = $oA['im1']= $oA['im2'] = "MailFolder".$_key.".png";
|
||||
}
|
||||
else
|
||||
{
|
||||
$oA['im0'] = "MailFolderPlain.png"; // one Level
|
||||
$oA['im1'] = "folderOpen.gif";
|
||||
$oA['im2'] = "MailFolderClosed.png"; // has Children
|
||||
}
|
||||
if ($fetchCounters)
|
||||
{
|
||||
$count = $this->mail_bo->getMailBoxCounters($key,true);
|
||||
if($count->unseen)
|
||||
{
|
||||
$oA['text'] = $oA['text'].' ('.$count->unseen.')';
|
||||
$oA['style'] = 'font-weight: bold';
|
||||
}
|
||||
}
|
||||
$path = $this->mail_bo->profileID.self::$delimiter.$key;
|
||||
$oA['id'] = $path; // ID holds the PATH
|
||||
|
||||
// A2. This part needs to be commented out because of part A1 (see A1). as they are relative
|
||||
/*
|
||||
if (!empty($fS['attributes']) && stripos(array2string($fS['attributes']),'\noselect')!== false)
|
||||
{
|
||||
$oA['im0'] = "folderNoSelectClosed.gif"; // one Level
|
||||
$oA['im1'] = "folderNoSelectOpen.gif";
|
||||
$oA['im2'] = "folderNoSelectClosed.gif"; // has Children
|
||||
}
|
||||
if (!empty($fS['attributes']) && stripos(array2string($fS['attributes']),'\hasnochildren')=== false)
|
||||
{
|
||||
$oA['child']=1; // translates to: hasChildren -> dynamicLoading
|
||||
}*/
|
||||
|
||||
$oA['parent'] = $parentName;
|
||||
|
||||
mail_tree::setOutStructure($oA,$out,$obj->delimiter,true,$nameSpace);
|
||||
$c++;
|
||||
}
|
||||
if (!is_null($_nodeID) && $_nodeID !=0 && $_returnNodeOnly==true)
|
||||
{
|
||||
$node = self::findNode($out,$_nodeID);
|
||||
//error_log(__METHOD__.__LINE__.':'.$_nodeID.'->'.array2string($node));
|
||||
if (mail_bo::$debugTimes) mail_bo::logRunTimes($starttime,null,'return subtree for:'.$_nodeID,__METHOD__.__LINE__);
|
||||
return $node;
|
||||
}
|
||||
if (mail_bo::$debugTimes) mail_bo::logRunTimes($starttime,null,function_backtrace(),__METHOD__.__LINE__);
|
||||
return ($c?$out:array('id'=>0, 'item'=>array('text'=>'INBOX','tooltip'=>'INBOX'.' '.lang('(not connected)'),'im0'=>'kfm_home.png')));
|
||||
}
|
||||
|
||||
/**
|
||||
* findNode - helper function to return only a branch of the tree
|
||||
*
|
||||
@ -2129,7 +1939,10 @@ class mail_ui
|
||||
if (strtoupper($value['mimeType']=='APPLICATION/OCTET-STREAM')) $value['mimeType'] = mime_magic::filename2mime($attachmentHTML[$key]['filename']);
|
||||
$attachmentHTML[$key]['type']=$value['mimeType'];
|
||||
$attachmentHTML[$key]['mimetype']=mime_magic::mime2label($value['mimeType']);
|
||||
list(, $acc_id) = explode(self::$delimiter, $rowID);
|
||||
$hA = self::splitRowID($rowID);
|
||||
$uid = $hA['msgUID'];
|
||||
$mailbox = $hA['folder'];
|
||||
$acc_id = $hA['profileID'];
|
||||
|
||||
$attachmentHTML[$key]['mime_data'] = egw_link::set_data($value['mimeType'], 'emailadmin_imapbase::getAttachmentAccount', array(
|
||||
$acc_id, $mailbox, $uid, $value['partID'], $value['is_winmail'], true
|
||||
@ -2774,7 +2587,7 @@ class mail_ui
|
||||
//error_log(__METHOD__.__LINE__.array2string($bodyParts));
|
||||
// attachments here are only fetched to determine if there is a meeting request
|
||||
// and if. use the appropriate action. so we do not need embedded images
|
||||
$fetchEmbeddedImages = false;
|
||||
$fetchEmbeddedImages = false;
|
||||
$attachments = (array)$this->mail_bo->getMessageAttachments($uid, $partID, $structure, $fetchEmbeddedImages, true,true,$mailbox);
|
||||
//error_log(__METHOD__.__LINE__.array2string($attachments));
|
||||
foreach ($attachments as &$attach)
|
||||
@ -3102,7 +2915,7 @@ class mail_ui
|
||||
{
|
||||
if ($_type !="background")
|
||||
{
|
||||
$bo = emailadmin_imapbase::getInstance(false, mail_ui::$icServerID);
|
||||
$bo = emailadmin_imapbase::getInstance(false, self::$icServerID);
|
||||
$attachment = $bo->getAttachmentByCID($_uid, $CID, $_partID);
|
||||
|
||||
// only use data uri for "smaller" images, as otherwise the first display of the mail takes to long
|
||||
@ -3758,7 +3571,7 @@ class mail_ui
|
||||
$response = egw_json_response::get();
|
||||
foreach($refreshData as $folder => &$name)
|
||||
{
|
||||
$name = $this->getFolderTree(true, $folder, $_subscribedOnly);
|
||||
$name = $this->mail_tree->getTree($folder,$profileID,1,false, $_subscribedOnly,true);
|
||||
}
|
||||
$response->call('app.mail.mail_reloadNode',$refreshData);
|
||||
|
||||
@ -3888,7 +3701,7 @@ class mail_ui
|
||||
// Send full info back in the response
|
||||
foreach($refreshData as $folder => &$name)
|
||||
{
|
||||
$name = $this->getFolderTree(true, $folder, !$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']);
|
||||
$name = $this->mail_tree->getTree($folder,$profileID,1,false,!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane'],true);
|
||||
}
|
||||
$response->call('app.mail.mail_reloadNode',$refreshData);
|
||||
|
||||
@ -4056,7 +3869,7 @@ class mail_ui
|
||||
translation::add_app('mail');
|
||||
|
||||
$refreshData = array(
|
||||
$icServerID => $mail_ui->getFolderTree(true, $icServerID, !$mail_ui->mail_bo->mailPreferences['showAllFoldersInFolderPane'],true)
|
||||
$icServerID => $mail_ui->mail_tree->getTree(null,$icServerID,1,false,!$mail_ui->mail_bo->mailPreferences['showAllFoldersInFolderPane'],!$mail_ui->mail_bo->mailPreferences['showAllFoldersInFolderPane'])
|
||||
);
|
||||
$response->call('app.mail.mail_reloadNode',$refreshData);
|
||||
}
|
||||
@ -4193,6 +4006,56 @@ class mail_ui
|
||||
$response->call('app.mail.mail_setQuotaDisplay',array('data'=>$content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty spam/junk folder
|
||||
*
|
||||
* @param string $icServerID id of the server to empty its junkFolder
|
||||
* @param string $selectedFolder seleted(active) folder by nm filter
|
||||
* @return nothing
|
||||
*/
|
||||
function ajax_emptySpam($icServerID, $selectedFolder)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.' '.$icServerID);
|
||||
translation::add_app('mail');
|
||||
$response = egw_json_response::get();
|
||||
$rememberServerID = $this->mail_bo->profileID;
|
||||
if ($icServerID && $icServerID != $this->mail_bo->profileID)
|
||||
{
|
||||
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
|
||||
$this->changeProfile($icServerID);
|
||||
}
|
||||
$junkFolder = $this->mail_bo->getJunkFolder();
|
||||
if(!empty($junkFolder)) {
|
||||
if ($selectedFolder == $icServerID.self::$delimiter.$junkFolder)
|
||||
{
|
||||
// Lock the tree if the active folder is junk folder
|
||||
$response->call('app.mail.lock_tree');
|
||||
}
|
||||
$this->mail_bo->deleteMessages('all',$junkFolder,'remove_immediately');
|
||||
|
||||
$heirarchyDelimeter = $this->mail_bo->getHierarchyDelimiter(true);
|
||||
$fShortName = array_pop(explode($heirarchyDelimeter, $junkFolder));
|
||||
$fStatus = array(
|
||||
$icServerID.self::$delimiter.$junkFolder => lang($fShortName)
|
||||
);
|
||||
//Call to reset folder status counter, after junkFolder triggered not from Junk folder
|
||||
//-as we don't have junk folder specific information available on client-side we need to deal with it on server
|
||||
$response->call('app.mail.mail_setFolderStatus',$fStatus);
|
||||
}
|
||||
if ($rememberServerID != $this->mail_bo->profileID)
|
||||
{
|
||||
$oldFolderInfo = $this->mail_bo->getFolderStatus($junkFolder,false,false,false);
|
||||
$response->call('egw.message',lang('empty junk'));
|
||||
$response->call('app.mail.mail_reloadNode',array($icServerID.self::$delimiter.$junkFolder=>$oldFolderInfo['shortDisplayName']));
|
||||
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$rememberServerID);
|
||||
$this->changeProfile($rememberServerID);
|
||||
}
|
||||
else if ($selectedFolder == $icServerID.self::$delimiter.$junkFolder)
|
||||
{
|
||||
$response->call('egw.refresh',lang('empty junk'),'mail');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty trash folder
|
||||
*
|
||||
|
@ -1663,7 +1663,10 @@ app.classes.mail = AppJS.extend(
|
||||
}
|
||||
// alert(folder);
|
||||
this.egw.message(this.egw.lang('Connect to Profile %1',_widget.getSelectedLabel().replace(this._unseen_regexp, '')));
|
||||
|
||||
|
||||
//Open unloaded tree to get loaded
|
||||
_widget.openItem(folder, true);
|
||||
|
||||
this.lock_tree();
|
||||
egw.json('mail_ui::ajax_changeProfile',[folder, getFolders, this.et2._inst.etemplate_exec_id], jQuery.proxy(function() {
|
||||
// Profile changed, select inbox
|
||||
|
@ -45,7 +45,7 @@
|
||||
</grid>
|
||||
</template>
|
||||
<template id="mail.index" template="" lang="" group="0" version="1.9.001">
|
||||
<tree autoloading="mail.mail_ui.ajax_foldertree" id="nm[foldertree]" onclick="app.mail.mail_changeFolder" parent_node="mail-tree_target"/>
|
||||
<tree autoloading="mail.mail_ui.ajax_foldertree" id="nm[foldertree]" onclick="app.mail.mail_changeFolder" parent_node="mail-tree_target" onopenstart="app.mail.subscription_autoloadingStart" onopenend="app.mail.subscription_autoloadingEnd" highlighting="true"/>
|
||||
<html id="msg"/>
|
||||
<buttononly id="button[mailcreate]" onclick="app.mail.mail_compose(false);" label="Compose" parent_node="mail-index_buttonmailcreate"/>
|
||||
<hbox class="mail-index_quotabox"><progress id="nm[quotainpercent]" label="@nm[quota]" class="@nm[quotaclass]"/></hbox>
|
||||
|
@ -1076,10 +1076,15 @@ body {
|
||||
.egw_fw_ui_category_content .dtree {
|
||||
font-family: Verdana, "Lucida Grande", Helvetica, Sans-Serif;
|
||||
}
|
||||
.egw_fw_ui_category_content .selectedTreeRow {
|
||||
.egw_fw_ui_category_content .selectedTreeRow,
|
||||
.egw_fw_ui_category_content .selectedTreeRow_lor {
|
||||
background-color: #ffc200;
|
||||
color: #1e1e1e;
|
||||
}
|
||||
.egw_fw_ui_category_content .standartTreeRow_lor {
|
||||
background-color: #f2f2f2;
|
||||
color: #1e1e1e;
|
||||
}
|
||||
/* ##################################################################################
|
||||
* E-Mail Dialog "Compose"
|
||||
*
|
||||
|
@ -287,8 +287,9 @@ body {
|
||||
|
||||
|
||||
// color - selected tree item
|
||||
.selectedTreeRow {background-color: @egw_color_1_a; color: @gray_90;}
|
||||
|
||||
.selectedTreeRow, .selectedTreeRow_lor {background-color: @egw_color_1_a; color: @gray_90;}
|
||||
|
||||
.standartTreeRow_lor {background-color: @gray_5; color: @gray_90;}
|
||||
/*new mail in FOlder
|
||||
span.standartTreeRow b {color: @egw_color_2_a;}
|
||||
*/
|
||||
@ -889,6 +890,10 @@ div#displayToolbar-menulist{
|
||||
|
||||
|
||||
}
|
||||
// color - selected tree item
|
||||
.selectedTreeRow,.selectedTreeRow_lor {background-color: @egw_color_1_a; color: @gray_90;}
|
||||
// color - hover over standard tree item
|
||||
.standartTreeRow_lor {background-color: @gray_5; color: @gray_90;}
|
||||
|
||||
} // #mail-subscribe
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user