* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @version $Id$ */ include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.etemplate.inc.php'); /** * Mail Interface class */ class mail_ui { /** * Methods callable via menuaction * * @var array */ var $public_functions = array ( 'index' => True, 'displayHeader' => True, 'displayMessage' => True, 'displayImage' => True, 'getAttachment' => True, 'saveMessage' => True, 'vfsSaveMessage' => True, 'loadEmailBody' => True, 'importMessage' => True, 'TestConnection' => True, ); /** * current icServerID * * @var int */ static $icServerID; /** * delimiter - used to separate profileID from foldertreestructure, and separate keyinformation in rowids * * @var string */ static $delimiter = '::'; /** * instance of mail_bo * * @var object */ var $mail_bo; /** * Constructor * */ function __construct() { // no autohide of the sidebox, as we use it for folderlist now. unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']); if (!empty($_GET["resetConnection"])) $connectionReset = html::purify($_GET["resetConnection"]); unset($_GET["resetConnection"]); //$icServerID =& egw_cache::getSession('mail','activeProfileID'); if (isset($GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID']) && !empty($GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'])) { self::$icServerID = (int)$GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID']; } if ($connectionReset) { if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Connection Reset triggered:'.$connectionReset.' for Profile with ID:'.self::$icServerID); emailadmin_bo::unsetCachedObjects(self::$icServerID); } $this->mail_bo = mail_bo::getInstance(false,$icServerID); if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Fetched IC Server:'.self::$icServerID.'/'.$this->mail_bo->profileID.':'.function_backtrace()); // no icServer Object: something failed big time if (!isset($this->mail_bo->icServer)) exit; // ToDo: Exception or the dialog for setting up a server config if (!($this->mail_bo->icServer->_connected == 1)) $this->mail_bo->openConnection(self::$icServerID); } /** * changeProfile * * @param int $icServerID */ function changeProfile($_icServerID,$unsetCache=false) { //if (self::$icServerID != $_icServerID) $unsetCache = true; if (mail_bo::$debug) error_log(__METHOD__.__LINE__.'->'.self::$icServerID.'<->'.$_icServerID); self::$icServerID = $_icServerID; if ($unsetCache) emailadmin_bo::unsetCachedObjects(self::$icServerID); $this->mail_bo = mail_bo::getInstance(false,self::$icServerID); if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Fetched IC Server:'.self::$icServerID.'/'.$this->mail_bo->profileID.':'.function_backtrace()); // no icServer Object: something failed big time if (!isset($this->mail_bo->icServer)) exit; // ToDo: Exception or the dialog for setting up a server config /*if (!($this->mail_bo->icServer->_connected == 1))*/ $this->mail_bo->openConnection(self::$icServerID); // save session varchar $oldicServerID =& egw_cache::getSession('mail','activeProfileID'); $oldicServerID = self::$icServerID; // save pref $GLOBALS['egw']->preferences->add('mail','ActiveProfileID',self::$icServerID,'user'); $GLOBALS['egw']->preferences->save_repository(true); $GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'] = self::$icServerID; } /** * Main mail page * * @param array $content=null * @param string $msg=null */ function index(array $content=null,$msg=null) { //_debug_array($content); if (!is_array($content)) { $content = array( 'nm' => egw_session::appsession('index','mail'), ); if (!is_array($content['nm'])) { $content['nm'] = array( 'get_rows' => 'mail.mail_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' 'filter' => 'INBOX', // filter is used to choose the mailbox 'no_filter2' => false, // I disable the 2. filter (params are the same as for filter) 'no_cat' => true, // I disable the cat-selectbox //'cat_is_select' => 'no_lang', // true or no_lang 'lettersearch' => false, // I show a lettersearch 'searchletter' => false, // I0 active letter of the lettersearch or false for [all] 'start' => 0, // IO position in list 'order' => 'date', // IO name of the column to sort after (optional for the sortheaders) 'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC' 'default_cols' => 'status,attachments,subject,fromaddress,date,size', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns 'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames, //or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type) 'actions' => self::get_actions(), 'row_id' => 'row_id', // is a concatenation of trim($GLOBALS['egw_info']['user']['account_id']):profileID:base64_encode(FOLDERNAME):uid ); //$content['nm']['path'] = self::get_home_dir(); } } $content['nm']['csv_fields'] = false; if ($msg) { $content['msg'] = $msg; } else { unset($msg); unset($content['msg']); } //$content['preview'] = "
':''); return $header; } function showBody(&$body, $print=true,$fullPageTags=true) { $BeginBody = ''; $EndBody = ' |
"; $this->mail_bo->restoreSessionData(); // filter is used to choose the mailbox //if (!isset($content['nm']['foldertree'])) // maybe we fetch the folder here /* $sel_options['nm']['foldertree'] = array('id' => 0, 'item' => array( array('id' => '/INBOX', 'text' => 'INBOX', 'im0' => 'kfm_home.png', 'child' => '1', 'item' => array( array('id' => '/INBOX/sub', 'text' => 'sub'), array('id' => '/INBOX/sub2', 'text' => 'sub2'), )), array('id' => '/user', 'text' => 'user', 'child' => '1', 'item' => array( array('id' => '/user/birgit', 'text' => 'birgit'), )), )); $content['nm']['foldertree'] = '/INBOX/sub'; */ $sel_options['nm']['foldertree'] = $this->getFolderTree(false); $sessionFolder = $this->mail_bo->sessionData['maibox']; if ($this->mail_bo->folderExists($sessionFolder)) { $content['nm']['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.$this->mail_bo->sessionData['maibox']; } if (!isset($content['nm']['foldertree'])) $content['nm']['foldertree'] = $this->mail_bo->profileID.self::$delimiter.'INBOX'; if (!isset($content['nm']['selectedFolder'])) $content['nm']['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.'INBOX'; $content['nm']['foldertree'] = $content['nm']['selectedFolder']; $sel_options['cat_id'] = array(1=>'none'); if (!isset($content['nm']['cat_id'])) $content['nm']['cat_id'] = 'All'; $etpl = new etemplate_new('mail.index'); // Set tree actions $etpl->set_cell_attribute('nm[foldertree]','actions', array( 'drop_move_mail' => array( 'type' => 'drop', 'acceptedTypes' => 'mail', 'icon' => 'move', 'caption' => 'Move to', 'onExecute' => 'javaScript:app.mail.mail_move' ), 'drop_copy_mail' => array( 'type' => 'drop', 'acceptedTypes' => 'mail', 'icon' => 'copy', 'caption' => 'Copy to', 'onExecute' => 'javaScript:app.mail.mail_copy' ), 'drop_cancel' => array( 'caption' => 'Cancel', 'acceptedTypes' => 'mail', 'type' => 'drop', ), // Tree does support this one 'add' => array( 'caption' => 'Add Folder', 'type' => 'popup', 'onExecute' => 'javaScript:app.mail.mail_AddFolder' ), 'rename' => array( 'caption' => 'Rename Folder', 'type' => 'popup', 'onExecute' => 'javaScript:app.mail.mail_RenameFolder' ), 'delete' => array( 'caption' => 'Delete Folder', 'type' => 'popup', 'onExecute' => 'javaScript:app.mail.mail_DeleteFolder' ) )); return $etpl->exec('mail.mail_ui.index',$content,$sel_options,$readonlys,$preserv); } /** * Test Connection * Simple Test, resets the active connections cachedObjects / ImapServer */ function TestConnection () { // load translations translation::add_app('mail'); common::egw_header(); parse_navbar(); //$GLOBALS['egw']->framework->sidebox(); $preferences =& $this->mail_bo->mailPreferences; if ($preferences->preferences['prefcontroltestconnection'] == 'none') die('You should not be here!'); if (isset($GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'])) $icServerID = (int)$GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID']; //_debug_array($this->mail_bo->mailPreferences); if (is_object($preferences)) $imapServer = $preferences->getIncomingServer($icServerID); if (isset($imapServer->ImapServerId) && !empty($imapServer->ImapServerId)) { $icServerID = $GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'] = $imapServer->ImapServerId; } echo "
"; _debug_array('Connection Reset triggered:'.$connectionReset.' for Profile with ID:'.$icServerID); emailadmin_bo::unsetCachedObjects($icServerID); /* if (mail_bo::$idna2) { _debug_array('Umlautdomains supported (see Example below)'); $dom = 'füßler.com'; $encDom = mail_bo::$idna2->encode($dom); _debug_array(array('source'=>$dom,'result'=>array('encoded'=>$encDom,'decoded'=>mail_bo::$idna2->decode($encDom)))); } */ if ($preferences->preferences['prefcontroltestconnection'] == 'reset') exit; echo "
"; if($imapServer->_connectionErrorObject) $eO = $imapServer->_connectionErrorObject; unset($imapServer->_connectionErrorObject); $sieveServer = clone $imapServer; if (!empty($imapServer->adminPassword)) $imapServer->adminPassword='**********************'; if ($preferences->preferences['prefcontroltestconnection'] == 'nopasswords' || $preferences->preferences['prefcontroltestconnection'] == 'nocredentials') { if (!empty($imapServer->password)) $imapServer->password='**********************'; } if ($preferences->preferences['prefcontroltestconnection'] == 'nocredentials') { if (!empty($imapServer->adminUsername)) $imapServer->adminUsername='++++++++++++++++++++++'; if (!empty($imapServer->username)) $imapServer->username='++++++++++++++++++++++'; if (!empty($imapServer->loginName)) $imapServer->loginName='++++++++++++++++++++++'; } if ($preferences->preferences['prefcontroltestconnection'] <> 'basic') { _debug_array($imapServer); } else { _debug_array(array('ImapServerId' =>$imapServer->ImapServerId, 'host'=>$imapServer->host, 'port'=>$imapServer->port, 'validatecert'=>$imapServer->validatecert)); } echo "
"; $lE = false; if ($eO && $eO->message) { _debug_array($eO->message); $lE = true; } $isError = egw_cache::getCache(egw_cache::INSTANCE,'email','icServerIMAP_connectionError'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),$expiration=60*5); if ($isError[$icServerID]) { _debug_array($isError[$icServerID]); $lE = true; } _debug_array(($lE?'':lang('Successfully connected'))); $suF = $this->mail_bo->getSpecialUseFolders(); if (is_array($suF) && !empty($suF)) _debug_array(array(lang('Server supports Special-Use Folders')=>$suF)); if(($sieveServer instanceof defaultimap) && $sieveServer->enableSieve) { $scriptName = (!empty($GLOBALS['egw_info']['user']['preferences']['mail']['sieveScriptName'])) ? $GLOBALS['egw_info']['user']['preferences']['mail']['sieveScriptName'] : 'mail'; $sieveServer->getScript($scriptName); $rules = $sieveServer->retrieveRules($sieveServer->scriptName,true); $vacation = $sieveServer->getVacation($sieveServer->scriptName); echo "
"; $isSieveError = egw_cache::getCache(egw_cache::INSTANCE,'email','icServerSIEVE_connectionError'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*15); if ($isSieveError[$icServerID]) { _debug_array($isSieveError[$icServerID]); } else { _debug_array(array(lang('Successfully connected'),$rules)); } } echo "
"; _debug_array($preferences->preferences); //error_log(__METHOD__.__LINE__.' ImapServerId:'.$imapServer->ImapServerId.' Prefs:'.array2string($preferences->preferences)); //error_log(__METHOD__.__LINE__.' ImapServerObject:'.array2string($imapServer)); if (is_object($preferences)) $activeIdentity =& $preferences->getIdentity($icServerID, true); //_debug_array($activeIdentity); $maxMessages = 50; $userPreferences =& $GLOBALS['egw_info']['user']['preferences']['mail']; // retrieve data for/from user defined accounts $selectedID = 0; if (count($preferences->ic_server)) { foreach ($preferences->ic_server as $tmpkey => $accountData) { if ($tmpkey==0) continue; $identity =& $preferences->identities[$tmpkey]; $icServer =& $accountData; //_debug_array($identity); //_debug_array($icServer); //error_log(__METHOD__.__LINE__.' Userdefined Profiles ImapServerId:'.$icServer->ImapServerId); if (empty($icServer->host)) continue; $identities[$identity->id]=$identity->realName.' '.$identity->organization.' <'.$identity->emailAddress.'>'; if (!empty($identity->default)) $identities[$identity->id] = $identities[$identity->id].'('.lang('selected').')'; } } if (count($identities)>0) { echo "
";
_debug_array($identities);
}
if (empty($imapServer->host) && count($identities)==0 && $preferences->userDefinedAccounts)
{
// redirect to new personal account
egw::redirect_link('/index.php',array('menuaction'=>'mail.uipreferences.editAccountData',
'accountID'=>"new",
'msg' => lang("There is no IMAP Server configured.")." - ".lang("Please configure access to an existing individual IMAP account."),
));
}
common::egw_footer();
}
/**
* Ajax callback to fetch folders for given profile
*
* We currently load all folders of a given profile, tree can also load parts of a tree.
*
* @param string $_GET[id] if of node whos children are requested
*/
public function ajax_foldertree($_nodeID = null)
{
$nodeID = $_GET['id'];
if (!is_null($_nodeID)) $nodeID = $_nodeID;
//error_log(__METHOD__.__LINE__.'->'.array2string($_REQUEST));
//error_log(__METHOD__.__LINE__.'->'.array2string($_GET));
$fetchCounters = !is_null($_nodeID);
list($_profileID,$_folderName) = explode(self::$delimiter,$nodeID,2);
if (!empty($_folderName)) $fetchCounters = true;
$data = $this->getFolderTree($fetchCounters, $nodeID);
//error_log(__METHOD__.__LINE__.':'.$nodeID.'->'.array2string($data));
if (!is_null($_nodeID)) return $data;
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data);
common::egw_exit();
}
/**
* getFolderTree, get folders from server and prepare the folder tree
* @param bool $_fetchCounters, wether to fetch extended information on folders
* @param string $_nodeID, nodeID to fetch and return
* @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)
{
if (!is_null($_nodeID) && $_nodeID !=0)
{
list($_profileID,$_folderName) = explode(self::$delimiter,$_nodeID,2);
if (is_numeric($_profileID))
{
if ($_profileID && $_profileID != $this->mail_bo->profileID)
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$_profileID);
$this->changeProfile($_profileID);
}
}
}
$folderObjects = $this->mail_bo->getFolderObjects(true,false,true);
$trashFolder = $this->mail_bo->getTrashFolder();
$templateFolder = $this->mail_bo->getTemplateFolder();
$draftFolder = $this->mail_bo->getDraftFolder();
$sentFolder = $this->mail_bo->getSentFolder();
$userDefinedFunctionFolders = array();
if (isset($trashFolder) && $trashFolder != 'none') $userDefinedFunctionFolders['Trash'] = $trashFolder;
if (isset($sentFolder) && $sentFolder != 'none') $userDefinedFunctionFolders['Sent'] = $sentFolder;
if (isset($draftFolder) && $draftFolder != 'none') $userDefinedFunctionFolders['Drafts'] = $draftFolder;
if (isset($templateFolder) && $templateFolder != 'none') $userDefinedFunctionFolders['Templates'] = $templateFolder;
$out = array('id' => 0);
//_debug_array($this->mail_bo->mailPreferences);
//if($this->mail_bo->mailPreferences->userDefinedAccounts) $allAccountData = $this->mail_bo->bopreferences->getAllAccountData($this->mail_bo->mailPreferences);
//$starttime = microtime(true);
if (count($this->mail_bo->mailPreferences->ic_server)) {
foreach ($this->mail_bo->mailPreferences->ic_server as $tmpkey => $accountData)
{
if ($tmpkey==0) continue;
$identity =& $this->mail_bo->mailPreferences->identities[$tmpkey];
$icServer =& $accountData;
//_debug_array($identity);
//_debug_array($icServer);
if ($_profileID && $icServer->ImapServerId<>$_profileID) continue;
//error_log(__METHOD__.__LINE__.' Userdefined Profiles ImapServerId:'.$icServer->ImapServerId);
if (empty($icServer->host)) continue;
$identities[$icServer->ImapServerId]=$identity->realName.' '.$identity->organization.' <'.$identity->emailAddress.'>';
$oA = array('id'=>$icServer->ImapServerId,
'text'=>$identities[$icServer->ImapServerId], //$this->mail_bo->profileID,
'tooltip'=>'('.$icServer->ImapServerId.') '.htmlspecialchars_decode($identities[$icServer->ImapServerId]),
'im0' => 'thunderbird.png',
'im1' => 'thunderbird.png',
'im2' => 'thunderbird.png',
'path'=> array($icServer->ImapServerId),
'child'=> 1, // dynamic loading on unfold
'parent' => ''
);
$this->setOutStructure($oA,$out,self::$delimiter);
}
}
//$endtime = microtime(true) - $starttime;
//error_log(__METHOD__.__LINE__.' Fetching identities Took:'.$endtime);
//error_log(__METHOD__.__LINE__.array2string($folderObjects));
$c = 0;
foreach($folderObjects as $key => $obj)
{
$fS = $this->mail_bo->getFolderStatus($key,false,($_fetchCounters?false:true));
//_debug_array($fS);
//error_log(__METHOD__.__LINE__.array2string($fS));
$fFP = $folderParts = explode($obj->delimiter, $key);
//get rightmost folderpart
$shortName = 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->displayName);
array_unshift($fFP,$this->mail_bo->profileID);
$oA['path'] = $fFP;
$path = $key; //$obj->folderName; //$obj->delimiter
if ($fS['unseen']) $oA['text'] = ''.$oA['text'].' ('.$fS['unseen'].')';
if ($path=='INBOX')
{
$oA['im0'] = $oA['im1']= $oA['im2'] = "kfm_home.png";
}
elseif (in_array($obj->shortFolderName,mail_bo::$autoFolders))
{
//echo $obj->shortFolderName.'
';
$oA['im0'] = $oA['im1']= $oA['im2'] = "MailFolder".$obj->shortFolderName.".png";
//$image2 = "'MailFolderPlain.png'";
//$image3 = "'MailFolderPlain.png'";
}
elseif (in_array($key,$userDefinedFunctionFolders))
{
$_key = array_search($key,$userDefinedFunctionFolders);
$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
}
$path = $this->mail_bo->profileID.self::$delimiter.$key; //$obj->folderName; //$obj->delimiter
$oA['id'] = $path; // ID holds the PATH
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;
//_debug_array($oA);
$this->setOutStructure($oA,$out,$obj->delimiter);
$c++;
}
if (!is_null($_nodeID) && $_nodeID !=0)
{
$node = self::findNode($out,$_nodeID);
//error_log(__METHOD__.__LINE__.':'.$_nodeID.'->'.array2string($node));
return $node;
}
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
*
* @param array $out, out array (to be searched)
* @param string $_nodeID, node to search for
* @param boolean $childElements=true return node itself, or only its child items
* @return array structured subtree
*/
static function findNode($_out, $_nodeID, $childElements = false)
{
foreach($_out['item'] as $node)
{
if (strcmp($node['id'],$_nodeID)===0)
{
//error_log(__METHOD__.__LINE__.':'.$_nodeID.'->'.$node['id']);
return ($childElements?$node['item']:$node);
}
elseif (is_array($node['item']) && strncmp($node['id'],$_nodeID,strlen($node['id']))===0 && strlen($_nodeID)>strlen($node['id']))
{
//error_log(__METHOD__.__LINE__.' descend into '.$node['id']);
return self::findNode($node,$_nodeID,$childElements);
}
}
}
/**
* setOutStructure - helper function to transform the folderObjectList to dhtmlXTreeObject requirements
*
* @param array $data, data to be processed
* @param array &$out, out array
* @param string $del='.', needed as glue for parent/child operation / comparsion
* @param boolean $createMissingParents=true create a missing parent, instead of throwing an exception
* @return void
*/
function setOutStructure($data, &$out, $del='.', $createMissingParents=true)
{
//error_log(__METHOD__."(".array2string($data).', '.array2string($out).", '$del')");
$components = $data['path'];
array_pop($components); // remove own name
$insert = &$out;
$parents = array();
foreach($components as $component)
{
if (count($parents)>1)
{
$helper = array_slice($parents,1,null,true);
$parent = $parents[0].self::$delimiter.implode($del, $helper);
if ($parent) $parent .= $del;
}
else
{
$parent = implode(self::$delimiter, $parents);
if ($parent) $parent .= self::$delimiter;
}
if (!is_array($insert) || !isset($insert['item']))
{
// throwing an exeption here seems to be unrecoverable, even if the cause is a something that can be handeled by the mailserver
error_log(__METHOD__.':'.__LINE__." id=$data[id]: Parent '$parent' of '$component' not found!");
break;
//throw new egw_exception_assertion_failed(__METHOD__.':'.__LINE__." id=$data[id]: Parent '$parent' '$component' not found! out=".array2string($out));
}
foreach($insert['item'] as &$item)
{
if ($item['id'] == $parent.$component)
{
$insert =& $item;
break;
}
}
if ($item['id'] != $parent.$component)
{
if ($createMissingParents)
{
unset($item);
$item = array('id' => $parent.$component, 'text' => $component, 'im0' => "folderNoSelectClosed.gif",'im1' => "folderNoSelectOpen.gif",'im2' => "folderNoSelectClosed.gif",'tooltip' => '**missing**');
$insert['item'][] =& $item;
$insert =& $item;
}
else
{
throw new egw_exception_assertion_failed(__METHOD__.':'.__LINE__.": id=$data[id]: Parent '$parent' '$component' not found!");
}
}
$parents[] = $component;
}
unset($data['path']);
$insert['item'][] = $data;
//error_log(__METHOD__."() leaving with out=".array2string($out));
}
/**
* Get actions / context menu for index
*
* Changes here, require to log out, as $content['nm'] get stored in session!
* @var &$action_links
*
* @return array see nextmatch_widget::egw_actions()
*/
private function get_actions(array &$action_links=array())
{
// duplicated from mail_hooks
static $deleteOptions = array(
'move_to_trash' => 'move to trash',
'mark_as_deleted' => 'mark as deleted',
'remove_immediately' => 'remove immediately',
);
// todo: real hierarchical folder list
$folders = array(
'INBOX' => 'INBOX',
'Drafts' => 'Drafts',
'Sent' => 'Sent',
);
$lastFolderUsedForMove = null;
$moveaction = 'move_';
$lastFolderUsedForMoveCont = egw_cache::getCache(egw_cache::INSTANCE,'email','lastFolderUsedForMove'.trim($GLOBALS['egw_info']['user']['account_id']),null,array(),$expiration=60*60*1);
if (isset($lastFolderUsedForMoveCont[$this->mail_bo->profileID]))
{
$_folder = $this->mail_bo->icServer->getCurrentMailbox();
//error_log(__METHOD__.__LINE__.' '.$_folder."<->".$lastFolderUsedForMoveCont[$this->mail_bo->profileID].function_backtrace());
//if ($_folder!=$lastFolderUsedForMoveCont[$this->mail_bo->profileID]) $this->mail_bo->icServer->selectMailbox($lastFolderUsedForMoveCont[$this->mail_bo->profileID]);
if ($_folder!=$lastFolderUsedForMoveCont[$this->mail_bo->profileID])
{
$lastFolderUsedForMove = $this->mail_bo->getFolderStatus($lastFolderUsedForMoveCont[$this->mail_bo->profileID]);
//error_log(array2string($lastFolderUsedForMove));
$moveaction .= $lastFolderUsedForMoveCont[$this->mail_bo->profileID];
}
//if ($_folder!=$lastFolderUsedForMoveCont[$this->profileID]) $this->mail_bo->icServer->selectMailbox($_folder);
}
$actions = array(
'open' => array(
'caption' => lang('Open'),
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_open',
'allowOnMultiple' => false,
'default' => true,
),
'reply' => array(
'caption' => 'Reply',
'icon' => 'mail_reply',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_compose',
'allowOnMultiple' => false,
),
'reply_all' => array(
'caption' => 'Reply All',
'icon' => 'mail_replyall',
'group' => $group,
'onExecute' => 'javaScript:app.mail.mail_compose',
'allowOnMultiple' => false,
),
'forward' => array(
'caption' => 'Forward',
'icon' => 'mail_forward',
'group' => $group,
'children' => array(
'forwardinline' => array(
'caption' => 'forward inline',
'icon' => 'mail_forward',
'group' => $group,
'onExecute' => 'javaScript:app.mail.mail_compose',
'allowOnMultiple' => false,
),
'forwardasattach' => array(
'caption' => 'forward as attachment',
'icon' => 'mail_forward',
'group' => $group,
'onExecute' => 'javaScript:app.mail.mail_compose',
),
),
),
'composeasnew' => array(
'caption' => 'Compose as new',
'icon' => 'new',
'group' => $group,
'onExecute' => 'javaScript:app.mail.mail_compose',
'allowOnMultiple' => false,
),
$moveaction => array(
'caption' => lang('Move selected to').': '.(isset($lastFolderUsedForMove['shortDisplayName'])?$lastFolderUsedForMove['shortDisplayName']:''),
'icon' => 'move',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_move2folder',
'allowOnMultiple' => true,
),
'infolog' => array(
'caption' => 'InfoLog',
'hint' => 'Save as InfoLog',
'icon' => 'infolog/navbar',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_infolog',
'url' => 'menuaction=infolog.infolog_ui.import_mail',
'popup' => egw_link::get_registry('infolog', 'add_popup'),
'allowOnMultiple' => false,
),
'tracker' => array(
'caption' => 'Tracker',
'hint' => 'Save as ticket',
'group' => $group,
'icon' => 'tracker/navbar',
'onExecute' => 'javaScript:app.mail.mail_tracker',
'url' => 'menuaction=tracker.tracker_ui.import_mail',
'popup' => egw_link::get_registry('tracker', 'add_popup'),
'allowOnMultiple' => false,
),
'print' => array(
'caption' => 'Print',
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_print',
'allowOnMultiple' => false,
),
'save' => array(
'caption' => 'Save',
'group' => $group,
'icon' => 'fileexport',
'children' => array(
'save2disk' => array(
'caption' => 'Save message to disk',
'hint' => 'Save message to disk',
'group' => $group,
'icon' => 'fileexport',
'onExecute' => 'javaScript:app.mail.mail_save',
'allowOnMultiple' => false,
),
'save2filemanager' => array(
'caption' => 'Save to filemanager',
'hint' => 'Save message to filemanager',
'group' => $group,
'icon' => 'filemanager/navbar',
'onExecute' => 'javaScript:app.mail.mail_save2fm',
'allowOnMultiple' => false,
),
),
),
'view' => array(
'caption' => 'View',
'group' => $group,
'icon' => 'kmmsgread',
'children' => array(
'header' => array(
'caption' => 'Header lines',
'hint' => 'View header lines',
'group' => $group,
'icon' => 'kmmsgread',
'onExecute' => 'javaScript:app.mail.mail_header',
'allowOnMultiple' => false,
),
'mailsource' => array(
'caption' => 'Mail Source',
'hint' => 'View full Mail Source',
'group' => $group,
'icon' => 'fileexport',
'onExecute' => 'javaScript:app.mail.mail_mailsource',
'allowOnMultiple' => false,
),
'openastext' => array(
'caption' => lang('Open in Text mode'),
'group' => ++$group,
'icon' => egw_vfs::mime_icon('text/plain'),
'onExecute' => 'javaScript:app.mail.mail_openAsText',
'allowOnMultiple' => false,
),
'openashtml' => array(
'caption' => lang('Open in HTML mode'),
'group' => $group,
'icon' => egw_vfs::mime_icon('text/html'),
'onExecute' => 'javaScript:app.mail.mail_openAsHtml',
'allowOnMultiple' => false,
),
),
),
'mark' => array(
'caption' => 'Mark as',
'icon' => 'read_small',
'group' => ++$group,
'children' => array(
// icons used from http://creativecommons.org/licenses/by-sa/3.0/
// Artist: Led24
// Iconset Homepage: http://led24.de/iconset
// License: CC Attribution 3.0
'setLabel' => array(
'caption' => 'Set Label',
'icon' => 'tag_message',
'group' => ++$group,
'children' => array(
'label1' => array(
'caption' => "".lang('urgent')."",
'icon' => 'mail_label1',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'label2' => array(
'caption' => "".lang('job')."",
'icon' => 'mail_label2',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'label3' => array(
'caption' => "".lang('personal')."",
'icon' => 'mail_label3',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'label4' => array(
'caption' => "".lang('to do')."",
'icon' => 'mail_label4',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'label5' => array(
'caption' => "".lang('later')."",
'icon' => 'mail_label5',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
),
),
// modified icons from http://creativecommons.org/licenses/by-sa/3.0/
'unsetLabel' => array(
'caption' => 'Remove Label',
'icon' => 'untag_message',
'group' => ++$group,
'children' => array(
'unlabel1' => array(
'caption' => "".lang('urgent')."",
'icon' => 'mail_unlabel1',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'unlabel2' => array(
'caption' => "".lang('job')."",
'icon' => 'mail_unlabel2',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'unlabel3' => array(
'caption' => "".lang('personal')."",
'icon' => 'mail_unlabel3',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'unlabel4' => array(
'caption' => "".lang('to do')."",
'icon' => 'mail_unlabel4',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
'unlabel5' => array(
'caption' => "".lang('later')."",
'icon' => 'mail_unlabel5',
'onExecute' => 'javaScript:app.mail.mail_flag',
),
),
),
'flagged' => array(
'group' => ++$group,
'caption' => 'Flagged',
'icon' => 'unread_flagged_small',
'onExecute' => 'javaScript:app.mail.mail_flag',
//'disableClass' => 'flagged',
//'enabled' => "javaScript:mail_disabledByClass",
'shortcut' => egw_keymanager::shortcut(egw_keymanager::F, true, true),
),
'unflagged' => array(
'group' => $group,
'caption' => 'Unflagged',
'icon' => 'read_flagged_small',
'onExecute' => 'javaScript:app.mail.mail_flag',
//'enableClass' => 'flagged',
//'enabled' => "javaScript:mail_enabledByClass",
'shortcut' => egw_keymanager::shortcut(egw_keymanager::U, true, true),
),
'read' => array(
'group' => $group,
'caption' => 'Read',
'icon' => 'read_small',
'onExecute' => 'javaScript:app.mail.mail_flag',
//'enableClass' => 'unseen',
//'enabled' => "javaScript:mail_enabledByClass",
),
'unread' => array(
'group' => $group,
'caption' => 'Unread',
'icon' => 'unread_small',
'onExecute' => 'javaScript:app.mail.mail_flag',
//'disableClass' => 'unseen',
//'enabled' => "javaScript:mail_disabledByClass",
),
'undelete' => array(
'group' => $group,
'caption' => 'Undelete',
'icon' => 'revert',
'onExecute' => 'javaScript:app.mail.mail_flag',
'enableClass' => 'deleted',
'enabled' => "javaScript:mail_enabledByClass",
),
),
),
'delete' => array(
'caption' => 'Delete',
'hint' => $deleteOptions[$this->mail_bo->mailPreferences->preferences['deleteOptions']],
'group' => ++$group,
'onExecute' => 'javaScript:app.mail.mail_delete',
),
'drag_mail' => array(
'dragType' => array('mail','file'),
'type' => 'drag',
'onExecute' => 'javaScript:app.mail.mail_dragStart',
)
);
// save as tracker, save as infolog, as this are actions that are either available for all, or not, we do that for all and not via css-class disabling
if (!isset($GLOBALS['egw_info']['user']['apps']['infolog']))
{
unset($actions['infolog']);
}
if (!isset($GLOBALS['egw_info']['user']['apps']['tracker']))
{
unset($actions['tracker']);
}
if (empty($lastFolderUsedForMove))
{
unset($actions[$moveaction]);
}
// note this one is NOT a real CAPABILITY reported by the server, but added by selectMailbox
if (!$this->mail_bo->icServer->hasCapability('SUPPORTS_KEYWORDS'))
{
unset($actions['mark']['children']['setLabel']);
unset($actions['mark']['children']['unsetLabel']);
}
return $actions;
}
/**
* Callback to fetch the rows for the nextmatch widget
*
* @param array $query
* @param array &$rows
* @param array &$readonlys
*/
function get_rows($query,&$rows,&$readonlys)
{
unset($query['actions']);
//error_log(__METHOD__.__LINE__.array2string($query));
//error_log(__METHOD__.__LINE__.' SelectedFolder:'.$query['selectedFolder'].' Start:'.$query['start'].' NumRows:'.$query['num_rows']);
$starttime = microtime(true);
//error_log(__METHOD__.__LINE__.array2string($query['search']));
//$query['search'] is the phrase in the searchbox
//error_log(__METHOD__.__LINE__.' Folder:'.array2string($_folderName).' FolderType:'.$folderType.' RowsFetched:'.array2string($rowsFetched)." these Uids:".array2string($uidOnly).' Headers passed:'.array2string($headers));
$this->mail_bo->restoreSessionData();
$maxMessages = 50; // match the hardcoded setting for data retrieval as inital value
$previewMessage = $this->mail_bo->sessionData['previewMessage'];
if (isset($query['selectedFolder'])) $this->mail_bo->sessionData['maibox']=$query['selectedFolder'];
$this->mail_bo->saveSessionData();
$sRToFetch = null;
$_folderName=$query['selectedFolder'];
list($_profileID,$folderName) = explode(self::$delimiter,$_folderName,2);
if (is_numeric($_profileID))
{
if ($_profileID && $_profileID != $this->mail_bo->profileID)
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$_profileID);
$this->changeProfile($_profileID);
}
$_folderName = $folderName;
}
//save selected Folder to sessionData (mailbox)->currentFolder
if (isset($query['selectedFolder'])) $this->mail_bo->sessionData['maibox']=$_folderName;
$this->mail_bo->saveSessionData();
$rowsFetched['messages'] = null;
$offset = $query['start']+1; // we always start with 1
$maxMessages = $query['num_rows'];
$sort = $query['order'];
if (!empty($query['search']))
{
//([filterName] => Schnellsuche[type] => quick[string] => ebay[status] => any
$filter = array('filterName' => lang('quicksearch'),'type' => 'quick','string' => $query['search'],'status' => 'any');
}
else
{
$filter = array();
}
$reverse = ($query['order']=='ASC'?false:true);
//error_log(__METHOD__.__LINE__.' maxMessages:'.$maxMessages.' Offset:'.$offset.' Filter:'.array2string($this->sessionData['messageFilter']));
if ($maxMessages > 75)
{
$sR = $this->mail_bo->getSortedList(
$_folderName,
$sort,
$reverse,
$filter,
$rByUid=true
);
$rowsFetched['messages'] = count($sR);
// if $sR is false, something failed fundamentally
if($reverse === true) $sR = ($sR===false?array():array_reverse((array)$sR));
$sR = array_slice((array)$sR,($offset==0?0:$offset-1),$maxMessages); // we need only $maxMessages of uids
$sRToFetch = $sR;//array_slice($sR,0,50); // we fetch only the headers of a subset of the fetched uids
//error_log(__METHOD__.__LINE__.' Rows fetched (UID only):'.count($sR).' Data:'.array2string($sR));
$maxMessages = 75;
$sortResultwH['header'] = array();
if (count($sRToFetch)>0)
{
//error_log(__METHOD__.__LINE__.' Headers to fetch with UIDs:'.count($sRToFetch).' Data:'.array2string($sRToFetch));
$sortResult = array();
// fetch headers
$sortResultwH = $this->mail_bo->getHeaders(
$_folderName,
$offset,
$maxMessages,
$sort,
$reverse,
$filter,
$sRToFetch
);
}
}
else
{
$sortResult = array();
// fetch headers
$sortResultwH = $this->mail_bo->getHeaders(
$_folderName,
$offset,
$maxMessages,
$sort,
$reverse,
$filter
);
$rowsFetched['messages'] = $sortResultwH['info']['total'];
}
if (is_array($sR) && count($sR)>0)
{
foreach ((array)$sR as $key => $v)
{
if (array_key_exists($key,(array)$sortResultwH['header'])==true)
{
$sortResult['header'][] = $sortResultwH['header'][$key];
}
else
{
if (!empty($v)) $sortResult['header'][] = array('uid'=>$v);
}
}
}
else
{
$sortResult = $sortResultwH;
}
$rowsFetched['rowsFetched'] = count($sortResult['header']);
if (empty($rowsFetched['messages'])) $rowsFetched['messages'] = $rowsFetched['rowsFetched'];
//error_log(__METHOD__.__LINE__.' Rows fetched:'.$rowsFetched.' Data:'.array2string($sortResult));
$cols = array('row_id','uid','status','attachments','subject','toaddress','fromaddress','date','size','modified');
if ($GLOBALS['egw_info']['user']['preferences']['common']['select_mode']=='EGW_SELECTMODE_TOGGLE') unset($cols[0]);
$rows = $this->header2gridelements($sortResult['header'],$cols, $_folderName, $folderType,$previewMessage);
//error_log(__METHOD__.__LINE__.array2string($rows));
$endtime = microtime(true) - $starttime;
//error_log(__METHOD__.__LINE__.' SelectedFolder:'.$query['selectedFolder'].' Start:'.$query['start'].' NumRows:'.$query['num_rows'].' Took:'.$endtime);
return $rowsFetched['messages'];
}
/**
* function createRowID - create a unique rowID for the grid
*
* @param string $_folderName, used to ensure the uniqueness of the uid over all folders
* @param string $message_uid, the message_Uid to be used for creating the rowID
* @return string - a colon separated string in the form accountID:profileID:folder:message_uid
*/
function createRowID($_folderName, $message_uid)
{
return trim($GLOBALS['egw_info']['user']['account_id']).self::$delimiter.$this->mail_bo->profileID.self::$delimiter.base64_encode($_folderName).self::$delimiter.$message_uid;
}
/**
* function splitRowID - split the rowID into its parts
*
* @param string $_rowID, string - a colon separated string in the form accountID:profileID:folder:message_uid
* @return array populated named result array (accountID,profileID,folder,msgUID)
*/
static function splitRowID($_rowID)
{
$res = explode(self::$delimiter,$_rowID);
// as a rowID is perceeded by app::, should be mail!
return array('app'=>$res[0], 'accountID'=>$res[1], 'profileID'=>$res[2], 'folder'=>base64_decode($res[3]), 'msgUID'=>$res[4]);
}
/**
* function header2gridelements - to populate the grid elements with the collected Data
*
* @param array $_headers, headerdata to process
* @param array $cols, cols to populate
* @param array $_folderName, used to ensure the uniqueness of the uid over all folders
* @param array $_folderType=0, foldertype, used to determine if we need to populate from/to
* @param array $previewMessage=0, the message previewed
* @return array populated result array
*/
public function header2gridelements($_headers, $cols, $_folderName, $_folderType=0, $previewMessage=0)
{
$timestamp7DaysAgo =
mktime(date("H"), date("i"), date("s"), date("m"), date("d")-7, date("Y"));
$timestampNow =
mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y"));
$dateToday = date("Y-m-d");
$rv = array();
$i=0;
$firstuid = null;
foreach((array)$_headers as $header)
{
$i++;
$data = array();
//error_log(__METHOD__.array2string($header));
$result = array(
"id" => $header['uid'],
"group" => "mail", // activate the action links for mail objects
);
$message_uid = $header['uid'];
$data['uid'] = $message_uid;
$data['row_id']=$this->createRowID($_folderName,$message_uid);
//_debug_array($header);
#if($i<10) {$i++;continue;}
#if($i>20) {continue;} $i++;
// create the listing of subjects
$maxSubjectLength = 60;
$maxAddressLength = 20;
$maxSubjectLengthBold = 50;
$maxAddressLengthBold = 14;
$flags = "";
if(!empty($header['recent'])) $flags .= "R";
if(!empty($header['flagged'])) $flags .= "F";
if(!empty($header['answered'])) $flags .= "A";
if(!empty($header['forwarded'])) $flags .= "W";
if(!empty($header['deleted'])) $flags .= "D";
if(!empty($header['seen'])) $flags .= "S";
if(!empty($header['label1'])) $flags .= "1";
if(!empty($header['label2'])) $flags .= "2";
if(!empty($header['label3'])) $flags .= "3";
if(!empty($header['label4'])) $flags .= "4";
if(!empty($header['label5'])) $flags .= "5";
$data["status"] = "";
//error_log(__METHOD__.array2string($header).' Flags:'.$flags);
// the css for this row
$is_recent=false;
$css_styles = array("mail");
if ($header['deleted']) {
$css_styles[] = 'deleted';
}
if ($header['recent'] && !($header['deleted'] || $header['seen'] || $header['answered'] || $header['forwarded'])) {
$css_styles[] = 'recent';
$is_recent=true;
}
if ($header['priority'] < 3) {
$css_styles[] = 'prio_high';
}
if ($header['flagged']) {
$css_styles[] = 'flagged';
/*
if (!$header['seen'])
{
$css_styles[] = 'flagged_unseen';
}
else
{
$css_styles[] = 'flagged_seen';
}
*/
}
if (!$header['seen']) {
$css_styles[] = 'unseen'; // different status image for recent // solved via css !important
}
if ($header['answered']) {
$css_styles[] = 'replied';
}
if ($header['forwarded']) {
$css_styles[] = 'forwarded';
}
if ($header['label1']) {
$css_styles[] = 'labelone';
}
if ($header['label2']) {
$css_styles[] = 'labeltwo';
}
if ($header['label3']) {
$css_styles[] = 'labelthree';
}
if ($header['label4']) {
$css_styles[] = 'labelfour';
}
if ($header['label5']) {
$css_styles[] = 'labelfive';
}
//error_log(__METHOD__.array2string($css_styles));
//if (in_array("check", $cols))
// don't overwrite check with "false" as this forces the grid to
// deselect the row - sending "0" doesn't do that
//if (in_array("check", $cols)) $data["check"] = $previewMessage == $header['uid'] ? true : 0;// $row_selected; //TODO:checkbox true or false
//$data["check"] ='';
if (in_array("subject", $cols))
{
// filter out undisplayable characters
$search = array('[\016]','[\017]',
'[\020]','[\021]','[\022]','[\023]','[\024]','[\025]','[\026]','[\027]',
'[\030]','[\031]','[\032]','[\033]','[\034]','[\035]','[\036]','[\037]');
$replace = '';
$header['subject'] = preg_replace($search,$replace,$header['subject']);
$headerSubject = $header['subject'];//mail_bo::htmlentities($header['subject'],$this->charset);
$header['subject'] = $headerSubject;
// curly brackets get messed up by the template!
$header['subject'] = str_replace(array('{','}'),array('{','}'),$header['subject']);
if (!empty($header['subject'])) {
// make the subject shorter if it is to long
$fullSubject = $header['subject'];
$subject = $header['subject'];
#$this->t->set_var('attachments', $header['attachment']);
} else {
$subject = @htmlspecialchars('('. lang('no subject') .')', ENT_QUOTES, $this->charset);
}
$data["subject"] = $subject; // the mailsubject
}
//_debug_array($header);
if (in_array("attachments", $cols))
{
if($header['mimetype'] == 'multipart/mixed' ||
$header['mimetype'] == 'multipart/signed' ||
$header['mimetype'] == 'multipart/related' ||
$header['mimetype'] == 'multipart/report' ||
$header['mimetype'] == 'text/calendar' ||
$header['mimetype'] == 'text/html' ||
substr($header['mimetype'],0,11) == 'application' ||
substr($header['mimetype'],0,5) == 'audio' ||
substr($header['mimetype'],0,5) == 'video' ||
$header['mimetype'] == 'multipart/alternative')
{
$linkDataAttachments = array (
'menuaction' => 'mail.uidisplay.displayAttachments',
'showHeader' => 'false',
'mailbox' => base64_encode($_folderName),
'uid' => $header['uid'],
'id' => $header['id'],
);
$windowName = 'displayMessage_'.$header['uid'];
$image = html::image('mail','attach');
if (//$header['mimetype'] != 'multipart/mixed' &&
$header['mimetype'] != 'multipart/signed'
)
{
if ($this->mail_bo->icServer->_connected != 1)
{
$this->mail_bo->openConnection($this->profileID); // connect to the current server
$this->mail_bo->reopen($_folderName);
}
$attachments = $this->mail_bo->getMessageAttachments($header['uid'],$_partID='', $_structure='', $fetchEmbeddedImages=true, $fetchTextCalendar=false, $resolveTNEF=false);
if (count($attachments)<1) $image = ' ';
}
if (count($attachments)>0) $image = "link('/index.php',$linkDataAttachments)."', '".$windowName."', this); return false;\"
title=\"".$header['subject']."\">".$image."";
$attachmentFlag = $image;
} else {
$attachmentFlag =' ';
}
// show priority flag
if ($header['priority'] < 3) {
$image = html::image('mail','prio_high');
} elseif ($header['priority'] > 3) {
$image = html::image('mail','prio_low');
} else {
$image = '';
}
// show a flag for flagged messages
$imageflagged ='';
if ($header['flagged'])
{
$imageflagged = html::image('mail','unread_flagged_small');
}
$data["attachments"] = $image.$attachmentFlag.$imageflagged; // icon for attachments available
}
// sent or draft or template folder -> to address
if (in_array("toaddress", $cols))
{
if(!empty($header['to_name'])) {
list($mailbox, $host) = explode('@',$header['to_address']);
$senderAddress = imap_rfc822_write_address($mailbox,
$host,
$header['to_name']);
} else {
$senderAddress = $header['to_address'];
}
$linkData = array
(
'menuaction' => 'mail.uicompose.compose',
'send_to' => base64_encode($senderAddress)
);
$windowName = 'compose_'.$header['uid'];
// sent or drafts or template folder means foldertype > 0, use to address instead of from
$header2add = $header['to_address'];//mail_bo::htmlentities($header['to_address'],$this->charset);
$header['to_address'] = $header2add;
if (!empty($header['to_name'])) {
$header2name = $header['to_name'];//mail_bo::htmlentities($header['to_name'],$this->charset);
$header['to_name'] = $header2name;
$sender_name = $header['to_name'];
$full_address = $header['to_name'].' <'.$header['to_address'].'>';
} else {
$sender_name = $header['to_address'];
$full_address = $header['to_address'];
}
//$data["toaddress"] = "
";print_r($rawheaders);print"
";exit; // add line breaks to $rawheaders $newRawHeaders = explode("\n",$rawheaders); reset($newRawHeaders); // reset $rawheaders $rawheaders = ""; // create it new, with good line breaks reset($newRawHeaders); while(list($key,$value) = @each($newRawHeaders)) { $rawheaders .= wordwrap($value, 90, "\n "); } $this->mail_bo->closeConnection(); header('Content-type: text/html; charset=iso-8859-1'); print '
'. htmlspecialchars($rawheaders, ENT_NOQUOTES, 'iso-8859-1') .'
'; } /** * display messages * * all params are passed as GET Parameters */ function displayMessage() { //_debug_array($_REQUEST); if(isset($_GET['id'])) $rowID = $_GET['id']; if(isset($_GET['part'])) $partID = $_GET['part']; $hA = self::splitRowID($rowID); $uid = $hA['msgUID']; $mailbox = $hA['folder']; //$transformdate =& CreateObject('felamimail.transformdate'); //$htmlFilter =& CreateObject('felamimail.htmlfilter'); //$uiWidgets =& CreateObject('felamimail.uiwidgets'); $this->mail_bo->reopen($mailbox); // retrieve the flags of the message, before touching it. $headers = $this->mail_bo->getMessageHeader($uid, $partID); if (PEAR::isError($headers)) { $error_msg[] = lang("ERROR: Message could not be displayed."); $error_msg[] = lang("In Mailbox: %1, with ID: %2, and PartID: %3",$mailbox,$uid,$partID); $error_msg[] = $headers->message; $error_msg[] = array2string($headers->backtrace[0]); } if (!empty($uid)) $flags = $this->mail_bo->getFlags($uid); $envelope = $this->mail_bo->getMessageEnvelope($uid, $partID,true); $rawheaders = $this->mail_bo->getMessageRawHeader($uid, $partID); $fetchEmbeddedImages = false; if ($htmlOptions !='always_display') $fetchEmbeddedImages = true; $attachments = $this->mail_bo->getMessageAttachments($uid, $partID, '',$fetchEmbeddedImages); //_debug_array($headers); $attachmentHTMLBlock = self::createAttachmentBlock($attachments, $rowID, $uid, $mailbox); $webserverURL = $GLOBALS['egw_info']['server']['webserver_url']; $nonDisplayAbleCharacters = array('[\016]','[\017]', '[\020]','[\021]','[\022]','[\023]','[\024]','[\025]','[\026]','[\027]', '[\030]','[\031]','[\032]','[\033]','[\034]','[\035]','[\036]','[\037]'); #print "
";print_r($rawheaders);print"
";exit;
$mailBody = $this->get_load_email_data($uid, $partID, $mailbox,false);
//error_log(__METHOD__.__LINE__.$mailBody);
$this->mail_bo->closeConnection();
$etpl = new etemplate_new('mail.display');
// Set cell attributes directly
/*
$etpl->set_cell_attribute('nm[foldertree]','actions', array(
'drop_move_mail' => array(
'type' => 'drop',
'acceptedTypes' => 'mail',
'icon' => 'move',
'caption' => 'Move to',
'onExecute' => 'javaScript:app.mail.mail_move'
),
));
*/
egw_framework::set_onload("");
$subject = mail_bo::htmlspecialchars($this->mail_bo->decode_subject(preg_replace($nonDisplayAbleCharacters,'',$envelope['SUBJECT']),false),
mail_bo::$displayCharset);
if (empty($subject)) $subject = lang('no subject');
$content['msg'] = $subject.(is_array($error_msg)?implode("
",$error_msg):$error_msg);
$content['mail_displaysubject'] = $subject;
$content['mail_displaybody'] = $mailBody;
//_debug_array($attachments);
$content['mail_displayattachments'] = $attachmentHTMLBlock;
$readonlys = $preserv = $content;
echo $etpl->exec('mail.mail_ui.displayMessage',$content,$sel_options,$readonlys,$preserv,2);
}
/**
* createAttachmentBlock
* helper function to create the attachment block/table
*
* @param array $attachments, array with the attachments information
* @param string $rowID, rowid of the message
* @param int $uid, uid of the message
* @param string $mailbox, the mailbox identifier
* @return string html or empty string
*/
static function createAttachmentBlock($attachments, $rowID, $uid, $mailbox)
{
$attachmentHTMLBlock='';
if (is_array($attachments) && count($attachments) > 0) {
$url_img_vfs = html::image('filemanager','navbar', lang('Filemanager'), ' height="16"');
$url_img_vfs_save_all = html::image('felamimail','save_all', lang('Save all'));
$detectedCharSet=$charset2use=mail_bo::$displayCharset;
foreach ($attachments as $key => $value)
{
//_debug_array($value);
#$detectedCharSet = mb_detect_encoding($value['name'].'a',strtoupper($this->displayCharset).",UTF-8, ISO-8559-1");
if (function_exists('mb_convert_variables')) mb_convert_variables("UTF-8","ISO-8559-1",$value['name']); # iso 2 UTF8
//if (mb_convert_variables("ISO-8859-1","UTF-8",$value['name'])){echo "Juhu utf8 2 ISO\n";};
//echo $value['name']."\n";
$filename=htmlentities($value['name'], ENT_QUOTES, $detectedCharSet);
$attachmentHTML[$key]['filename']= ($value['name'] ? ( $filename ? $filename : $value['name'] ) : lang('(no subject)'));
$attachmentHTML[$key]['mimetype']=mime_magic::mime2label($value['mimeType']);
$attachmentHTML[$key]['size']=egw_vfs::hsize($value['size']);
$attachmentHTML[$key]['attachment_number']=$key;
switch(strtoupper($value['mimeType']))
{
case 'MESSAGE/RFC822':
$linkData = array
(
'menuaction' => 'mail.mail_ui.displayMessage',
'id' => $rowID,
'part' => $value['partID'],
'mailbox' => base64_encode($mailbox),
'is_winmail' => $value['is_winmail']
);
$windowName = 'displayMessage_'. $rowID.'_'.$value['partID'];
$linkView = "egw_openWindowCentered('".$GLOBALS['egw']->link('/index.php',$linkData)."','$windowName',700,egw_getWindowOuterHeight());";
break;
case 'IMAGE/JPEG':
case 'IMAGE/PNG':
case 'IMAGE/GIF':
case 'IMAGE/BMP':
case 'APPLICATION/PDF':
case 'TEXT/PLAIN':
case 'TEXT/HTML':
case 'TEXT/DIRECTORY':
$sfxMimeType = $value['mimeType'];
$buff = explode('.',$value['name']);
$suffix = '';
if (is_array($buff)) $suffix = array_pop($buff); // take the last extension to check with ext2mime
if (!empty($suffix)) $sfxMimeType = mime_magic::ext2mime($suffix);
if (strtoupper($sfxMimeType) == 'TEXT/VCARD' || strtoupper($sfxMimeType) == 'TEXT/X-VCARD')
{
$attachments[$key]['mimeType'] = $sfxMimeType;
$value['mimeType'] = strtoupper($sfxMimeType);
}
case 'TEXT/X-VCARD':
case 'TEXT/VCARD':
case 'TEXT/CALENDAR':
case 'TEXT/X-VCALENDAR':
$linkData = array
(
'menuaction' => 'mail.mail_ui.getAttachment',
'id' => $rowID,
'part' => $value['partID'],
'is_winmail' => $value['is_winmail'],
'mailbox' => base64_encode($mailbox),
);
$windowName = 'displayAttachment_'. $uid;
$reg = '800x600';
// handle calendar/vcard
if (strtoupper($value['mimeType'])=='TEXT/CALENDAR')
{
$windowName = 'displayEvent_'. $rowID;
$reg2 = egw_link::get_registry('calendar','view_popup');
}
if (strtoupper($value['mimeType'])=='TEXT/X-VCARD' || strtoupper($value['mimeType'])=='TEXT/VCARD')
{
$windowName = 'displayContact_'. $rowID;
$reg2 = egw_link::get_registry('addressbook','add_popup');
}
// apply to action
list($width,$height) = explode('x',(!empty($reg2) ? $reg2 : $reg));
$linkView = "egw_openWindowCentered('".$GLOBALS['egw']->link('/index.php',$linkData)."','$windowName',$width,$height);";
break;
default:
$linkData = array
(
'menuaction' => 'mail.mail_ui.getAttachment',
'id' => $rowID,
'part' => $value['partID'],
'is_winmail' => $value['is_winmail'],
'mailbox' => base64_encode($mailbox),
);
$linkView = "window.location.href = '".$GLOBALS['egw']->link('/index.php',$linkData)."';";
break;
}
//error_log(__METHOD__.__LINE__.$linkView);
$attachmentHTML[$key]['link_view'] = ''.
($value['name'] ? ( $filename ? $filename : $value['name'] ) : lang('(no subject)')).
'';
$linkData = array
(
'menuaction' => 'mail.mail_ui.getAttachment',
'mode' => 'save',
'id' => $rowID,
'part' => $value['partID'],
'is_winmail' => $value['is_winmail'],
'mailbox' => base64_encode($mailbox),
);
$attachmentHTML[$key]['link_save'] ="link('/index.php',$linkData)."' title='".$attachmentHTML[$key]['filename']."'>".html::image('felamimail','fileexport')."";
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
{
$link_vfs_save = egw::link('/index.php',array(
'menuaction' => 'filemanager.filemanager_select.select',
'mode' => 'saveas',
'name' => $value['name'],
'mime' => strtolower($value['mimeType']),
'method' => 'felamimail.uidisplay.vfsSaveAttachment',
'id' => $mailbox.'::'.$uid.'::'.$value['partID'].'::'.$value['is_winmail'],
'label' => lang('Save'),
));
$vfs_save = "$url_img_vfs";
// add save-all icon for first attachment
if (!$key && count($attachments) > 1)
{
foreach ($attachments as $ikey => $value)
{
//$rowID
$ids["id[$ikey]"] = $rowID.'::'.$value['partID'].'::'.$value['is_winmail'].'::'.$value['name'];
}
$link_vfs_save = egw::link('/index.php',array(
'menuaction' => 'filemanager.filemanager_select.select',
'mode' => 'select-dir',
'method' => 'mail.mail_ui.vfsSaveAttachment',
'label' => lang('Save all'),
)+$ids);
$vfs_save .= "$url_img_vfs_save_all";
}
$attachmentHTML[$key]['link_save'] .= $vfs_save;
//error_log(__METHOD__.__LINE__.$attachmentHTML[$key]['link_save']);
}
}
$attachmentHTMLBlock="
".$row['link_view'].' | '; $attachmentHTMLBlock .= "".$row['mimetype'].' | '; $attachmentHTMLBlock .= "".$row['size'].' | '; $attachmentHTMLBlock .= "".$row['link_save'].' |
"; } return $attachmentHTMLBlock; } /** * display image * * all params are passed as GET Parameters */ function displayImage() { $uid = $_GET['uid']; $cid = base64_decode($_GET['cid']); $partID = urldecode($_GET['partID']); if (!empty($_GET['mailbox'])) $mailbox = base64_decode($_GET['mailbox']); //error_log(__METHOD__.__LINE__.":$uid, $cid, $partID"); $this->mail_bo->reopen($mailbox); $attachment = $this->mail_bo->getAttachmentByCID($uid, $cid, $partID); $this->mail_bo->closeConnection(); $GLOBALS['egw']->session->commit_session(); if(is_array($attachment)) { //error_log("Content-Type: ".$attachment['type']."; name=\"". $attachment['filename'] ."\""); header ("Content-Type: ". strtolower($attachment['type']) ."; name=\"". $attachment['filename'] ."\""); header ('Content-Disposition: inline; filename="'. $attachment['filename'] .'"'); header("Expires: 0"); // the next headers are for IE and SSL header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Pragma: public"); echo trim($attachment['attachment']); exit; } $GLOBALS['egw']->common->egw_exit(); exit; } function getAttachment() { if(isset($_GET['id'])) $rowID = $_GET['id']; if(isset($_GET['part'])) $partID = $_GET['part']; $hA = self::splitRowID($rowID); $uid = $hA['msgUID']; $mailbox = $hA['folder']; $part = $_GET['part']; $is_winmail = $_GET['is_winmail'] ? $_GET['is_winmail'] : 0; $this->mail_bo->reopen($mailbox); #$attachment = $this->bofelamimail->getAttachment($this->uid,$part); $attachment = $this->mail_bo->getAttachment($uid,$part,$is_winmail); $this->mail_bo->closeConnection(); $GLOBALS['egw']->session->commit_session(); if ($_GET['mode'] != "save") { if (strtoupper($attachment['type']) == 'TEXT/DIRECTORY') { $sfxMimeType = $attachment['type']; $buff = explode('.',$attachment['filename']); $suffix = ''; if (is_array($buff)) $suffix = array_pop($buff); // take the last extension to check with ext2mime if (!empty($suffix)) $sfxMimeType = mime_magic::ext2mime($suffix); $attachment['type'] = $sfxMimeType; if (strtoupper($sfxMimeType) == 'TEXT/VCARD' || strtoupper($sfxMimeType) == 'TEXT/X-VCARD') $attachment['type'] = strtoupper($sfxMimeType); } //error_log(__METHOD__.print_r($attachment,true)); if (strtoupper($attachment['type']) == 'TEXT/CALENDAR' || strtoupper($attachment['type']) == 'TEXT/X-VCALENDAR') { //error_log(__METHOD__."about to call calendar_ical"); $calendar_ical = new calendar_ical(); $eventid = $calendar_ical->search($attachment['attachment'],-1); //error_log(__METHOD__.array2string($eventid)); if (!$eventid) $eventid = -1; $event = $calendar_ical->importVCal($attachment['attachment'],(is_array($eventid)?$eventid[0]:$eventid),null,true); //error_log(__METHOD__.$event); if ((int)$event > 0) { $vars = array( 'menuaction' => 'calendar.calendar_uiforms.edit', 'cal_id' => $event, ); $GLOBALS['egw']->redirect_link('../index.php',$vars); } //Import failed, download content anyway } if (strtoupper($attachment['type']) == 'TEXT/X-VCARD' || strtoupper($attachment['type']) == 'TEXT/VCARD') { $addressbook_vcal = new addressbook_vcal(); // double \r\r\n seems to end a vcard prematurely, so we set them to \r\n //error_log(__METHOD__.__LINE__.$attachment['attachment']); $attachment['attachment'] = str_replace("\r\r\n", "\r\n", $attachment['attachment']); $vcard = $addressbook_vcal->vcardtoegw($attachment['attachment']); if ($vcard['uid']) { $vcard['uid'] = trim($vcard['uid']); //error_log(__METHOD__.__LINE__.print_r($vcard,true)); $contact = $addressbook_vcal->find_contact($vcard,false); } if (!$contact) $contact = null; // if there are not enough fields in the vcard (or the parser was unable to correctly parse the vcard (as of VERSION:3.0 created by MSO)) if ($contact || count($vcard)>2) { $contact = $addressbook_vcal->addVCard($attachment['attachment'],(is_array($contact)?array_shift($contact):$contact),true); } if ((int)$contact > 0) { $vars = array( 'menuaction' => 'addressbook.addressbook_ui.edit', 'contact_id' => $contact, ); $GLOBALS['egw']->redirect_link('../index.php',$vars); } //Import failed, download content anyway } } header ("Content-Type: ".$attachment['type']."; name=\"". $attachment['filename'] ."\""); if($_GET['mode'] == "save") { // ask for download header ("Content-Disposition: attachment; filename=\"". $attachment['filename'] ."\""); } else { // display it header ("Content-Disposition: inline; filename=\"". $attachment['filename'] ."\""); } header("Expires: 0"); // the next headers are for IE and SSL header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Pragma: public"); echo $attachment['attachment']; $GLOBALS['egw']->common->egw_exit(); exit; } /** * save messages on disk or filemanager, or display it in popup * * all params are passed as GET Parameters */ function saveMessage() { $display = false; if(isset($_GET['id'])) $rowID = $_GET['id']; if(isset($_GET['part'])) $partID = $_GET['part']; if (isset($_GET['location'])&& ($_GET['location']=='display'||$_GET['location']=='filemanager')) $display = $_GET['location']; $hA = self::splitRowID($rowID); $uid = $hA['msgUID']; $mailbox = $hA['folder']; $this->mail_bo->reopen($mailbox); $message = $this->mail_bo->getMessageRawBody($uid, $partID); $headers = $this->mail_bo->getMessageHeader($uid, $partID); $this->mail_bo->closeConnection(); $GLOBALS['egw']->session->commit_session(); if ($display==false) { $subject = str_replace('$$','__',mail_bo::decode_header($headers['SUBJECT'])); header ("Content-Type: message/rfc822; name=\"". $subject .".eml\""); header ("Content-Disposition: attachment; filename=\"". $subject .".eml\""); header("Expires: 0"); // the next headers are for IE and SSL header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Pragma: public"); echo $message; $GLOBALS['egw']->common->egw_exit(); exit; } //elseif ($display=='filemanager') // done in vfsSaveMessage //{ //} else { header('Content-type: text/html; charset=iso-8859-1'); print '
'. htmlspecialchars($message, ENT_NOQUOTES, 'iso-8859-1') .'
'; } } /** * Save an Message in the vfs * * @param string|array $ids use splitRowID, to separate values * @param string $path path in vfs (no egw_vfs::PREFIX!), only directory for multiple id's ($ids is an array) * @return string javascript eg. to close the selector window */ function vfsSaveMessage($ids,$path) { error_log(__METHOD__.' IDs:'.array2string($ids).' SaveToPath:'.$path); if (is_array($ids) && !egw_vfs::is_writable($path) || !is_array($ids) && !egw_vfs::is_writable(dirname($path))) { return 'alert("'.addslashes(lang('%1 is NOT writable by you!',$path)).'"); window.close();'; } foreach((array)$ids as $id) { $hA = self::splitRowID($id); $uid = $hA['msgUID']; $mailbox = $hA['folder']; if ($mb != $this->mail_bo->mailbox) $this->mail_bo->reopen($mb = $mailbox); $message = $this->mail_bo->getMessageRawBody($uid, $partID=''); if (!($fp = egw_vfs::fopen($file=$path.($name ? '/'.$name : ''),'wb')) || !fwrite($fp,$message)) { $err .= 'alert("'.addslashes(lang('Error saving %1!',$file)).'");'; } if ($fp) fclose($fp); } //$this->mail_bo->closeConnection(); return $err.'window.close();'; } function get_load_email_data($uid, $partID, $mailbox,$fullHeader=true) { // seems to be needed, as if we open a mail from notification popup that is // located in a different folder, we experience: could not parse message $this->mail_bo->reopen($mailbox); $this->mailbox = $mailbox; $this->uid = $uid; $this->partID = $partID; $bodyParts = $this->mail_bo->getMessageBody($uid, '', $partID, '', false, $mailbox); //error_log(__METHOD__.__LINE__.array2string($bodyParts)); $meetingRequest = false; $fetchEmbeddedImages = false; if ($this->mail_bo->htmlOptions !='always_display') $fetchEmbeddedImages = true; $attachments = $this->mail_bo->getMessageAttachments($uid, $partID, '',$fetchEmbeddedImages,true); foreach ((array)$attachments as $key => $attach) { if (strtolower($attach['mimeType']) == 'text/calendar' && (strtolower($attach['method']) == 'request' || strtolower($attach['method']) == 'reply') && isset($GLOBALS['egw_info']['user']['apps']['calendar']) && ($attachment = $this->mail_bo->getAttachment($uid, $attach['partID']))) { //error_log(__METHOD__.__LINE__.array2string($attachment)); egw_cache::setSession('calendar', 'ical', array( 'charset' => $attach['charset'] ? $attach['charset'] : 'utf-8', 'attachment' => $attachment['attachment'], 'method' => $attach['method'], 'sender' => $sender, )); return ExecMethod( 'calendar.calendar_uiforms.meeting', array('event'=>null,'msg'=>'','useSession'=>true) ); } } // Compose the content of the frame $frameHtml = $this->get_email_header($this->mail_bo->getStyles($bodyParts),$fullHeader). $this->showBody($this->getdisplayableBody($bodyParts), false,$fullHeader); //IE10 eats away linebreaks preceeded by a whitespace in PRE sections $frameHtml = str_replace(" \r\n","\r\n",$frameHtml); return $frameHtml; } static function get_email_header($additionalStyle='',$fullHeader=true) { //error_log(__METHOD__.__LINE__.$additionalStyle); $header = ($fullHeader?'
':'').' '.$additionalStyle.' '.($fullHeader?'