* 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:
Hadi Nategh 2015-08-12 13:27:57 +00:00
parent 6f52ff858c
commit df179a3859
8 changed files with 515 additions and 397 deletions

View File

@ -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);
}
}

View File

@ -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);
},
/**

View File

@ -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;
}
}

View File

@ -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
*

View File

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

View File

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

View File

@ -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"
*

View File

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