diff --git a/emailadmin/inc/class.emailadmin_imapbase.inc.php b/emailadmin/inc/class.emailadmin_imapbase.inc.php
index 1674d43a1d..0f2afc1846 100644
--- a/emailadmin/inc/class.emailadmin_imapbase.inc.php
+++ b/emailadmin/inc/class.emailadmin_imapbase.inc.php
@@ -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']."
";
-
+
$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);
-
+
}
}
diff --git a/etemplate/js/et2_widget_tree.js b/etemplate/js/et2_widget_tree.js
index 684e2e73bd..b93fd2c5bd 100644
--- a/etemplate/js/et2_widget_tree.js
+++ b/etemplate/js/et2_widget_tree.js
@@ -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);
},
/**
diff --git a/mail/inc/class.mail_tree.inc.php b/mail/inc/class.mail_tree.inc.php
index b7d43cfdd4..9b68e77b34 100644
--- a/mail/inc/class.mail_tree.inc.php
+++ b/mail/inc/class.mail_tree.inc.php
@@ -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;
+ }
}
diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php
index 89dc579efb..13f8c42100 100644
--- a/mail/inc/class.mail_ui.inc.php
+++ b/mail/inc/class.mail_ui.inc.php
@@ -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
*
diff --git a/mail/js/app.js b/mail/js/app.js
index 434bc34654..166ba0d140 100644
--- a/mail/js/app.js
+++ b/mail/js/app.js
@@ -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
diff --git a/mail/templates/default/index.xet b/mail/templates/default/index.xet
index a3af3042a3..46d7ee43af 100644
--- a/mail/templates/default/index.xet
+++ b/mail/templates/default/index.xet
@@ -45,7 +45,7 @@
-
+
diff --git a/mail/templates/pixelegg/app.css b/mail/templates/pixelegg/app.css
index b5ddaec350..beebbd0489 100755
--- a/mail/templates/pixelegg/app.css
+++ b/mail/templates/pixelegg/app.css
@@ -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"
*
diff --git a/mail/templates/pixelegg/app.less b/mail/templates/pixelegg/app.less
index 79bc46f3e9..e448e8b13c 100755
--- a/mail/templates/pixelegg/app.less
+++ b/mail/templates/pixelegg/app.less
@@ -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