2013-02-08 20:11:44 +01:00
< ? php
/**
* EGroupware - Mail - interface class
*
* @ link http :// www . egroupware . org
* @ package mail
2016-10-08 14:32:58 +02:00
* @ author EGroupware GmbH [ info @ egroupware . org ]
* @ copyright ( c ) 2013 - 2016 by EGroupware GmbH < info - AT - egroupware . org >
2013-02-08 20:11:44 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id $
*/
2016-03-13 12:56:00 +01:00
use EGroupware\Api ;
2016-05-03 21:17:44 +02:00
use EGroupware\Api\Link ;
use EGroupware\Api\Framework ;
use EGroupware\Api\Egw ;
use EGroupware\Api\Vfs ;
use EGroupware\Api\Etemplate ;
use EGroupware\Api\Etemplate\KeyManager ;
2016-03-28 20:51:38 +02:00
use EGroupware\Api\Mail ;
2016-03-13 12:56:00 +01:00
2013-02-08 20:11:44 +01:00
/**
2014-08-20 16:58:12 +02:00
* Mail User Interface
*
* As we do NOT want to connect to previous imap server , when a profile change is triggered
* by user get_rows and ajax_changeProfile are not static methods and instanciates there own
* mail_ui object .
*
* If they detect a profile change is to be triggered they call :
* $mail_ui = new mail_ui ( false ); // not call constructor / connect to imap server
* $mail_ui -> changeProfile ( $_profileID );
* If no profile change is needed they just call :
* $mail_ui = new mail_ui ();
* Afterwards they use $mail_ui instead of $this .
2015-08-21 10:01:42 +02:00
*/
2013-02-08 20:11:44 +01:00
class mail_ui
{
/**
* Methods callable via menuaction
*
* @ var array
*/
var $public_functions = array
(
'index' => True ,
2013-02-28 10:28:08 +01:00
'displayHeader' => True ,
2013-06-05 16:24:56 +02:00
'displayMessage' => True ,
2013-06-12 13:50:30 +02:00
'displayImage' => True ,
'getAttachment' => True ,
2014-07-08 14:01:29 +02:00
'download_zip' => True ,
2013-02-28 10:28:08 +01:00
'saveMessage' => True ,
2017-11-17 18:31:15 +01:00
'vfsSaveMessages' => True ,
2013-04-12 15:10:27 +02:00
'loadEmailBody' => True ,
2013-04-12 11:22:23 +02:00
'importMessage' => True ,
2014-01-24 11:30:45 +01:00
'importMessageFromVFS2DraftAndDisplay' => True ,
2014-02-06 18:18:12 +01:00
'subscription' => True ,
2015-08-10 17:45:22 +02:00
'folderManagement' => true ,
2017-08-30 17:00:28 +02:00
'smimeExportCert' => true
2013-02-08 20:11:44 +01:00
);
2013-02-20 17:27:10 +01:00
/**
* current icServerID
*
* @ var int
*/
static $icServerID ;
/**
* delimiter - used to separate profileID from foldertreestructure , and separate keyinformation in rowids
*
* @ var string
*/
static $delimiter = '::' ;
2013-08-21 12:47:20 +02:00
/**
* nextMatch name for index
*
* @ var string
*/
static $nm_index = 'nm' ;
2013-02-08 20:11:44 +01:00
/**
2016-03-28 20:51:38 +02:00
* instance of Mail
2013-02-08 20:11:44 +01:00
*
2016-03-28 20:51:38 +02:00
* @ var Mail
2013-02-08 20:11:44 +01:00
*/
var $mail_bo ;
2013-07-17 14:01:01 +02:00
/**
* definition of available / supported search types
*
* @ var array
*/
var $searchTypes = array (
2013-07-20 09:23:55 +02:00
'quick' => 'quicksearch' , // lang('quicksearch')
2016-03-24 11:38:35 +01:00
'quickwithcc' => 'quicksearch (with cc)' , // lang('quicksearch (with cc)')
2013-07-20 09:23:55 +02:00
'subject' => 'subject' , // lang('subject')
'body' => 'message body' , // lang('message body')
'from' => 'from' , // lang('from')
'to' => 'to' , // lang('to')
'cc' => 'cc' , // lang('cc')
2016-02-19 13:23:06 +01:00
'text' => 'whole message' , // lang('whole message')
2016-03-24 11:38:35 +01:00
'larger' => 'greater than' , // lang('greater than')
'smaller' => 'less than' , // lang('less than')
2016-04-12 14:53:50 +02:00
'bydate' => 'Selected date range (with quicksearch)' , // lang('Selected date range (with quicksearch)')
2013-07-17 14:01:01 +02:00
);
/**
* definition of available / supported status types
*
* @ var array
*/
var $statusTypes = array (
2013-07-20 09:23:55 +02:00
'any' => 'any status' , // lang('any status')
2013-10-22 17:30:25 +02:00
'flagged' => 'flagged' , // lang('flagged')
2013-07-20 09:23:55 +02:00
'unseen' => 'unread' , // lang('unread')
'answered' => 'replied' , // lang('replied')
'seen' => 'read' , // lang('read')
'deleted' => 'deleted' , // lang('deleted')
2013-07-17 14:01:01 +02:00
);
2013-02-08 20:11:44 +01:00
/**
* Constructor
*
2014-08-20 16:58:12 +02:00
* @ param boolean $run_constructor = true false : no not run constructor and therefore do NOT connect to imap server
2013-02-08 20:11:44 +01:00
*/
2014-08-20 16:58:12 +02:00
function __construct ( $run_constructor = true )
2013-02-08 20:11:44 +01:00
{
2015-08-03 16:33:18 +02:00
$this -> mail_tree = new mail_tree ( $this );
2014-08-20 16:58:12 +02:00
if ( ! $run_constructor ) return ;
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) $starttime = microtime ( true );
2013-02-08 20:11:44 +01:00
// no autohide of the sidebox, as we use it for folderlist now.
unset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'auto_hide_sidebox' ]);
2013-02-20 12:31:57 +01:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ]) && ! empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ]))
{
2013-02-20 17:27:10 +01:00
self :: $icServerID = ( int ) $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ];
2013-02-20 12:31:57 +01:00
}
2014-09-25 10:47:47 +02:00
if ( $_GET [ " resetConnection " ])
2013-02-08 20:11:44 +01:00
{
2014-09-25 10:47:47 +02:00
unset ( $_GET [ " resetConnection " ]);
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' Connection Reset triggered: for Profile with ID:' . self :: $icServerID );
Mail :: unsetCachedObjects ( self :: $icServerID );
2013-02-08 20:11:44 +01:00
}
2013-11-06 22:02:19 +01:00
try {
2016-03-28 20:51:38 +02:00
$this -> mail_bo = Mail :: getInstance ( true , self :: $icServerID , true , false , true );
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' Fetched IC Server:' . self :: $icServerID . '/' . $this -> mail_bo -> profileID . ':' . function_backtrace ());
2013-11-06 22:02:19 +01:00
//error_log(__METHOD__.__LINE__.array2string($this->mail_bo->icServer));
2014-08-11 16:16:26 +02:00
2014-07-31 12:18:41 +02:00
// RegEx to minimize extra openConnection
2014-08-21 16:11:35 +02:00
$needle = '/^(?!mail)/' ;
2016-05-03 21:17:44 +02:00
if ( ! preg_match ( $needle , $_GET [ 'menuaction' ]) && ! Api\Json\Request :: isJSONRequest ())
2014-02-27 16:32:14 +01:00
{
2014-05-09 14:43:57 +02:00
//error_log(__METHOD__.__LINE__.' Fetched IC Server openConnection:'.self::$icServerID.'/'.$this->mail_bo->profileID.':'.function_backtrace());
2014-02-27 16:32:14 +01:00
//openConnection gathers SpecialUseFolderInformation and Delimiter Info
$this -> mail_bo -> openConnection ( self :: $icServerID );
}
2013-11-06 22:02:19 +01:00
}
catch ( Exception $e )
{
2016-06-09 15:46:51 +02:00
// we need this to handle failed JSONRequests
if ( Api\Json\Request :: isJSONRequest () && $_GET [ 'menuaction' ] != 'mail.mail_ui.index' )
{
$response = Api\Json\Response :: get ();
$response -> call ( 'egw.message' , $e -> getMessage (), 'error' );
}
// redirect to mail wizard to handle it (redirect works for ajax too), unless index is called. we want the sidebox
if ( $_GET [ 'menuaction' ] != 'mail.mail_ui.index' ) self :: callWizard ( $e -> getMessage (), true , 'error' , false );
2013-11-06 22:02:19 +01:00
}
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) Mail :: logRunTimes ( $starttime , null , '' , __METHOD__ . __LINE__ );
2013-02-08 20:11:44 +01:00
}
2014-05-09 14:43:57 +02:00
/**
* callWizard
*
* @ param string $message
2016-05-03 21:17:44 +02:00
* @ param boolean $exit If true , will call exit () after opening the wizardpopup
2014-08-08 15:36:33 +02:00
* @ param string $msg_type = 'success' message type
2014-05-09 14:43:57 +02:00
*/
2016-06-09 15:46:51 +02:00
static function callWizard ( $message , $exit = true , $msg_type = 'success' , $reset_sidebox_on_index = true )
2014-05-09 14:43:57 +02:00
{
2014-05-20 13:47:18 +02:00
//error_log(__METHOD__."('$message', $exit) ".function_backtrace());
2014-05-09 14:43:57 +02:00
$linkData = ( self :: $icServerID ? array (
'menuaction' => 'mail.mail_wizard.edit' ,
'acc_id' => self :: $icServerID ,
) : array (
'menuaction' => 'mail.mail_wizard.add' ,
)) + array (
2014-08-08 15:36:33 +02:00
'msg' => $message ,
'msg_type' => $msg_type
2014-05-09 14:43:57 +02:00
);
2014-05-12 09:35:23 +02:00
2023-01-25 13:38:40 +01:00
// if we already called the wizard, ignore further calls for 5min = 300s
if ( ! Api\Cache :: getSession ( __CLASS__ , $id = 'call-wizzard-' . self :: $icServerID ))
{
Api\Cache :: setSession ( __CLASS__ , $id , self :: $icServerID , 300 );
}
// ignore further calls / one popup is enough
elseif ( $exit )
{
exit ;
}
else
{
return ;
}
2016-05-03 21:17:44 +02:00
if ( Api\Json\Response :: isJSONResponse ())
2014-05-12 09:35:23 +02:00
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-05-12 09:35:23 +02:00
$windowName = " editMailAccount " . self :: $icServerID ;
2016-05-03 21:17:44 +02:00
$response -> call ( " egw.open_link " , Egw :: link ( '/index.php' , $linkData ), $windowName , " 600x480 " , null , true );
Framework :: message ( $message , 'error' );
2016-06-09 15:46:51 +02:00
if ( $_GET [ 'menuaction' ] == 'mail.mail_ui.index' && $reset_sidebox_on_index )
2014-07-18 19:18:29 +02:00
{
$response -> call ( 'framework.setSidebox' , 'mail' , array (), 'md5' );
2014-08-11 16:16:26 +02:00
}
2014-05-12 09:35:23 +02:00
if ( $exit )
{
2016-05-03 21:17:44 +02:00
exit ();
2014-05-12 09:35:23 +02:00
}
}
else // regular GET request eg. in idots template
{
2016-06-09 15:46:51 +02:00
$windowName = " editMailAccount " . self :: $icServerID ;
Framework :: popup ( Framework :: link ( '/index.php' , $linkData ), $windowName );
2014-06-23 13:38:42 +02:00
$GLOBALS [ 'egw' ] -> framework -> render ( $message , '' , true );
2014-06-30 17:48:49 +02:00
if ( $exit )
{
2016-05-03 21:17:44 +02:00
exit ();
2014-07-08 13:09:31 +02:00
}
2014-05-12 09:35:23 +02:00
}
2014-05-09 14:43:57 +02:00
}
2013-02-20 12:31:57 +01:00
/**
* changeProfile
*
2014-07-16 15:42:36 +02:00
* @ param int $_icServerID
* @ param boolean $unsetCache
2015-07-29 15:34:56 +02:00
*
2016-05-03 21:17:44 +02:00
* @ throws Api\Exception
2013-02-20 12:31:57 +01:00
*/
2013-06-04 17:29:53 +02:00
function changeProfile ( $_icServerID , $unsetCache = false )
2013-02-20 12:31:57 +01:00
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) $starttime = microtime ( true );
2013-10-08 16:23:46 +02:00
if ( self :: $icServerID != $_icServerID )
{
2014-06-30 17:48:49 +02:00
self :: $icServerID = $_icServerID ;
2013-10-08 16:23:46 +02:00
}
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . '->' . self :: $icServerID . '<->' . $_icServerID );
2014-07-08 13:09:31 +02:00
2016-03-28 20:51:38 +02:00
if ( $unsetCache ) Mail :: unsetCachedObjects ( self :: $icServerID );
2016-03-29 11:56:21 +02:00
$this -> mail_bo = Mail :: getInstance ( false , self :: $icServerID , true , false , true );
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' Fetched IC Server:' . self :: $icServerID . '/' . $this -> mail_bo -> profileID . ':' . function_backtrace ());
2013-02-20 12:31:57 +01:00
// no icServer Object: something failed big time
2016-06-14 10:50:04 +02:00
if ( ! isset ( $this -> mail_bo ) || ! isset ( $this -> mail_bo -> icServer ) || $this -> mail_bo -> icServer -> ImapServerId <> $_icServerID )
2014-06-30 17:48:49 +02:00
{
self :: $icServerID = $_icServerID ;
2016-05-03 21:17:44 +02:00
throw new Api\Exception ( 'Profile change failed!' );
2014-06-30 17:48:49 +02:00
}
2014-07-08 13:09:31 +02:00
2013-02-20 12:31:57 +01:00
// save session varchar
2016-05-03 21:17:44 +02:00
$oldicServerID =& Api\Cache :: getSession ( 'mail' , 'activeProfileID' );
2020-07-20 12:08:53 +02:00
if ( $oldicServerID != self :: $icServerID )
{
$this -> mail_bo -> openConnection ( self :: $icServerID );
}
2016-05-03 21:17:44 +02:00
if ( true ) $oldicServerID = self :: $icServerID ;
2016-03-28 20:51:38 +02:00
if ( ! Mail :: storeActiveProfileIDToPref ( $this -> mail_bo -> icServer , self :: $icServerID , true ))
2014-05-09 14:43:57 +02:00
{
2016-05-03 21:17:44 +02:00
throw new Api\Exception ( __METHOD__ . " failed to change Profile to $_icServerID " );
2014-05-09 14:43:57 +02:00
}
2014-07-08 13:09:31 +02:00
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) Mail :: logRunTimes ( $starttime , null , '' , __METHOD__ . __LINE__ );
2013-02-20 12:31:57 +01:00
}
2015-08-21 10:01:42 +02:00
2015-07-20 18:41:50 +02:00
/**
* Ajax function to request next branch of a tree branch
*/
2015-07-27 19:46:45 +02:00
static function ajax_tree_autoloading ( $_id = null )
2015-07-20 18:41:50 +02:00
{
$mail_ui = new mail_ui ();
2016-04-04 10:48:04 +02:00
$id = $_id ? $_id : $_GET [ 'id' ];
2016-05-03 21:17:44 +02:00
Etemplate\Widget\Tree :: send_quote_json ( $mail_ui -> mail_tree -> getTree ( $id , '' , 1 , false ));
2015-07-20 18:41:50 +02:00
}
2015-08-21 10:01:42 +02:00
2014-02-06 18:18:12 +01:00
/**
* Subscription popup window
*
* @ param array $content
* @ param type $msg
*/
2014-08-15 13:22:43 +02:00
function subscription ( array $content = null , $msg = null )
2014-02-06 18:18:12 +01:00
{
2016-05-03 21:17:44 +02:00
$stmpl = new Etemplate ( 'mail.subscribe' );
2014-02-19 09:01:37 +01:00
2014-08-15 13:22:43 +02:00
if ( is_array ( $content ))
{
$profileId = $content [ 'profileId' ];
}
elseif ( ! ( $profileId = ( int ) $_GET [ 'acc_id' ]))
{
2016-05-03 21:17:44 +02:00
Framework :: window_close ( 'Missing acc_id!' );
2014-08-15 13:22:43 +02:00
}
2024-04-16 14:23:30 +02:00
// Initial tree's options, the rest would be loaded dynamically by autoloading,
2015-07-27 19:46:45 +02:00
// triggered from client-side. Also, we keep this here as
2015-10-06 17:09:10 +02:00
$sel_options [ 'foldertree' ] = $this -> mail_tree -> getTree ( null , $profileId , 1 , true , false , true );
2015-08-21 10:01:42 +02:00
2015-07-28 15:50:12 +02:00
//Get all subscribed folders
// as getting all subscribed folders is very fast operation
2015-07-27 19:46:45 +02:00
// we can use it to get a comparison base for folders which
// got subscribed or unsubscribed by the user
try {
2024-04-16 14:23:30 +02:00
$subscribed = array_keys ( $this -> mail_bo -> icServer -> listSubscribedMailboxes ( '' , 0 , true ) ? : []);
2015-07-27 19:46:45 +02:00
} catch ( Exception $ex ) {
2016-05-03 21:17:44 +02:00
Framework :: message ( $ex -> getMessage ());
2015-07-27 19:46:45 +02:00
}
2015-08-21 10:01:42 +02:00
2014-02-06 18:18:12 +01:00
if ( ! is_array ( $content ))
{
2024-04-16 14:23:30 +02:00
$content [ 'foldertree' ] = array_map ( static function ( $folder ) use ( $profileId )
2014-02-06 18:18:12 +01:00
{
2024-04-16 14:23:30 +02:00
return $profileId . self :: $delimiter . $folder ;
}, $subscribed );
2014-05-09 14:43:57 +02:00
}
2014-02-06 18:18:12 +01:00
else
{
2019-02-12 22:13:45 +01:00
$button = @ key ( $content [ 'button' ]);
2024-04-16 14:23:30 +02:00
unset ( $content [ $button ]);
2014-02-07 17:29:20 +01:00
switch ( $button )
{
case 'save' :
case 'apply' :
{
2014-08-15 13:22:43 +02:00
// do not let user (un)subscribe namespace roots eg. "other", "user" or "INBOX", same for tree-root/account itself
$namespace_roots = array ( $profileId );
foreach ( $this -> mail_bo -> _getNameSpaces () as $namespace )
{
$namespace_roots [] = $profileId . self :: $delimiter . str_replace ( $namespace [ 'delimiter' ], '' , $namespace [ 'prefix' ]);
}
2024-04-16 14:23:30 +02:00
$to_unsubscribe = array_diff ( $subscribed , $subs = array_map ( static function ( $id )
2015-07-27 19:46:45 +02:00
{
2024-04-16 14:23:30 +02:00
return explode ( self :: $delimiter , $id )[ 1 ];
}, $content [ 'foldertree' ]));
$to_subscribe = array_diff ( $subs , $subscribed );
2015-07-27 19:46:45 +02:00
// set foldertree options to basic node in order to avoid initial autoloading
// from client side, as no options would trigger that.
2024-04-16 14:23:30 +02:00
//$sel_options['foldertree'] = array('id' => '0', 'item'=> array());
2014-08-15 13:22:43 +02:00
foreach ( array_merge ( $to_subscribe , $to_unsubscribe ) as $mailbox )
2014-02-07 17:29:20 +01:00
{
2015-07-27 19:46:45 +02:00
if ( in_array ( $profileId . self :: $delimiter . $mailbox , $namespace_roots , true ))
{
continue ;
}
2014-08-15 13:22:43 +02:00
$subscribe = in_array ( $mailbox , $to_subscribe );
try {
$this -> mail_bo -> icServer -> subscribeMailbox ( $mailbox , $subscribe );
}
catch ( Exception $ex )
2014-02-07 17:29:20 +01:00
{
2014-08-15 13:22:43 +02:00
$msg_type = 'error' ;
if ( $subscribe )
2014-02-17 17:36:16 +01:00
{
2014-08-15 13:22:43 +02:00
$msg .= lang ( 'Failed to subscribe folder %1!' , $mailbox ) . ' ' . $ex -> getMessage ();
2014-02-17 17:36:16 +01:00
}
else
{
2014-08-15 13:22:43 +02:00
$msg .= lang ( 'Failed to unsubscribe folder %1!' , $mailbox ) . ' ' . $ex -> getMessage ();
2014-02-17 17:36:16 +01:00
}
2014-02-07 17:29:20 +01:00
}
2014-08-15 13:22:43 +02:00
}
if ( ! isset ( $msg ))
{
$msg_type = 'success' ;
if ( $to_subscribe || $to_unsubscribe )
{
$msg = lang ( 'Subscription successfully saved.' );
}
2014-02-07 17:29:20 +01:00
else
{
2014-08-15 13:22:43 +02:00
$msg = lang ( 'Nothing to change.' );
2014-02-07 17:29:20 +01:00
}
}
2014-08-15 13:22:43 +02:00
// update foldertree in main window
2014-04-24 11:23:06 +02:00
$parentFolder = 'INBOX' ;
$refreshData = array (
2015-07-27 19:46:45 +02:00
$profileId => lang ( $parentFolder ),
2014-05-20 16:28:23 +02:00
);
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-04-24 11:23:06 +02:00
foreach ( $refreshData as $folder => & $name )
{
2015-08-03 16:33:18 +02:00
$name = $this -> mail_tree -> getTree ( $folder , $profileId , 1 , true , true , true );
2014-04-24 11:23:06 +02:00
}
2014-08-15 13:22:43 +02:00
// give success/error message to opener and popup itself
2015-07-27 19:46:45 +02:00
//$response->call('opener.app.mail.subscription_refresh',$refreshData);
2014-04-24 11:23:06 +02:00
$response -> call ( 'opener.app.mail.mail_reloadNode' , $refreshData );
2015-07-27 19:46:45 +02:00
2016-05-03 21:17:44 +02:00
Framework :: refresh_opener ( $msg , 'mail' , null , null , null , null , null , $msg_type );
2014-08-15 13:22:43 +02:00
if ( $button == 'apply' )
{
2016-05-03 21:17:44 +02:00
Framework :: message ( $msg , $msg_type );
2014-08-15 13:22:43 +02:00
break ;
}
2014-02-07 17:29:20 +01:00
}
case 'cancel' :
{
2016-05-03 21:17:44 +02:00
Framework :: window_close ();
2014-02-07 17:29:20 +01:00
}
}
2014-02-06 18:18:12 +01:00
}
2014-02-19 09:01:37 +01:00
2014-08-15 13:22:43 +02:00
$preserv [ 'profileId' ] = $profileId ;
2015-08-21 10:01:42 +02:00
2014-02-06 18:18:12 +01:00
$readonlys = array ();
2014-02-07 17:29:20 +01:00
$stmpl -> exec ( 'mail.mail_ui.subscription' , $content , $sel_options , $readonlys , $preserv , 2 );
2014-02-06 18:18:12 +01:00
}
2013-02-20 12:31:57 +01:00
2020-07-09 11:54:52 +02:00
const DEFAULT_IMAGE_PROXY = 'https://' ;
const EGROUPWARE_IMAGE_PROXY = 'https://proxy.egroupware.org/7d510d4f7966f97ab56580425ddb4811e707c018/' ;
const IMAGE_PROXY_CONFIG = 'http_image_proxy' ;
/**
* Get image proxy / http :// replacement for image urls
*
* @ return string
*/
protected static function image_proxy ()
{
$configs = Api\Config :: read ( 'mail' );
2021-10-07 10:14:08 +02:00
$image_proxy = $configs [ self :: IMAGE_PROXY_CONFIG ] ? ? self :: DEFAULT_IMAGE_PROXY ;
2020-07-09 11:54:52 +02:00
if ( strpos ( self :: EGROUPWARE_IMAGE_PROXY , parse_url ( $image_proxy , PHP_URL_HOST )))
{
$image_proxy = self :: EGROUPWARE_IMAGE_PROXY ;
}
return $image_proxy ;
}
2013-02-08 20:11:44 +01:00
/**
* Main mail page
*
2014-05-22 09:47:49 +02:00
* @ param array $content
* @ param string $msg
2013-02-08 20:11:44 +01:00
*/
function index ( array $content = null , $msg = null )
{
2016-02-25 13:26:50 +01:00
//error_log(__METHOD__.__LINE__.array2string($content));
2014-07-18 19:18:29 +02:00
try {
2016-06-16 16:39:17 +02:00
if ( ! isset ( $this -> mail_bo )) throw new Api\Exception\WrongUserinput ( lang ( 'Initialization of mail failed. Please use the Wizard to cope with the problem.' ));
2014-07-18 19:18:29 +02:00
//error_log(__METHOD__.__LINE__.function_backtrace());
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) $starttime = microtime ( true );
2014-07-18 19:18:29 +02:00
$this -> mail_bo -> restoreSessionData ();
$sessionFolder = $this -> mail_bo -> sessionData [ 'mailbox' ];
if ( $this -> mail_bo -> folderExists ( $sessionFolder ))
{
$this -> mail_bo -> reopen ( $sessionFolder ); // needed to fetch full set of capabilities
}
else
{
$sessionFolder = $this -> mail_bo -> sessionData [ 'mailbox' ] = 'INBOX' ;
}
//error_log(__METHOD__.__LINE__.' SessionFolder:'.$sessionFolder.' isToSchema:'.$toSchema);
if ( ! is_array ( $content ))
{
$content = array (
2016-05-03 21:17:44 +02:00
self :: $nm_index => Api\Cache :: getSession ( 'mail' , 'index' ),
2014-07-18 19:18:29 +02:00
);
if ( ! is_array ( $content [ self :: $nm_index ]))
{
2016-04-13 01:45:36 +02:00
// These only set on first load
2014-07-18 19:18:29 +02:00
$content [ self :: $nm_index ] = array (
'filter' => 'any' , // filter is used to choose the mailbox
'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' => 'DESC' , // IO direction of the sort: 'ASC' or 'DESC'
2023-04-03 16:04:40 +02:00
'no_columnselection' => false
2014-07-18 19:18:29 +02:00
);
}
2024-09-02 14:11:16 +02:00
if ( Api\Header\UserAgent :: mobile ())
{
$content [ self :: $nm_index ][ 'header_row' ] = 'mail.index.header_right' ;
}
2014-07-18 19:18:29 +02:00
}
2014-07-28 23:21:23 +02:00
2016-04-13 01:45:36 +02:00
// These must always be set, even if $content is an array
$content [ self :: $nm_index ][ 'cat_is_select' ] = true ; // Category select is just a normal selectbox
2016-04-26 12:13:59 +02:00
$content [ self :: $nm_index ][ 'no_filter2' ] = false ; // Disable second filter
2016-06-09 15:46:51 +02:00
$content [ self :: $nm_index ][ 'actions' ] = self :: get_actions ();
2016-04-13 01:45:36 +02:00
$content [ self :: $nm_index ][ 'row_id' ] = 'row_id' ; // is a concatenation of trim($GLOBALS['egw_info']['user']['account_id']):profileID:base64_encode(FOLDERNAME):uid
$content [ self :: $nm_index ][ 'placeholder_actions' ] = array ( 'composeasnew' );
2015-06-01 21:18:15 +02:00
$content [ self :: $nm_index ][ 'get_rows' ] = 'mail_ui::get_rows' ;
2014-07-28 23:21:23 +02:00
$content [ self :: $nm_index ][ 'num_rows' ] = 0 ; // Do not send any rows with initial request
2022-07-29 13:26:58 +02:00
$content [ self :: $nm_index ][ 'default_cols' ] = 'avatar,status,attachments,subject,address,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
2014-07-18 19:18:29 +02:00
$content [ self :: $nm_index ][ 'csv_fields' ] = false ;
if ( $msg )
{
$content [ 'msg' ] = $msg ;
}
else
{
unset ( $msg );
unset ( $content [ 'msg' ]);
}
2014-08-05 10:51:26 +02:00
// call getQuotaRoot asynchronously in getRows by initiating a client Server roundtrip
$quota = false ; //$this->mail_bo->getQuotaRoot();
2014-07-18 19:18:29 +02:00
if ( $quota !== false && $quota [ 'limit' ] != 'NOT SET' ) {
$quotainfo = $this -> quotaDisplay ( $quota [ 'usage' ], $quota [ 'limit' ]);
$content [ self :: $nm_index ][ 'quota' ] = $sel_options [ self :: $nm_index ][ 'quota' ] = $quotainfo [ 'text' ];
$content [ self :: $nm_index ][ 'quotainpercent' ] = $sel_options [ self :: $nm_index ][ 'quotainpercent' ] = ( string ) $quotainfo [ 'percent' ];
$content [ self :: $nm_index ][ 'quotaclass' ] = $sel_options [ self :: $nm_index ][ 'quotaclass' ] = $quotainfo [ 'class' ];
$content [ self :: $nm_index ][ 'quotanotsupported' ] = $sel_options [ self :: $nm_index ][ 'quotanotsupported' ] = " " ;
} else {
$content [ self :: $nm_index ][ 'quota' ] = $sel_options [ self :: $nm_index ][ 'quota' ] = lang ( " Quota not provided by server " );
$content [ self :: $nm_index ][ 'quotaclass' ] = $sel_options [ self :: $nm_index ][ 'quotaclass' ] = " mail_DisplayNone " ;
$content [ self :: $nm_index ][ 'quotanotsupported' ] = $sel_options [ self :: $nm_index ][ 'quotanotsupported' ] = " mail_DisplayNone " ;
}
2017-08-21 10:59:02 +02:00
2014-07-18 19:18:29 +02:00
//$zstarttime = microtime (true);
2015-08-25 11:36:43 +02:00
$sel_options [ self :: $nm_index ][ 'foldertree' ] = $this -> mail_tree -> getInitialIndexTree ( null , $this -> mail_bo -> profileID , null , ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ], ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ]);
2014-07-18 19:18:29 +02:00
//$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' );
// since we are connected,(and selected the folder) we check for capabilities SUPPORTS_KEYWORDS to eventually add the keyword filters
if ( $this -> mail_bo -> icServer -> hasCapability ( 'SUPPORTS_KEYWORDS' ))
{
$this -> statusTypes = array_merge ( $this -> statusTypes , array (
'keyword1' => 'important' , //lang('important'),
'keyword2' => 'job' , //lang('job'),
'keyword3' => 'personal' , //lang('personal'),
'keyword4' => 'to do' , //lang('to do'),
'keyword5' => 'later' , //lang('later'),
));
}
else
{
$keywords = array ( 'keyword1' , 'keyword2' , 'keyword3' , 'keyword4' , 'keyword5' );
foreach ( $keywords as & $k )
{
if ( array_key_exists ( $k , $this -> statusTypes )) unset ( $this -> statusTypes [ $k ]);
}
}
2013-02-12 18:48:04 +01:00
2014-07-18 19:18:29 +02:00
if ( ! isset ( $content [ self :: $nm_index ][ 'foldertree' ])) $content [ self :: $nm_index ][ 'foldertree' ] = $this -> mail_bo -> profileID . self :: $delimiter . 'INBOX' ;
if ( ! isset ( $content [ self :: $nm_index ][ 'selectedFolder' ])) $content [ self :: $nm_index ][ 'selectedFolder' ] = $this -> mail_bo -> profileID . self :: $delimiter . 'INBOX' ;
$content [ self :: $nm_index ][ 'foldertree' ] = $content [ self :: $nm_index ][ 'selectedFolder' ];
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $supportsORinQuery ) || ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ]))
2014-07-18 19:18:29 +02:00
{
2016-05-03 21:17:44 +02:00
Mail :: $supportsORinQuery = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'supportsORinQuery' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), 60 * 60 * 10 );
2016-03-28 20:51:38 +02:00
if ( ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])) Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] = true ;
2014-07-18 19:18:29 +02:00
}
2016-03-28 20:51:38 +02:00
if ( ! Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])
2016-03-24 11:38:35 +01:00
{
unset ( $this -> searchTypes [ 'quick' ]);
unset ( $this -> searchTypes [ 'quickwithcc' ]);
}
2016-02-18 16:46:02 +01:00
$sel_options [ 'cat_id' ] = $this -> searchTypes ;
2016-03-24 11:50:05 +01:00
//error_log(__METHOD__.__LINE__.array2string($sel_options['cat_id']));
//error_log(__METHOD__.__LINE__.array2string($GLOBALS['egw_info']['user']['preferences']['mail']['ActiveSearchType']));
2016-03-24 11:38:35 +01:00
$content [ self :: $nm_index ][ 'cat_id' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveSearchType' ];
2014-07-18 19:18:29 +02:00
$sel_options [ 'filter' ] = $this -> statusTypes ;
2016-07-15 09:57:18 +02:00
$sel_options [ 'filter2' ] = array ( '' => lang ( 'No Sneak Preview in list' ), 1 => lang ( 'Sneak Preview in list' ));
2016-02-19 13:23:06 +01:00
$content [ self :: $nm_index ][ 'filter2' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ShowDetails' ];
2014-07-18 19:18:29 +02:00
2016-05-03 21:17:44 +02:00
$etpl = new Etemplate ( 'mail.index' );
2016-04-12 14:53:50 +02:00
//apply infolog_filter_change javascript method (hide/show of date filter form) over onchange filter
$content [ self :: $nm_index ][ 'cat_id_onchange' ] = " app.mail.mail_searchtype_change() " ;
2016-06-09 15:46:51 +02:00
// set the actions on tree
$etpl -> setElementAttribute ( self :: $nm_index . '[foldertree]' , 'actions' , $this -> get_tree_actions ());
2013-12-17 16:21:36 +01:00
2014-07-18 19:18:29 +02:00
// sending preview toolbar actions
2021-10-07 10:14:08 +02:00
if ( ! empty ( $content [ 'mailSplitter' ])) $etpl -> setElementAttribute ( 'mailPreview[toolbar]' , 'actions' , $this -> get_toolbar_actions ());
2016-03-09 13:31:55 +01:00
2016-03-01 18:00:28 +01:00
// We need to send toolbar actions to client-side because view template needs them
2016-05-03 21:17:44 +02:00
if ( Api\Header\UserAgent :: mobile ()) $sel_options [ 'toolbar' ] = $this -> get_toolbar_actions ();
2016-03-09 13:31:55 +01:00
2016-02-19 13:23:06 +01:00
//we use the category "filter" option as specifier where we want to search (quick, subject, from, to, etc. ....)
2016-03-24 16:16:10 +01:00
if ( empty ( $content [ self :: $nm_index ][ 'cat_id' ]) || empty ( $content [ self :: $nm_index ][ 'search' ]))
{
2016-03-28 20:51:38 +02:00
$content [ self :: $nm_index ][ 'cat_id' ] = ( $content [ self :: $nm_index ][ 'cat_id' ] ? ( ! Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] && ( $content [ self :: $nm_index ][ 'cat_id' ] == 'quick' || $content [ self :: $nm_index ][ 'cat_id' ] == 'quickwithcc' ) ? 'subject' : $content [ self :: $nm_index ][ 'cat_id' ]) : ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] ? 'quick' : 'subject' ));
2016-03-24 16:16:10 +01:00
}
2023-06-21 16:45:23 +02:00
$content [ 'emailTag' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'emailTag' ] ? ? 'onlyname' ;
2014-07-18 19:18:29 +02:00
$readonlys = $preserv = array ();
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) Mail :: logRunTimes ( $starttime , null , '' , __METHOD__ . __LINE__ );
2014-07-18 19:18:29 +02:00
}
catch ( Exception $e )
{
2016-06-09 15:46:51 +02:00
// do not exit here. mail-tree should be build. if we exit here, we never get there.
2023-11-21 14:56:41 +01:00
_egw_log_exception ( $e );
2016-06-14 10:50:04 +02:00
if ( isset ( $this -> mail_bo ))
2016-06-09 15:46:51 +02:00
{
2016-06-14 10:50:04 +02:00
if ( empty ( $etpl ))
{
$sel_options [ self :: $nm_index ][ 'foldertree' ] = $this -> mail_tree -> getInitialIndexTree ( null , $this -> mail_bo -> profileID , null , ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ], ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ]);
$etpl = new Etemplate ( 'mail.index' );
}
$etpl -> setElementAttribute ( self :: $nm_index . '[foldertree]' , 'actions' , $this -> get_tree_actions ( false ));
2016-06-09 15:46:51 +02:00
}
$readonlys = $preserv = array ();
if ( empty ( $content )) $content = array ();
2016-06-14 10:50:04 +02:00
self :: callWizard ( $e -> getMessage () . ( $e -> details ? ', ' . $e -> details : '' ),( isset ( $this -> mail_bo ) ? false : true ), 'error' , false );
2016-06-07 15:25:33 +02:00
//return false;
2014-07-18 19:18:29 +02:00
}
2017-06-28 12:09:21 +02:00
switch ( $this -> mail_bo -> mailPreferences [ 'previewPane' ])
2017-03-23 17:28:20 +01:00
{
2017-06-28 12:09:21 +02:00
case " 1 " :// preference used to be '1' , now 'hide'
case " hide " :
$etpl -> setElementAttribute ( 'splitter' , 'template' , 'mail.index.nosplitter' );
break ;
case " vertical " :
$etpl -> setElementAttribute ( 'mailSplitter' , 'orientation' , 'v' );
break ;
2023-06-02 11:38:54 +02:00
case " allColumns " :
$etpl -> setElementAttribute ( 'mailSplitter' , 'orientation' , 'v' );
$etpl -> setElementAttribute ( 'nm' , 'template' , 'mail.index.rows.horizental' );
break ;
2017-06-28 12:09:21 +02:00
case " expand " :
case " fixed " :
$etpl -> setElementAttribute ( 'mailSplitter' , 'orientation' , 'h' );
2022-10-12 12:49:41 +02:00
if ( ! Api\Header\UserAgent :: mobile ()) $etpl -> setElementAttribute ( 'nm' , 'template' , 'mail.index.rows.horizental' );
2017-06-28 12:09:21 +02:00
break ;
2017-08-24 12:14:06 +02:00
default :
$etpl -> setElementAttribute ( 'mailSplitter' , 'orientation' , 'v' );
2017-03-23 17:28:20 +01:00
}
2020-07-09 11:54:52 +02:00
// send configured image proxy to client-side
$content [ 'image_proxy' ] = self :: image_proxy ();
2021-04-26 14:18:57 +02:00
$content [ 'no_vfs' ] = ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'filemanager' ];
2013-02-08 20:11:44 +01:00
return $etpl -> exec ( 'mail.mail_ui.index' , $content , $sel_options , $readonlys , $preserv );
}
2016-06-09 15:46:51 +02:00
/**
* Get tree actions / context menu for tree
*
* Changes here , may require to log out , as $content [ self :: $nm_index ] get stored in session !
* @ param { boolean } $imap_actions set to false if you want to avoid to talk to the imap - server
* @ return array
*/
function get_tree_actions ( $imap_actions = true )
{
// Start at 2 so auto-added copy+paste actions show up as second group
// Needed because there's no 'select all' action to push things down
$group = 1 ;
// Set tree actions
$tree_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 (
'icon' => 'cancel' ,
'caption' => 'Cancel' ,
'acceptedTypes' => 'mail' ,
'type' => 'drop' ,
),
'drop_move_folder' => array (
'caption' => 'Move folder' ,
'hideOnDisabled' => true ,
'type' => 'drop' ,
'acceptedTypes' => 'mailFolder' ,
'onExecute' => 'javaScript:app.mail.mail_MoveFolder'
),
// Tree does support this one
'add' => array (
'caption' => 'Add Folder' ,
'onExecute' => 'javaScript:app.mail.mail_AddFolder' ,
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'group' => $group ,
),
'edit' => array (
'caption' => 'Rename Folder' ,
'onExecute' => 'javaScript:app.mail.mail_RenameFolder' ,
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'group' => $group ,
),
'move' => array (
'caption' => 'Move Folder' ,
'type' => 'drag' ,
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'dragType' => array ( 'mailFolder' ),
'group' => $group ,
),
'delete' => array (
'caption' => 'Delete Folder' ,
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'onExecute' => 'javaScript:app.mail.mail_DeleteFolder' ,
'group' => $group ,
),
2019-05-14 22:08:36 +02:00
'readall' => array (
'group' => $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'mark all as read' ),
'color' => 'red' ,
2019-10-01 11:04:27 +02:00
'icon' => 'kmmsgread' ,
2019-05-14 22:08:36 +02:00
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'hint' => 'mark all messages in folder as read' ,
'toolbarDefault' => false
),
2016-06-09 15:46:51 +02:00
'subscribe' => array (
'caption' => 'Subscribe folder ...' ,
//'icon' => 'configure',
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'onExecute' => 'javaScript:app.mail.edit_subscribe' ,
'group' => $group
),
'unsubscribe' => array (
'caption' => 'Unsubscribe folder' ,
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'onExecute' => 'javaScript:app.mail.unsubscribe_folder' ,
'group' => $group ,
),
'foldermanagement' => array (
'caption' => 'Folder Management ...' ,
2016-06-16 16:39:17 +02:00
'icon' => 'folder_management' ,
2016-06-09 15:46:51 +02:00
'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect' ,
'onExecute' => 'javaScript:app.mail.folderManagement' ,
'group' => $group ,
'hideOnMobile' => true
),
'sieve' => array (
'caption' => 'Mail filter' ,
'onExecute' => 'javaScript:app.mail.edit_sieve' ,
'enabled' => 'javaScript:app.mail.sieve_enabled' ,
'icon' => 'mail/filter' , // funnel
'hideOnMobile' => true
),
'vacation' => array (
'caption' => 'Vacation notice' ,
'icon' => 'mail/navbar' , // mail as in admin
'onExecute' => 'javaScript:app.mail.edit_vacation' ,
'enabled' => 'javaScript:app.mail.sieve_enabled' ,
),
'edit_account' => array (
'caption' => 'Edit account ...' ,
'icon' => 'configure' ,
'onExecute' => 'javaScript:app.mail.edit_account' ,
),
'edit_acl' => array (
'caption' => 'Edit folder ACL ...' ,
'icon' => 'lock' ,
'enabled' => 'javaScript:app.mail.acl_enabled' ,
'onExecute' => 'javaScript:app.mail.edit_acl' ,
),
2020-07-06 15:22:04 +02:00
'predefined-addresses' => array (
'caption' => 'Set predefined values for compose...' ,
'onExecute' => 'javaScript:app.mail.set_predefined_addresses' ,
'icon' => 'edit' ,
)
2016-06-09 15:46:51 +02:00
);
// the preference prefaskformove controls actually if there is a popup on target or not
// if there are multiple options there is a popup on target, 0 for prefaskformove means
// that only move is available; 1 stands for move and cancel; 2 (should be the default if
// not set); so we are assuming this, when not set
if ( isset ( $this -> mail_bo -> mailPreferences [ 'prefaskformove' ]))
{
switch ( $this -> mail_bo -> mailPreferences [ 'prefaskformove' ])
{
case 0 :
unset ( $tree_actions [ 'drop_copy_mail' ]);
unset ( $tree_actions [ 'drop_cancel' ]);
break ;
case 1 :
unset ( $tree_actions [ 'drop_copy_mail' ]);
break ;
default :
// everything is fine
}
}
//error_log(__METHOD__.__LINE__.' showAllFoldersInFolderPane:'.$this->mail_bo->mailPreferences['showAllFoldersInFolderPane'].'/'.$GLOBALS['egw_info']['user']['preferences']['mail']['showAllFoldersInFolderPane']);
if ( $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ])
{
unset ( $tree_actions [ 'subscribe' ]);
unset ( $tree_actions [ 'unsubscribe' ]);
}
++ $group ; // put delete in own group
switch ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'deleteOptions' ])
{
case 'move_to_trash' :
$tree_actions [ 'empty_trash' ] = array (
'caption' => 'empty trash' ,
'icon' => 'dhtmlxtree/MailFolderTrash' ,
'onExecute' => 'javaScript:app.mail.mail_emptyTrash' ,
'group' => $group ,
);
break ;
case 'mark_as_deleted' :
$tree_actions [ 'compress_folder' ] = array (
'caption' => 'compress folder' ,
'icon' => 'dhtmlxtree/MailFolderTrash' ,
'onExecute' => 'javaScript:app.mail.mail_compressFolder' ,
'group' => $group ,
);
break ;
}
$junkFolder = ( $imap_actions ? $this -> mail_bo -> getJunkFolder () : null );
//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 ,
);
}
$tree_actions [ 'sieve' ][ 'group' ] = $tree_actions [ 'vacation' ][ 'group' ] = ++ $group ; // new group for filter
2020-07-06 15:22:04 +02:00
$tree_actions [ 'edit_account' ][ 'group' ] = $tree_actions [ 'edit_acl' ][ 'group' ] =
$tree_actions [ 'predefined-addresses' ][ 'group' ] = ++ $group ;
2016-06-09 15:46:51 +02:00
// enforce global (group-specific) ACL
if ( ! mail_hooks :: access ( 'aclmanagement' ))
{
unset ( $tree_actions [ 'edit_acl' ]);
}
if ( ! mail_hooks :: access ( 'editfilterrules' ))
{
unset ( $tree_actions [ 'sieve' ]);
}
if ( ! mail_hooks :: access ( 'absentnotice' ))
{
unset ( $tree_actions [ 'vacation' ]);
}
if ( ! mail_hooks :: access ( 'managefolders' ))
{
unset ( $tree_actions [ 'add' ]);
unset ( $tree_actions [ 'move' ]);
unset ( $tree_actions [ 'delete' ]);
unset ( $tree_actions [ 'foldermanagement' ]);
// manage folders should not affect the ability to subscribe or unsubscribe
// to existing folders, it should only affect add/rename/move/delete
}
return $tree_actions ;
}
2013-12-20 17:23:45 +01:00
/**
* Ajax callback to subscribe / unsubscribe a Mailbox of an account
*
2014-02-07 17:29:20 +01:00
* @ param { int } $_acc_id profile Id of selected mailbox
* @ param { string } $_folderName name of mailbox needs to be subcribe or unsubscribed
* @ param { boolean } $_status set true for subscribe and false to unsubscribe
2013-12-20 17:23:45 +01:00
*/
public function ajax_foldersubscription ( $_acc_id , $_folderName , $_status )
{
2016-03-28 20:51:38 +02:00
//Change the Mail object to related profileId
2013-12-20 17:23:45 +01:00
$this -> changeProfile ( $_acc_id );
2016-06-24 10:05:21 +02:00
try {
$this -> mail_bo -> icServer -> subscribeMailbox ( $_folderName , $_status );
2013-12-20 17:23:45 +01:00
$this -> mail_bo -> resetFolderObjectCache ( $_acc_id );
2014-02-07 09:33:23 +01:00
$this -> ajax_reloadNode ( $_acc_id , ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ]);
2016-06-24 10:05:21 +02:00
} catch ( Horde_Imap_Client_Exception $ex ) {
error_log ( __METHOD__ . __LINE__ . " () " . lang ( 'Folder %1 %2 failed because of %3!' , $_folderName , $_status ? 'subscribed' : 'unsubscribed' , $ex ));
Framework :: message ( lang ( 'Folder %1 %2 failed!' , $_folderName , $_status ));
2013-12-20 17:23:45 +01:00
}
}
2013-02-20 13:04:29 +01:00
/**
* 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 .
*
2017-04-13 12:57:30 +02:00
* @ param string $_nodeID if of node whose children are requested
* @ param boolean $_subscribedOnly flag to tell whether to fetch all or only subscribed ( default )
2013-02-20 13:04:29 +01:00
*/
2014-02-07 09:33:23 +01:00
public function ajax_foldertree ( $_nodeID = null , $_subscribedOnly = null )
2013-02-20 13:04:29 +01:00
{
2013-02-20 17:27:10 +01:00
$nodeID = $_GET [ 'id' ];
2013-05-21 10:46:54 +02:00
if ( ! is_null ( $_nodeID )) $nodeID = $_nodeID ;
2014-02-07 09:33:23 +01:00
$subscribedOnly = ( bool )( ! is_null ( $_subscribedOnly ) ? $_subscribedOnly :! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ]);
2013-05-21 12:57:07 +02:00
$fetchCounters = ! is_null ( $_nodeID );
list ( $_profileID , $_folderName ) = explode ( self :: $delimiter , $nodeID , 2 );
2015-08-03 16:33:18 +02:00
2013-05-21 12:57:07 +02:00
if ( ! empty ( $_folderName )) $fetchCounters = true ;
2015-08-21 10:01:42 +02:00
2015-08-13 10:55:11 +02:00
// Check if it is called for refresh root
// then we need to reinitialized the index tree
if ( ! $nodeID && ! $_profileID )
{
$data = $this -> mail_tree -> getInitialIndexTree ( null , null , null , null , true , ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ]);
}
else
{
$data = $this -> mail_tree -> getTree ( $nodeID , $_profileID , 0 , false , $subscribedOnly , ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ]);
2015-08-21 10:01:42 +02:00
}
2013-05-21 10:46:54 +02:00
if ( ! is_null ( $_nodeID )) return $data ;
2016-05-03 21:17:44 +02:00
Etemplate\Widget\Tree :: send_quote_json ( $data );
2013-02-20 13:04:29 +01:00
}
2014-07-08 13:09:31 +02:00
2013-02-20 17:27:10 +01:00
/**
* findNode - helper function to return only a branch of the tree
*
2014-05-22 09:47:49 +02:00
* @ param array $_out out array ( to be searched )
* @ param string $_nodeID node to search for
* @ param boolean $childElements return node itself , or only its child items
2013-02-20 17:27:10 +01:00
* @ return array structured subtree
*/
static function findNode ( $_out , $_nodeID , $childElements = false )
{
foreach ( $_out [ 'item' ] as $node )
{
2013-05-28 11:32:23 +02:00
if ( strcmp ( $node [ 'id' ], $_nodeID ) === 0 )
2013-02-20 17:27:10 +01:00
{
2013-05-23 10:16:25 +02:00
//error_log(__METHOD__.__LINE__.':'.$_nodeID.'->'.$node['id']);
2013-02-20 17:27:10 +01:00
return ( $childElements ? $node [ 'item' ] : $node );
}
2013-05-21 10:46:54 +02:00
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 );
}
2013-02-20 17:27:10 +01:00
}
}
2017-05-31 17:38:09 +02:00
/**
* Method to execute spam actions
*
* @ param type $_action action id
2017-06-12 15:25:21 +02:00
* @ param type $_items
2017-05-31 17:38:09 +02:00
*/
2017-06-12 15:25:21 +02:00
public function ajax_spamAction ( $_action , $_items )
2017-05-31 17:38:09 +02:00
{
$msg = array ();
2017-06-08 14:27:46 +02:00
$refresh = false ;
2017-05-31 17:38:09 +02:00
$response = Api\Json\Response :: get ();
2017-06-12 15:25:21 +02:00
// Check active profile and change it if it's neccessary
if ( is_array ( $_items [ 0 ]))
2017-06-01 18:05:07 +02:00
{
2017-06-12 15:25:21 +02:00
$id_parts = self :: splitRowID ( $_items [ 0 ][ 'row_id' ]);
if ( $id_parts [ 'profileID' ] && $id_parts [ 'profileID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $id_parts [ 'profileID' ]);
}
2017-06-01 18:05:07 +02:00
}
2017-06-12 15:25:21 +02:00
2017-06-01 18:05:07 +02:00
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ();
// Ham folder
$ham = $this -> mail_bo -> profileID . self :: $delimiter . $this -> mail_bo -> icServer -> acc_folder_ham ;
// Junk folder
$junk = $this -> mail_bo -> profileID . self :: $delimiter . $this -> mail_bo -> getJunkFolder ();
// Inbox folder
$inbox = $this -> mail_bo -> profileID . self :: $delimiter . 'INBOX' ;
2017-06-12 15:25:21 +02:00
$messages = array ();
foreach ( $_items as & $params )
2017-05-31 17:38:09 +02:00
{
2017-06-12 15:25:21 +02:00
$id_parts = self :: splitRowID ( $params [ 'row_id' ]);
// Current Mailbox
$mailbox = $id_parts [ 'folder' ];
$messages [] = $params [ 'row_id' ];
2017-06-29 13:31:32 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'apps' ][ 'stylite' ] && $this -> mail_bo -> icServer -> acc_spam_api )
2017-06-12 15:25:21 +02:00
{
$params [ 'mailbody' ] = $this -> get_load_email_data ( $params [ 'uid' ], null , $mailbox );
}
2017-05-31 17:38:09 +02:00
}
switch ( $_action )
{
case 'spam' :
2017-06-12 15:25:21 +02:00
$msg [] = $this -> ajax_copyMessages ( $junk , array (
2017-06-01 18:05:07 +02:00
'all' => false ,
2017-06-12 15:25:21 +02:00
'msg' => $messages
), 'move' , null , true );
2017-06-08 14:27:46 +02:00
$refresh = true ;
2017-05-31 17:38:09 +02:00
break ;
case 'ham' :
2017-06-28 12:07:15 +02:00
if ( $this -> mail_bo -> icServer -> acc_folder_ham && empty ( $this -> mail_bo -> icServer -> acc_spam_api ))
2017-06-01 18:05:07 +02:00
{
2017-06-12 15:25:21 +02:00
$msg [] = $this -> ajax_copyMessages ( $ham , array (
2017-06-01 18:05:07 +02:00
'all' => false ,
2017-06-12 15:25:21 +02:00
'msg' => $messages
), 'copy' , null , true );
2017-06-01 18:05:07 +02:00
}
// Move mails to Inbox if they are in Junk folder
if ( $junk == $this -> mail_bo -> profileID . self :: $delimiter . $mailbox )
{
2017-06-12 15:25:21 +02:00
$msg [] = $this -> ajax_copyMessages ( $inbox , array (
2017-06-01 18:05:07 +02:00
'all' => false ,
2017-06-12 15:25:21 +02:00
'msg' => $messages
), 'move' , null , true );
2017-06-08 14:27:46 +02:00
$refresh = true ;
2017-06-01 18:05:07 +02:00
}
2017-05-31 17:38:09 +02:00
break ;
}
2017-06-28 10:24:59 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'apps' ][ 'stylite' ] && $this -> mail_bo -> icServer -> acc_spam_api )
2017-06-12 15:25:21 +02:00
{
2021-02-08 16:31:22 +01:00
if ( strpos ( $user = $this -> mail_bo -> icServer -> acc_imap_username , '@' ) === false )
{
if ( ! empty ( $this -> mail_bo -> icServer -> acc_domain ))
{
$user .= '@' . $this -> mail_bo -> icServer -> acc_domain ;
}
else
{
$user = $this -> mail_bo -> icServer -> ident_email ;
}
}
stylite_mail_spamtitan :: setActionItems ( $_action , $_items , $auth = [
'user' => $user ,
2017-06-12 15:25:21 +02:00
'userpwd' => $this -> mail_bo -> icServer -> acc_imap_password ,
2021-02-08 16:31:22 +01:00
'api_url' => $this -> mail_bo -> icServer -> acc_spam_api ,
'api_token' => $this -> mail_bo -> icServer -> acc_spam_password ,
]);
2018-04-23 17:37:40 +02:00
// sync aliases to SpamTitan when the first spam action in a session is used
if ( Api\Mail\Account :: read ( $this -> mail_bo -> profileID ) -> acc_smtp_type !== 'EGroupware\\Api\\Mail\\Smtp' &&
! Api\Cache :: getSession ( 'SpamTitian' , 'AliasesSynced-' . $this -> mail_bo -> icServer -> acc_id . '-' . $this -> mail_bo -> icServer -> acc_imap_username ))
{
$data = Api\Mail\Account :: read ( $this -> mail_bo -> profileID ) -> smtpServer () -> getUserData ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]);
if (( $m = stylite_mail_spamtitan :: setActionItems ( 'sync_aliases' ,
2021-02-08 16:31:22 +01:00
array ( array_merge (( array ) $data [ 'mailLocalAddress' ], ( array ) $data [ 'mailAlternateAddress' ])), $auth )))
2018-04-23 17:37:40 +02:00
{
$msg [] = $m ;
}
Api\Cache :: setSession ( 'SpamTitian' , 'AliasesSynced-' . $this -> mail_bo -> icServer -> acc_id . '-' . $this -> mail_bo -> icServer -> acc_imap_username , true );
}
2017-06-12 15:25:21 +02:00
}
2017-06-08 14:27:46 +02:00
if ( $refresh )
{
2017-06-12 15:25:21 +02:00
$response -> data ([ implode ( '\n' , $msg ), $messages ]);
2017-06-08 14:27:46 +02:00
}
else
{
$response -> apply ( 'egw.message' ,[ implode ( '\n' , $msg )]);
}
2017-05-31 17:38:09 +02:00
}
/**
* Build spam actions
*
* @ return array actions
*/
public function getSpamActions ()
{
$actions = array (
'spamfilter' => array (
2017-06-02 17:17:15 +02:00
'caption' => 'Spam' ,
2017-05-31 17:38:09 +02:00
'icon' => 'dhtmlxtree/MailFolderJunk' ,
2017-06-12 15:25:21 +02:00
'allowOnMultiple' => true ,
2017-05-31 17:38:09 +02:00
'children' => array (
'spam' => array (
'caption' => 'Report as Spam' ,
'icon' => 'dhtmlxtree/MailFolderJunk' ,
'onExecute' => 'javaScript:app.mail.spam_actions' ,
2017-06-02 17:17:15 +02:00
'hint' => 'Report this email content as Spam - spam solutions like spamTitan will learn' ,
2017-06-12 15:25:21 +02:00
'allowOnMultiple' => true
2017-05-31 17:38:09 +02:00
),
'ham' => array (
2017-06-02 17:17:15 +02:00
'caption' => 'Report as Ham' ,
2017-06-09 16:06:03 +02:00
'icon' => 'dhtmlxtree/MailFolderHam' ,
2017-05-31 17:38:09 +02:00
'onExecute' => 'javaScript:app.mail.spam_actions' ,
2017-06-02 17:17:15 +02:00
'hint' => 'Report this email content as Ham (not spam) - spam solutions like spamTitan will learn' ,
2017-06-12 15:25:21 +02:00
'allowOnMultiple' => true
2017-05-31 17:38:09 +02:00
)
)
)
);
$account = Mail\Account :: read ( $this -> mail_bo -> profileID );
// spamTitan actions
2022-09-08 18:42:46 +02:00
if ( $account -> acc_spam_api && class_exists ( 'stylite_mail_spamtitan' ))
2017-05-31 17:38:09 +02:00
{
$actions [ 'spamfilter' ][ 'children' ] = array_merge ( $actions [ 'spamfilter' ][ 'children' ], stylite_mail_spamtitan :: getActions ());
}
return $actions ;
}
2015-08-21 10:01:42 +02:00
2013-02-08 20:11:44 +01:00
/**
* Get actions / context menu for index
*
2013-08-21 12:47:20 +02:00
* Changes here , require to log out , as $content [ self :: $nm_index ] get stored in session !
2013-02-08 20:11:44 +01:00
* @ return array see nextmatch_widget :: egw_actions ()
*/
2014-07-16 18:34:15 +02:00
private function get_actions ()
2013-02-08 20:11:44 +01:00
{
2014-07-16 18:34:15 +02:00
static $accArray = array (); // buffer identity names on single request
2013-02-08 20:11:44 +01:00
// 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
$lastFolderUsedForMove = null ;
2014-05-20 12:02:21 +02:00
$moveactions = array ();
2016-04-29 13:23:05 +02:00
$archiveFolder = $this -> mail_bo -> getArchiveFolder ();
2016-05-03 21:17:44 +02:00
$lastFoldersUsedForMoveCont = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'lastFolderUsedForMove' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), $expiration = 60 * 60 * 1 );
2014-05-20 12:02:21 +02:00
//error_log(__METHOD__.__LINE__." StoredFolders->".array2string($lastFoldersUsedForMoveCont));
2014-05-20 13:47:18 +02:00
//error_log(__METHOD__.__LINE__.' ProfileId:'.$this->mail_bo->profileID." StoredFolders->(".count($lastFoldersUsedForMoveCont[$this->mail_bo->profileID]).") ".array2string($lastFoldersUsedForMoveCont[$this->mail_bo->profileID]));
2014-05-20 12:02:21 +02:00
if ( is_null ( $accArray ))
2013-02-08 20:11:44 +01:00
{
2016-03-28 20:51:38 +02:00
foreach ( Mail\Account :: search ( $only_current_user = true , false ) as $acc_id => $accountObj )
2013-02-08 20:11:44 +01:00
{
2014-05-20 12:02:21 +02:00
//error_log(__METHOD__.__LINE__.array2string($accountObj));
2014-07-08 13:09:31 +02:00
if ( ! $accountObj -> is_imap ())
2014-05-20 12:02:21 +02:00
{
// not to be used for IMAP Foldertree, as there is no Imap host
continue ;
}
2016-03-28 20:51:38 +02:00
$identity_name = Mail\Account :: identity_name ( $accountObj , true , $GLOBALS [ 'egw_info' ][ 'user' ][ 'acount_id' ]);
2014-05-20 12:02:21 +02:00
$accArray [ $acc_id ] = str_replace ( array ( '<' , '>' ), array ( '[' , ']' ), $identity_name ); // as angle brackets are quoted, display in Javascript messages when used is ugly, so use square brackets instead
2013-02-08 20:11:44 +01:00
}
}
2014-05-20 12:02:21 +02:00
if ( ! is_array ( $lastFoldersUsedForMoveCont )) $lastFoldersUsedForMoveCont = array ();
2016-05-03 21:17:44 +02:00
foreach ( array_keys ( $lastFoldersUsedForMoveCont ) as $pid )
2014-05-20 12:02:21 +02:00
{
if ( $this -> mail_bo -> profileID == $pid && isset ( $lastFoldersUsedForMoveCont [ $this -> mail_bo -> profileID ]))
{
$_folder = $this -> mail_bo -> icServer -> getCurrentMailbox ();
//error_log(__METHOD__.__LINE__.' '.$_folder."<->".$lastFoldersUsedForMoveCont[$this->mail_bo->profileID].function_backtrace());
$counter = 1 ;
foreach ( $lastFoldersUsedForMoveCont [ $this -> mail_bo -> profileID ] as $i => $lastFolderUsedForMoveCont )
{
$moveaction = 'move_' ;
if ( $_folder != $i )
{
$moveaction .= $lastFolderUsedForMoveCont ;
2016-04-29 13:23:05 +02:00
//error_log(__METHOD__.__LINE__.'#'.$moveaction);
//error_log(__METHOD__.__LINE__.'#'.$currentArchiveActionKey);
2015-08-25 10:11:27 +02:00
if ( $this -> mail_bo -> folderExists ( $i )) // only 10 entries per mailaccount.Control this on setting the buffered folders
2014-05-20 12:02:21 +02:00
{
$fS [ 'profileID' ] = $this -> mail_bo -> profileID ;
$fS [ 'profileName' ] = $accArray [ $this -> mail_bo -> profileID ];
$fS [ 'shortDisplayName' ] = $i ;
$moveactions [ $moveaction ] = $fS ;
$counter ++ ;
}
else
{
unset ( $lastFoldersUsedForMoveCont [ $this -> mail_bo -> profileID ][ $i ]);
}
//error_log(array2string($moveactions[$moveaction]));
}
}
}
elseif ( $this -> mail_bo -> profileID != $pid && isset ( $lastFoldersUsedForMoveCont [ $pid ]) && ! empty ( $lastFoldersUsedForMoveCont [ $pid ]))
{
$counter = 1 ;
foreach ( $lastFoldersUsedForMoveCont [ $pid ] as $i => $lastFolderUsedForMoveCont )
{
//error_log(__METHOD__.__LINE__."$i => $lastFolderUsedForMoveCont");
2015-08-25 10:11:27 +02:00
if ( ! empty ( $lastFolderUsedForMoveCont )) // only 10 entries per mailaccount.Control this on setting the buffered folders
2014-05-20 12:02:21 +02:00
{
2016-04-29 15:19:32 +02:00
$moveaction = 'move_' . $lastFolderUsedForMoveCont ;
//error_log(__METHOD__.__LINE__.'#'.$moveaction);
2014-05-20 12:02:21 +02:00
$fS = array ();
$fS [ 'profileID' ] = $pid ;
$fS [ 'profileName' ] = $accArray [ $pid ];
$fS [ 'shortDisplayName' ] = $i ;
$moveactions [ $moveaction ] = $fS ;
$counter ++ ;
}
}
}
}
2016-05-03 21:17:44 +02:00
Api\Cache :: setCache ( Api\Cache :: INSTANCE , 'email' , 'lastFolderUsedForMove' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), $lastFoldersUsedForMoveCont , $expiration = 60 * 60 * 1 );
2014-07-16 18:34:15 +02:00
$group = 0 ;
2013-02-08 20:11:44 +01:00
$actions = array (
'open' => array (
'caption' => lang ( 'Open' ),
2013-10-10 13:44:01 +02:00
'icon' => 'view' ,
2013-02-08 20:11:44 +01:00
'group' => ++ $group ,
2022-07-25 11:15:48 +02:00
'onExecute' => Api\Header\UserAgent :: mobile () ? 'javaScript:app.mail.mobileView' : 'javaScript:app.mail.mail_open' ,
2013-02-08 20:11:44 +01:00
'allowOnMultiple' => false ,
'default' => true ,
2016-05-25 16:44:23 +02:00
'mobileViewTemplate' => 'view?' . filemtime ( Api\Etemplate\Widget\Template :: rel2path ( '/mail/templates/mobile/view.xet' ))
2013-02-08 20:11:44 +01:00
),
2024-09-02 14:11:16 +02:00
'replies' => array (
2013-02-08 20:11:44 +01:00
'caption' => 'Reply' ,
'icon' => 'mail_reply' ,
'group' => ++ $group ,
2013-04-09 16:43:55 +02:00
'onExecute' => 'javaScript:app.mail.mail_compose' ,
2013-02-08 20:11:44 +01:00
'allowOnMultiple' => false ,
2024-09-02 14:11:16 +02:00
'children' => [
'reply' => [
'caption' => 'Reply' ,
'icon' => 'mail_reply' ,
'onExecute' => 'javaScript:app.mail.mail_compose' ,
'allowOnMultiple' => false ,
'toolbarDefault' => true ,
],
'reply_all' => [
'caption' => 'Reply All' ,
'icon' => 'mail_replyall' ,
'onExecute' => 'javaScript:app.mail.mail_compose' ,
'allowOnMultiple' => false ,
'shortcut' => array ( 'ctrl' => true , 'shift' => true , 'keyCode' => 65 , 'caption' => 'Ctrl + Shift + A' ),
'toolbarDefault' => true ,
],
'reply_attachments' => [
'caption' => 'Reply With Attachments' ,
'icon' => 'attach' ,
'onExecute' => 'javaScript:app.mail.mail_compose' ,
'allowOnMultiple' => false ,
],
],
2013-02-08 20:11:44 +01:00
),
'forward' => array (
'caption' => 'Forward' ,
'icon' => 'mail_forward' ,
'group' => $group ,
'children' => array (
'forwardinline' => array (
2014-02-13 12:30:05 +01:00
'caption' => 'Inline' ,
2013-02-08 20:11:44 +01:00
'icon' => 'mail_forward' ,
'group' => $group ,
2014-02-10 14:06:49 +01:00
'hint' => 'forward inline' ,
2013-04-09 16:43:55 +02:00
'onExecute' => 'javaScript:app.mail.mail_compose' ,
2013-02-08 20:11:44 +01:00
'allowOnMultiple' => false ,
2017-09-26 00:12:17 +02:00
'shortcut' => array ( 'ctrl' => true , 'keyCode' => 70 , 'caption' => 'Ctrl + F' ),
2014-02-10 16:47:27 +01:00
'toolbarDefault' => true
2013-02-08 20:11:44 +01:00
),
'forwardasattach' => array (
2014-02-13 12:30:05 +01:00
'caption' => 'Attachment' ,
2014-02-10 14:06:49 +01:00
'hint' => 'forward as attachment' ,
2016-03-18 18:15:55 +01:00
'icon' => 'mail_forward_attach' ,
2013-02-08 20:11:44 +01:00
'group' => $group ,
2013-04-09 16:43:55 +02:00
'onExecute' => 'javaScript:app.mail.mail_compose' ,
2013-02-08 20:11:44 +01:00
),
),
2016-03-09 13:31:55 +01:00
'hideOnMobile' => true
2013-02-08 20:11:44 +01:00
),
'composeasnew' => array (
2014-02-10 14:06:49 +01:00
'caption' => 'Compose' ,
2013-02-08 20:11:44 +01:00
'icon' => 'new' ,
2014-02-10 14:06:49 +01:00
'hint' => 'Compose as new' ,
2013-02-08 20:11:44 +01:00
'group' => $group ,
2013-04-09 16:43:55 +02:00
'onExecute' => 'javaScript:app.mail.mail_compose' ,
2013-02-08 20:11:44 +01:00
'allowOnMultiple' => false ,
2018-02-20 18:00:30 +01:00
),
'modifysubject' => array (
'caption' => 'Modify Subject' ,
'icon' => 'edit' ,
'hint' => 'Modify subject of this message' ,
'group' => $group ,
'onExecute' => 'javaScript:app.mail.modifyMessageSubjectDialog' ,
'allowOnMultiple' => false ,
2018-02-26 12:34:08 +01:00
'shortcut' => array ( 'ctrl' => true , 'keyCode' => 77 , 'caption' => 'Ctrl + M' ),
2014-05-20 12:02:21 +02:00
)
);
$macounter = 0 ;
if ( ! empty ( $moveactions ))
{
//error_log(__METHOD__.__LINE__.array2string($moveactions));
$children = array ();
$pID = 0 ;
foreach ( $moveactions as $moveaction => $lastFolderUsedForMove )
{
$group = ( $pID != $lastFolderUsedForMove [ 'profileID' ] && $macounter > 0 ? $group + 1 : $group );
//error_log(__METHOD__.__LINE__."#$pID != ".$lastFolderUsedForMove['profileID']."#".$macounter.'#'.$groupCounter.'#');
$children = array_merge ( $children ,
array (
$moveaction => array (
'caption' => ( ! empty ( $lastFolderUsedForMove [ 'profileName' ]) ? $lastFolderUsedForMove [ 'profileName' ] : '(' . $lastFolderUsedForMove [ 'profileID' ] . ')' ) . ': ' . ( isset ( $lastFolderUsedForMove [ 'shortDisplayName' ]) ? $lastFolderUsedForMove [ 'shortDisplayName' ] : '' ),
'icon' => 'move' ,
'group' => $group ,
'onExecute' => 'javaScript:app.mail.mail_move2folder' ,
'allowOnMultiple' => true ,
)
)
);
$pID = $lastFolderUsedForMove [ 'profileID' ];
$macounter ++ ;
}
2016-05-03 21:17:44 +02:00
$actions [ 'moveto' ] = array (
'caption' => lang ( 'Move selected to' ),
'icon' => 'move' ,
'group' => $group ,
'children' => $children ,
2014-05-20 12:02:21 +02:00
);
2016-04-29 13:23:05 +02:00
} else {
$group ++ ;
2014-05-20 12:02:21 +02:00
}
2017-06-02 17:17:15 +02:00
$spam_actions = $this -> getSpamActions ();
$group ++ ;
foreach ( $spam_actions as & $action )
{
$action [ 'group' ] = $group ;
}
2016-04-29 13:23:05 +02:00
//error_log(__METHOD__.__LINE__.$archiveFolder);
2016-05-03 21:17:44 +02:00
$actions [ 'move2' . $this -> mail_bo -> profileID . self :: $delimiter . $archiveFolder ] = array ( //toarchive
'caption' => 'Move to archive' ,
'hint' => 'move selected mails to archive' ,
2016-06-13 10:10:10 +02:00
'icon' => 'archive' ,
2016-05-03 21:17:44 +02:00
'group' => $group ++ ,
'enabled' => 'javaScript:app.mail.archivefolder_enabled' ,
//'hideOnDisabled' => true, // does not work as expected on message-list
'onExecute' => 'javaScript:app.mail.mail_move2folder' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: V , true , true ),
'allowOnMultiple' => true ,
'toolbarDefault' => false
);
$actions += array (
'infolog' => array (
'caption' => 'InfoLog' ,
'hint' => 'Save as InfoLog' ,
2019-08-05 10:59:26 +02:00
'icon' => 'infolog/navbar' ,
2016-05-03 21:17:44 +02:00
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.mail_integrate' ,
'popup' => Link :: get_registry ( 'infolog' , 'add_popup' ),
'allowOnMultiple' => false ,
'toolbarDefault' => true
),
'tracker' => array (
'caption' => 'Tracker' ,
'hint' => 'Save as ticket' ,
'group' => $group ,
2019-08-05 10:59:26 +02:00
'icon' => 'tracker/navbar' ,
2016-05-03 21:17:44 +02:00
'onExecute' => 'javaScript:app.mail.mail_integrate' ,
'popup' => Link :: get_registry ( 'tracker' , 'add_popup' ),
'mail_import' => Api\Hooks :: single ( array ( 'location' => 'mail_import' ), 'tracker' ),
'allowOnMultiple' => false ,
),
'calendar' => array (
'caption' => 'Calendar' ,
'hint' => 'Save as Calendar' ,
2019-08-05 10:59:26 +02:00
'icon' => 'calendar/navbar' ,
2016-05-03 21:17:44 +02:00
'group' => $group ,
'onExecute' => 'javaScript:app.mail.mail_integrate' ,
'popup' => Link :: get_registry ( 'calendar' , 'add_popup' ),
'allowOnMultiple' => false ,
'toolbarDefault' => true
),
'print' => array (
'caption' => 'Print' ,
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.mail_print' ,
'allowOnMultiple' => false ,
'hideOnMobile' => true
),
'save' => array (
'caption' => 'Save' ,
'group' => $group ,
'icon' => 'fileexport' ,
'children' => array (
'save2disk' => array (
'caption' => 'Save to disk' ,
'hint' => 'Save message to disk' ,
'group' => $group ,
'icon' => 'fileexport' ,
'onExecute' => 'javaScript:app.mail.mail_save' ,
2017-05-09 15:09:00 +02:00
'allowOnMultiple' => true ,
2016-05-03 21:17:44 +02:00
'hideOnMobile' => true
),
'save2filemanager' => array (
'caption' => 'Filemanager' ,
2017-02-27 19:14:31 +01:00
'hint' => 'Save to filemanager' ,
2016-05-03 21:17:44 +02:00
'group' => $group ,
2019-08-05 10:59:26 +02:00
'icon' => 'filemanager/navbar' ,
2016-05-03 21:17:44 +02:00
'onExecute' => 'javaScript:app.mail.mail_save2fm' ,
2017-05-09 15:09:00 +02:00
'allowOnMultiple' => true ,
2013-05-13 16:42:42 +02:00
),
2013-02-08 20:11:44 +01:00
),
2016-05-03 21:17:44 +02:00
'hideOnMobile' => true
),
'view' => array (
'caption' => 'View' ,
'group' => $group ,
'icon' => 'kmmsgread' ,
'children' => array (
'header' => array (
'caption' => 'Header' ,
'hint' => 'View header lines' ,
'group' => $group ,
'icon' => 'kmmsgread' ,
'onExecute' => 'javaScript:app.mail.mail_header' ,
'allowOnMultiple' => false ,
),
'mailsource' => array (
'caption' => 'Source' ,
'hint' => 'View full Mail Source' ,
'group' => $group ,
'icon' => 'source' ,
'onExecute' => 'javaScript:app.mail.mail_mailsource' ,
'allowOnMultiple' => false ,
),
'openastext' => array (
'caption' => lang ( 'Text mode' ),
'hint' => 'Open in Text mode' ,
'group' => ++ $group ,
'icon' => 'textmode' ,
'onExecute' => 'javaScript:app.mail.mail_openAsText' ,
'allowOnMultiple' => false ,
),
'openashtml' => array (
'caption' => lang ( 'HTML mode' ),
'hint' => 'Open in HTML mode' ,
'group' => $group ,
'icon' => 'htmlmode' ,
'onExecute' => 'javaScript:app.mail.mail_openAsHtml' ,
'allowOnMultiple' => false ,
2013-02-08 20:11:44 +01:00
),
2014-05-20 12:02:21 +02:00
),
2016-05-03 21:17:44 +02:00
'hideOnMobile' => true
),
'mark' => array (
'caption' => 'Set / Remove Flags' ,
2019-10-01 11:04:27 +02:00
'icon' => 'kmmsgread' ,
2016-05-03 21:17:44 +02:00
'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 / Remove Labels' ,
'icon' => 'tag_message' ,
'group' => ++ $group ,
// note this one is NOT a real CAPABILITY reported by the server, but added by selectMailbox
'enabled' => $this -> mail_bo -> icServer -> hasCapability ( 'SUPPORTS_KEYWORDS' ),
'hideOnDisabled' => true ,
'children' => array (
'unlabel' => array (
'group' => ++ $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'remove all' ),
'icon' => 'tag_message' ,
2016-05-03 21:17:44 +02:00
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: _0 , true , true ),
),
'label1' => array (
'group' => ++ $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'important' ),
'color' => '#ff0000' ,
2016-05-03 21:17:44 +02:00
'icon' => 'mail_label1' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: _1 , true , true ),
),
'label2' => array (
'group' => $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'job' ),
'color' => '#ff8000' ,
2016-05-03 21:17:44 +02:00
'icon' => 'mail_label2' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: _2 , true , true ),
),
'label3' => array (
'group' => $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'personal' ),
'color' => '#008000' ,
2016-05-03 21:17:44 +02:00
'icon' => 'mail_label3' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: _3 , true , true ),
),
'label4' => array (
'group' => $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'to do' ),
'color' => '#0000ff' ,
2016-05-03 21:17:44 +02:00
'icon' => 'mail_label4' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: _4 , true , true ),
),
'label5' => array (
'group' => $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'later' ),
'color' => '#8000ff' ,
2016-05-03 21:17:44 +02:00
'icon' => 'mail_label5' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: _5 , true , true ),
2013-02-08 20:11:44 +01:00
),
),
2016-05-03 21:17:44 +02:00
),
// modified icons from http://creativecommons.org/licenses/by-sa/3.0/
'flagged' => array (
'group' => ++ $group ,
'caption' => 'Flag / Unflag' ,
'icon' => 'unread_flagged_small' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'hint' => 'Flag or Unflag a mail' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: F , true , true ),
'toolbarDefault' => true
),
'read' => array (
'group' => $group ,
'caption' => 'Read / Unread' ,
2019-10-01 11:04:27 +02:00
'icon' => 'kmmsgread' ,
2016-05-03 21:17:44 +02:00
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'shortcut' => KeyManager :: shortcut ( KeyManager :: U , true , true ),
2013-12-06 11:35:39 +01:00
2016-05-03 21:17:44 +02:00
),
'readall' => array (
'group' => ++ $group ,
2024-07-16 20:37:30 +02:00
'caption' => lang ( 'mark all as read' ),
'color' => 'red' ,
2019-10-01 11:04:27 +02:00
'icon' => 'kmmsgread' ,
2016-05-03 21:17:44 +02:00
'onExecute' => 'javaScript:app.mail.mail_flag' ,
'hint' => 'mark all messages in folder as read' ,
'toolbarDefault' => false
),
'undelete' => array (
'group' => $group ,
'caption' => 'Undelete' ,
'icon' => 'revert' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
2013-02-08 20:11:44 +01:00
),
),
2016-05-03 21:17:44 +02:00
),
'delete' => array (
'caption' => 'Delete' ,
'hint' => $deleteOptions [ $this -> mail_bo -> mailPreferences [ 'deleteOptions' ]],
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.mail_delete' ,
'toolbarDefault' => true
),
'drag_mail' => array (
'dragType' => array ( 'mail' ),
'type' => 'drag' ,
//'onExecute' => 'javaScript:app.mail.mail_dragStart',
2013-04-12 12:35:40 +02:00
)
2013-02-08 20:11:44 +01:00
);
2014-05-20 12:02:21 +02:00
//error_log(__METHOD__.__LINE__.array2string(array_keys($actions)));
2013-02-08 20:11:44 +01:00
// 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' ]);
}
2015-06-03 10:44:44 +02:00
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'calendar' ]))
{
unset ( $actions [ 'calendar' ]);
}
2017-04-21 16:21:49 +02:00
// remove vfs actions if the user has no run access to filemanager
if ( ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'filemanager' ])
{
unset ( $actions [ 'save' ][ 'children' ][ 'save2filemanager' ]);
}
2017-05-31 17:38:09 +02:00
return array_merge ( $actions , $spam_actions );
2013-02-08 20:11:44 +01:00
}
/**
* Callback to fetch the rows for the nextmatch widget
*
2014-08-20 16:58:12 +02:00
* Function is static to not automatic call constructor in case profile is changed .
*
2013-02-08 20:11:44 +01:00
* @ param array $query
* @ param array & $rows
* @ param array & $readonlys
*/
2014-08-20 16:58:12 +02:00
public static function get_rows ( & $query , & $rows , & $readonlys )
2013-02-08 20:11:44 +01:00
{
2016-05-03 21:17:44 +02:00
unset ( $readonlys ); // not used, but required by function signature
2014-08-20 16:58:12 +02:00
// handle possible profile change in get_rows
if ( ! empty ( $query [ 'selectedFolder' ]))
2013-02-19 17:30:59 +01:00
{
2014-08-20 16:58:12 +02:00
list ( $_profileID , $folderName ) = explode ( self :: $delimiter , $query [ 'selectedFolder' ], 2 );
if ( is_numeric (( $_profileID )) && $_profileID != $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ])
2013-02-20 17:27:10 +01:00
{
2014-08-20 16:58:12 +02:00
try {
$mail_ui = new mail_ui ( false ); // do NOT run constructor, as we change profile anyway
$mail_ui -> changeProfile ( $_profileID );
$query [ 'actions' ] = $mail_ui -> get_actions ();
2014-05-09 14:43:57 +02:00
}
catch ( Exception $e )
{
2016-06-09 15:46:51 +02:00
unset ( $e );
2014-05-09 14:43:57 +02:00
$rows = array ();
return 0 ;
}
2014-08-20 16:58:12 +02:00
if ( empty ( $folderName )) $query [ 'selectedFolder' ] = $_profileID . self :: $delimiter . 'INBOX' ;
2013-02-20 17:27:10 +01:00
}
2014-08-20 16:58:12 +02:00
}
if ( ! isset ( $mail_ui ))
{
2016-06-09 15:46:51 +02:00
try
{
$mail_ui = new mail_ui ( true ); // run constructor for current profile
}
catch ( Exception $e )
{
unset ( $e );
$rows = array ();
return 0 ;
}
2014-08-20 16:58:12 +02:00
if ( empty ( $query [ 'selectedFolder' ])) $query [ 'selectedFolder' ] = $mail_ui -> mail_bo -> profileID . self :: $delimiter . 'INBOX' ;
}
2021-05-25 17:47:25 +02:00
// enable push notifications, if supported (and configured) by the server
2020-07-22 17:01:19 +02:00
if ( $mail_ui -> mail_bo -> icServer instanceof Api\Mail\Imap\PushIface &&
$mail_ui -> mail_bo -> icServer -> pushAvailable ())
{
2021-05-25 17:47:25 +02:00
Api\Json\Response :: get () -> call ( 'app.mail.disable_autorefresh' ,
$mail_ui -> mail_bo -> icServer -> enablePush ());
2020-08-11 15:52:12 +02:00
}
else
{
Api\Json\Response :: get () -> call ( 'app.mail.disable_autorefresh' , false );
2020-07-22 17:01:19 +02:00
}
2014-08-20 16:58:12 +02:00
//error_log(__METHOD__.__LINE__.' SelectedFolder:'.$query['selectedFolder'].' Start:'.$query['start'].' NumRows:'.$query['num_rows'].array2string($query['order']).'->'.array2string($query['sort']));
2016-03-28 20:51:38 +02:00
//Mail::$debugTimes=true;
if ( Mail :: $debugTimes ) $starttime = microtime ( true );
2014-08-20 16:58:12 +02:00
//$query['search'] is the phrase in the searchbox
$mail_ui -> mail_bo -> restoreSessionData ();
if ( isset ( $query [ 'selectedFolder' ])) $mail_ui -> mail_bo -> sessionData [ 'mailbox' ] = $query [ 'selectedFolder' ];
$sRToFetch = null ;
list ( $_profileID , $_folderName ) = explode ( self :: $delimiter , $query [ 'selectedFolder' ], 2 );
if ( strpos ( $_folderName , self :: $delimiter ) !== false )
{
list ( $app , $_profileID , $_folderName ) = explode ( self :: $delimiter , $_folderName , 3 );
unset ( $app );
2013-02-19 17:30:59 +01:00
}
//save selected Folder to sessionData (mailbox)->currentFolder
2014-08-20 16:58:12 +02:00
if ( isset ( $query [ 'selectedFolder' ])) $mail_ui -> mail_bo -> sessionData [ 'mailbox' ] = $_folderName ;
2013-12-10 16:59:54 +01:00
$toSchema = false ; //decides to select list schema with column to selected (if false fromaddress is default)
2014-08-20 16:58:12 +02:00
if ( $mail_ui -> mail_bo -> folderExists ( $_folderName ))
2013-12-10 16:59:54 +01:00
{
2014-08-20 16:58:12 +02:00
$toSchema = $mail_ui -> mail_bo -> isDraftFolder ( $_folderName , false ) || $mail_ui -> mail_bo -> isSentFolder ( $_folderName , false ) || $mail_ui -> mail_bo -> isTemplateFolder ( $_folderName , false );
2013-12-10 16:59:54 +01:00
}
2013-12-12 14:34:35 +01:00
else
{
2014-11-18 16:53:53 +01:00
// take the extra time on failure
if ( ! $mail_ui -> mail_bo -> folderExists ( $_folderName , true ))
{
//error_log(__METHOD__.__LINE__.' Test on Folder:'.$_folderName.' failed; Using INBOX instead');
$query [ 'selectedFolder' ] = $mail_ui -> mail_bo -> sessionData [ 'mailbox' ] = $_folderName = 'INBOX' ;
}
2013-12-12 14:34:35 +01:00
}
2013-02-08 20:11:44 +01:00
$rowsFetched [ 'messages' ] = null ;
$offset = $query [ 'start' ] + 1 ; // we always start with 1
$maxMessages = $query [ 'num_rows' ];
2016-02-25 13:26:50 +01:00
//error_log(__METHOD__.__LINE__.array2string($query));
2013-12-10 16:59:54 +01:00
$sort = ( $query [ 'order' ] == 'address' ? ( $toSchema ? 'toaddress' : 'fromaddress' ) : $query [ 'order' ]);
2016-04-12 14:53:50 +02:00
if ( ! empty ( $query [ 'search' ]) || ( $query [ 'cat_id' ] == 'bydate' && ( ! empty ( $query [ 'startdate' ]) ||! empty ( $query [ 'enddate' ]))))
2013-05-21 10:46:54 +02:00
{
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $supportsORinQuery ) || ! isset ( Mail :: $supportsORinQuery [ $mail_ui -> mail_bo -> profileID ]))
2014-04-11 15:52:58 +02:00
{
2016-05-03 21:17:44 +02:00
Mail :: $supportsORinQuery = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'supportsORinQuery' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), 60 * 60 * 10 );
2016-03-28 20:51:38 +02:00
if ( ! isset ( Mail :: $supportsORinQuery [ $mail_ui -> mail_bo -> profileID ]))
2014-07-16 15:42:36 +02:00
{
2016-03-28 20:51:38 +02:00
Mail :: $supportsORinQuery [ $mail_ui -> mail_bo -> profileID ] = true ;
2014-08-11 16:16:26 +02:00
}
2014-04-11 15:52:58 +02:00
}
2016-04-12 14:53:50 +02:00
//error_log(__METHOD__.__LINE__.' Startdate:'.$query['startdate'].' Enddate'.$query['enddate']);
$cutoffdate = $cutoffdate2 = null ;
2016-05-03 21:17:44 +02:00
if ( $query [ 'startdate' ]) $cutoffdate = Api\DateTime :: to ( $query [ 'startdate' ], 'ts' ); //SINCE, enddate
if ( $query [ 'enddate' ]) $cutoffdate2 = Api\DateTime :: to ( $query [ 'enddate' ], 'ts' ); //BEFORE, startdate
2016-04-12 14:53:50 +02:00
//error_log(__METHOD__.__LINE__.' Startdate:'.$cutoffdate2.' Enddate'.$cutoffdate);
2014-07-16 15:42:36 +02:00
$filter = array (
2016-03-28 20:51:38 +02:00
'filterName' => ( Mail :: $supportsORinQuery [ $mail_ui -> mail_bo -> profileID ] ? lang ( 'quicksearch' ) : lang ( 'subject' )),
'type' => ( $query [ 'cat_id' ] ? $query [ 'cat_id' ] : ( Mail :: $supportsORinQuery [ $mail_ui -> mail_bo -> profileID ] ? 'quick' : 'subject' )),
2014-07-16 15:42:36 +02:00
'string' => $query [ 'search' ],
2016-02-26 14:04:35 +01:00
'status' => 'any' ,
//'range'=>"BETWEEN",'since'=> date("d-M-Y", $cutoffdate),'before'=> date("d-M-Y", $cutoffdate2)
);
2016-04-12 14:53:50 +02:00
if ( $query [ 'enddate' ] || $query [ 'startdate' ]) {
$filter [ 'range' ] = " BETWEEN " ;
if ( $cutoffdate ) {
$filter [( empty ( $cutoffdate2 ) ? 'date' : 'since' )] = date ( " d-M-Y " , $cutoffdate );
if ( empty ( $cutoffdate2 )) $filter [ 'range' ] = " SINCE " ;
}
if ( $cutoffdate2 ) {
$filter [( empty ( $cutoffdate ) ? 'date' : 'before' )] = date ( " d-M-Y " , $cutoffdate2 );
if ( empty ( $cutoffdate )) $filter [ 'range' ] = " BEFORE " ;
}
}
2013-05-21 10:46:54 +02:00
}
else
{
$filter = array ();
}
2013-07-18 10:35:38 +02:00
if ( $query [ 'filter' ])
{
$filter [ 'status' ] = $query [ 'filter' ];
}
2013-09-23 10:33:30 +02:00
$reverse = ( $query [ 'sort' ] == 'ASC' ? false : true );
2016-03-24 11:38:35 +01:00
$prefchanged = false ;
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveSearchType' ]) || ( $query [ 'cat_id' ] != $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveSearchType' ]))
{
2016-03-24 16:16:10 +01:00
//error_log(__METHOD__.__LINE__.' Changing userPref ActivesearchType:'.$query['cat_id']);
2016-03-24 11:38:35 +01:00
$GLOBALS [ 'egw' ] -> preferences -> add ( 'mail' , 'ActiveSearchType' , $query [ 'cat_id' ], 'user' );
$prefchanged = true ;
}
2016-02-19 13:23:06 +01:00
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ShowDetails' ]) || ( $query [ 'filter2' ] != $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ShowDetails' ]))
{
$GLOBALS [ 'egw' ] -> preferences -> add ( 'mail' , 'ShowDetails' , $query [ 'filter2' ], 'user' );
2016-03-24 11:38:35 +01:00
$prefchanged = true ;
}
if ( $prefchanged )
{
2016-02-19 13:23:06 +01:00
// save prefs
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( true );
}
2014-08-20 16:58:12 +02:00
//error_log(__METHOD__.__LINE__.' maxMessages:'.$maxMessages.' Offset:'.$offset.' Filter:'.array2string($mail_ui->sessionData['messageFilter']));
2016-02-26 14:04:35 +01:00
/*
2016-05-03 21:17:44 +02:00
$cutoffdate = Api\DateTime :: to ( 'now' , 'ts' ) - ( 3600 * 24 * 6 ); //SINCE, enddate
$cutoffdate2 = Api\DateTime :: to ( 'now' , 'ts' ) - ( 3600 * 24 * 3 ); //BEFORE, startdate
2016-02-26 14:04:35 +01:00
$filter [ 'range' ] = " BETWEEN " ; // we support SINCE, BEFORE, BETWEEN and ON
$filter [ 'since' ] = date ( " d-M-Y " , $cutoffdate );
$filter [ 'before' ] = date ( " d-M-Y " , $cutoffdate2 );
*/
2018-12-18 19:00:02 +01:00
$sR = array ();
2014-05-09 14:43:57 +02:00
try
2013-02-08 20:11:44 +01:00
{
2014-05-09 14:43:57 +02:00
if ( $maxMessages > 75 )
{
2016-06-14 11:28:03 +02:00
$rByUid = true ;
2014-08-20 16:58:12 +02:00
$_sR = $mail_ui -> mail_bo -> getSortedList (
2014-05-09 14:43:57 +02:00
$_folderName ,
$sort ,
$reverse ,
$filter ,
2016-06-14 11:28:03 +02:00
$rByUid
2014-05-09 14:43:57 +02:00
);
$rowsFetched [ 'messages' ] = $_sR [ 'count' ];
2016-05-03 21:17:44 +02:00
$ids = $_sR [ 'match' ] -> ids ;
2014-05-09 14:43:57 +02:00
// if $sR is false, something failed fundamentally
2016-05-03 21:17:44 +02:00
if ( $reverse === true ) $ids = ( $ids === false ? array () : array_reverse (( array ) $ids ));
$sR = array_slice (( array ) $ids ,( $offset == 0 ? 0 : $offset - 1 ), $maxMessages ); // we need only $maxMessages of uids
2014-05-09 14:43:57 +02:00
$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
2014-08-20 16:58:12 +02:00
$sortResultwH = $mail_ui -> mail_bo -> getHeaders (
2014-05-09 14:43:57 +02:00
$_folderName ,
$offset ,
$maxMessages ,
$sort ,
$reverse ,
$filter ,
2015-11-20 16:16:37 +01:00
$sRToFetch ,
2016-02-18 16:46:02 +01:00
true , //cacheResult
( $query [ 'filter2' ] ? true : false ) // fetchPreview
2014-05-09 14:43:57 +02:00
);
}
}
else
2013-02-08 20:11:44 +01:00
{
$sortResult = array ();
2020-08-04 18:17:04 +02:00
$uids = array_map ( function ( $row_id )
{
return self :: splitRowID ( $row_id )[ 'msgUID' ];
}, ( array ) $query [ 'col_filter' ][ 'row_id' ]) ? : null ;
2013-02-08 20:11:44 +01:00
// fetch headers
2014-08-20 16:58:12 +02:00
$sortResultwH = $mail_ui -> mail_bo -> getHeaders (
2013-02-08 20:11:44 +01:00
$_folderName ,
$offset ,
$maxMessages ,
$sort ,
$reverse ,
2015-11-20 16:16:37 +01:00
$filter ,
2020-08-04 18:17:04 +02:00
$uids , // this uids only
2016-02-18 16:46:02 +01:00
true , // cacheResult
( $query [ 'filter2' ] ? true : false ) // fetchPreview
2013-02-08 20:11:44 +01:00
);
2014-05-09 14:43:57 +02:00
$rowsFetched [ 'messages' ] = $sortResultwH [ 'info' ][ 'total' ];
2013-02-08 20:11:44 +01:00
}
}
2014-05-09 14:43:57 +02:00
catch ( Exception $e )
2013-02-08 20:11:44 +01:00
{
2014-05-09 14:43:57 +02:00
$sortResultwH = array ();
$sR = array ();
2014-08-08 15:36:33 +02:00
self :: callWizard ( $e -> getMessage (), false , 'error' );
2013-02-08 20:11:44 +01:00
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-08-04 14:59:13 +02:00
// unlock immediately after fetching the rows
if ( stripos ( $_GET [ 'menuaction' ], 'ajax_get_rows' ) !== false )
{
//error_log(__METHOD__.__LINE__.' unlock tree ->'.$_GET['menuaction']);
$response -> call ( 'app.mail.unlock_tree' );
}
2014-08-11 16:16:26 +02:00
2013-02-08 20:11:44 +01:00
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 ;
}
2018-12-10 18:12:08 +01:00
$rowsFetched [ 'rowsFetched' ] = $sortResult [ 'header' ] ? count ( $sortResult [ 'header' ]) : 0 ;
2013-02-08 20:11:44 +01:00
if ( empty ( $rowsFetched [ 'messages' ])) $rowsFetched [ 'messages' ] = $rowsFetched [ 'rowsFetched' ];
//error_log(__METHOD__.__LINE__.' Rows fetched:'.$rowsFetched.' Data:'.array2string($sortResult));
2023-08-14 17:19:12 +02:00
$cols = array ( 'row_id' , 'uid' , 'status' , 'attachments' , 'subject' , 'address' , 'toaddress' , 'fromaddress' , 'ccaddress' , 'bccaddress' , 'additionaltoaddress' , 'date' , 'size' , 'modified' , 'bodypreview' , 'security' );
2013-02-08 20:11:44 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'select_mode' ] == 'EGW_SELECTMODE_TOGGLE' ) unset ( $cols [ 0 ]);
2014-08-20 16:58:12 +02:00
$rows = $mail_ui -> header2gridelements ( $sortResult [ 'header' ], $cols , $_folderName , $folderType = $toSchema );
2017-03-22 12:31:46 +01:00
// Save the session (since we are committing session) at the end
// to make sure all necessary data are stored in session.
// e.g.: Link:: get_data which is used to read attachments data.
$mail_ui -> mail_bo -> saveSessionData ();
2013-11-19 12:17:32 +01:00
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) Mail :: logRunTimes ( $starttime , null , 'Folder:' . $_folderName . ' Start:' . $query [ 'start' ] . ' NumRows:' . $query [ 'num_rows' ], __METHOD__ . __LINE__ );
2013-02-08 20:11:44 +01:00
return $rowsFetched [ 'messages' ];
}
2013-02-19 17:30:59 +01:00
/**
* function createRowID - create a unique rowID for the grid
*
2014-05-22 09:47:49 +02:00
* @ 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
2014-05-22 16:46:50 +02:00
* @ param boolean $_prependApp to indicate that the app 'mail' is to be used for creating the rowID
2013-09-05 16:52:11 +02:00
* @ return string - a colon separated string in the form [ app : ] accountID : profileID : folder : message_uid
2013-02-19 17:30:59 +01:00
*/
2013-09-05 16:52:11 +02:00
function createRowID ( $_folderName , $message_uid , $_prependApp = false )
2013-02-19 17:30:59 +01:00
{
2014-01-31 10:47:17 +01:00
return self :: generateRowID ( $this -> mail_bo -> profileID , $_folderName , $message_uid , $_prependApp );
}
/**
* static function generateRowID - create a unique rowID for the grid
*
2014-05-22 09:47:49 +02:00
* @ param integer $_profileID profile ID for the rowid to be used
* @ param string $_folderName to ensure the uniqueness of the uid over all folders
* @ param string $message_uid the message_Uid to be used for creating the rowID
* @ param boolean $_prependApp to indicate that the app 'mail' is to be used for creating the rowID
2014-01-31 10:47:17 +01:00
* @ return string - a colon separated string in the form [ app : ] accountID : profileID : folder : message_uid
*/
static function generateRowID ( $_profileID , $_folderName , $message_uid , $_prependApp = false )
{
return ( $_prependApp ? 'mail' . self :: $delimiter : '' ) . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]) . self :: $delimiter . $_profileID . self :: $delimiter . base64_encode ( $_folderName ) . self :: $delimiter . $message_uid ;
2013-02-19 17:30:59 +01:00
}
/**
* function splitRowID - split the rowID into its parts
*
2014-05-22 09:47:49 +02:00
* @ param string $_rowID string - a colon separated string in the form accountID : profileID : folder : message_uid
2013-02-19 17:30:59 +01:00
* @ return array populated named result array ( accountID , profileID , folder , msgUID )
*/
2013-03-05 15:09:35 +01:00
static function splitRowID ( $_rowID )
2013-02-19 17:30:59 +01:00
{
2013-02-20 17:27:10 +01:00
$res = explode ( self :: $delimiter , $_rowID );
2013-03-05 15:09:35 +01:00
// as a rowID is perceeded by app::, should be mail!
2013-10-03 12:05:05 +02:00
//error_log(__METHOD__.__LINE__.array2string($res).' [0] isInt:'.is_int($res[0]).' [0] isNumeric:'.is_numeric($res[0]).' [0] isString:'.is_string($res[0]).' Count:'.count($res));
2013-09-05 16:52:11 +02:00
if ( count ( $res ) == 4 && is_numeric ( $res [ 0 ]) )
{
// we have an own created rowID; prepend app=mail
array_unshift ( $res , 'mail' );
}
2021-10-07 10:14:08 +02:00
return array ( 'app' => $res [ 0 ], 'accountID' => $res [ 1 ] ? ? null , 'profileID' => $res [ 2 ] ? ? null , 'folder' => base64_decode ( $res [ 3 ] ? ? null ), 'msgUID' => $res [ 4 ] ? ? null );
2013-02-19 17:30:59 +01:00
}
2013-02-08 20:11:44 +01:00
/**
2014-02-27 18:47:06 +01:00
* Get actions for preview toolbar
2013-02-08 20:11:44 +01:00
*
2014-02-27 18:47:06 +01:00
* @ return array
2013-02-08 20:11:44 +01:00
*/
2014-02-27 18:47:06 +01:00
function get_toolbar_actions ()
2013-02-08 20:11:44 +01:00
{
2014-02-27 18:47:06 +01:00
$actions = $this -> get_actions ();
2024-09-02 14:11:16 +02:00
$arrActions = array ( 'composeasnew' , 'replies' , 'forward' , 'flagged' , 'delete' , 'print' ,
2017-06-02 17:17:15 +02:00
'infolog' , 'tracker' , 'calendar' , 'save' , 'view' , 'read' , 'label1' , 'label2' , 'label3' , 'label4' , 'label5' , 'spam' , 'ham' );
2024-09-02 14:11:16 +02:00
$actionsenabled = [];
2014-07-16 18:34:15 +02:00
foreach ( $arrActions as & $act )
2013-10-05 16:15:29 +02:00
{
//error_log(__METHOD__.__LINE__.' '.$act.'->'.array2string($actions[$act]));
switch ( $act )
{
2024-09-02 14:11:16 +02:00
case 'replies' :
// flatten reply-actions for toolbar
foreach ( $actions [ $act ][ 'children' ] as $name => $child )
{
2024-09-02 15:16:40 +02:00
$actionsenabled [ $name ] = $child + [
'group' => $actions [ $act ][ 'group' ],
];
2024-09-02 14:11:16 +02:00
}
break ;
2013-10-05 16:15:29 +02:00
case 'forward' :
2014-02-13 12:30:05 +01:00
$actionsenabled [ $act ] = $actions [ $act ];
2013-10-05 16:15:29 +02:00
break ;
case 'save' :
2014-02-13 12:30:05 +01:00
$actionsenabled [ $act ] = $actions [ $act ];
2013-10-05 16:15:29 +02:00
break ;
2014-02-13 12:30:05 +01:00
case 'view' :
$actionsenabled [ $act ] = $actions [ $act ];
2013-10-05 16:15:29 +02:00
break ;
case 'flagged' :
2014-02-10 15:03:19 +01:00
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ $act ];
2013-10-05 16:15:29 +02:00
break ;
2015-09-16 18:00:35 +02:00
case 'read' :
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ $act ];
break ;
case 'label1' :
$actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ][ 'caption' ] = lang ( 'important' );
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ];
break ;
case 'label2' :
$actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ][ 'caption' ] = lang ( 'job' );
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ];
break ;
case 'label3' :
$actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ][ 'caption' ] = lang ( 'personal' );
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ];
break ;
case 'label4' :
$actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ][ 'caption' ] = lang ( 'to do' );
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ];
break ;
case 'label5' :
$actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ][ 'caption' ] = lang ( 'later' );
$actionsenabled [ $act ] = $actions [ 'mark' ][ 'children' ][ 'setLabel' ][ 'children' ][ $act ];
break ;
2017-06-02 17:17:15 +02:00
case 'ham' :
case 'spam' :
$actionsenabled [ $act ] = $actions [ 'spamfilter' ][ 'children' ][ $act ];
break ;
2013-10-05 16:15:29 +02:00
default :
if ( isset ( $actions [ $act ])) $actionsenabled [ $act ] = $actions [ $act ];
}
}
2014-02-27 18:47:06 +01:00
unset ( $actionsenabled [ 'drag_mail' ]);
2014-03-07 15:26:16 +01:00
//error_log(array2string($actionsenabled['view']));
unset ( $actionsenabled [ 'view' ][ 'children' ][ 'openastext' ]); //not supported in preview
unset ( $actionsenabled [ 'view' ][ 'children' ][ 'openashtml' ]); //not supported in preview
2014-02-27 18:47:06 +01:00
return $actionsenabled ;
}
/**
* function header2gridelements - to populate the grid elements with the collected Data
*
2014-05-22 09:47:49 +02:00
* @ param array $_headers headerdata to process
* @ param array $cols cols to populate
* @ param array $_folderName to ensure the uniqueness of the uid over all folders
* @ param array $_folderType used to determine if we need to populate from / to
2014-02-27 18:47:06 +01:00
* @ return array populated result array
*/
2014-07-16 18:34:15 +02:00
public function header2gridelements ( $_headers , $cols , $_folderName , $_folderType = 0 )
2014-02-27 18:47:06 +01:00
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) $starttime = microtime ( true );
2014-02-27 18:47:06 +01:00
$rv = array ();
2013-02-08 20:11:44 +01:00
$i = 0 ;
foreach (( array ) $_headers as $header )
{
$i ++ ;
$data = array ();
//error_log(__METHOD__.array2string($header));
$message_uid = $header [ 'uid' ];
$data [ 'uid' ] = $message_uid ;
2013-02-19 17:30:59 +01:00
$data [ 'row_id' ] = $this -> createRowID ( $_folderName , $message_uid );
2013-02-08 20:11:44 +01:00
2018-07-04 15:41:43 +02:00
if ( $header [ 'smimeType' ])
2017-08-31 17:33:23 +02:00
{
2018-07-04 15:41:43 +02:00
$data [ 'smime' ] = Mail\Smime :: isSmimeSignatureOnly ( $header [ 'smimeType' ]) ?
Mail\Smime :: TYPE_SIGN : Mail\Smime :: TYPE_ENCRYPT ;
2017-08-31 17:33:23 +02:00
}
2013-02-08 20:11:44 +01:00
$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 " ;
//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 [] = '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' ]) {
2020-08-05 15:38:14 +02:00
$css_styles [] = 'label1' ;
2013-02-08 20:11:44 +01:00
}
if ( $header [ 'label2' ]) {
2020-08-05 15:38:14 +02:00
$css_styles [] = 'label2' ;
2013-02-08 20:11:44 +01:00
}
if ( $header [ 'label3' ]) {
2020-08-05 15:38:14 +02:00
$css_styles [] = 'label3' ;
2013-02-08 20:11:44 +01:00
}
if ( $header [ 'label4' ]) {
2020-08-05 15:38:14 +02:00
$css_styles [] = 'label4' ;
2013-02-08 20:11:44 +01:00
}
if ( $header [ 'label5' ]) {
2020-08-05 15:38:14 +02:00
$css_styles [] = 'label5' ;
2013-02-08 20:11:44 +01:00
}
//error_log(__METHOD__.array2string($css_styles));
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' ]);
// curly brackets get messed up by the template!
if ( ! empty ( $header [ 'subject' ])) {
// make the subject shorter if it is to long
$subject = $header [ 'subject' ];
} else {
2013-10-08 16:55:20 +02:00
$subject = '(' . lang ( 'no subject' ) . ')' ;
2013-02-08 20:11:44 +01:00
}
2013-02-19 17:30:59 +01:00
$data [ " subject " ] = $subject ; // the mailsubject
2013-02-08 20:11:44 +01:00
}
2013-10-01 13:29:54 +02:00
$imageHTMLBlock = '' ;
2013-11-05 15:16:40 +01:00
//error_log(__METHOD__.__LINE__.array2string($header));
2024-09-16 09:57:35 +02:00
if ( in_array ( 'attachments' , $cols ))
2013-02-08 20:11:44 +01:00
{
2018-04-13 09:11:03 +02:00
if ( ! empty ( $header [ 'attachments' ]) && ( in_array ( $header [ 'mimetype' ], array (
'multipart/mixed' , 'multipart/signed' , 'multipart/related' , 'multipart/report' ,
'text/calendar' , 'text/html' , 'multipart/alternative' ,
)) ||
2013-02-08 20:11:44 +01:00
substr ( $header [ 'mimetype' ], 0 , 11 ) == 'application' ||
substr ( $header [ 'mimetype' ], 0 , 5 ) == 'audio' ||
2018-04-13 09:11:03 +02:00
substr ( $header [ 'mimetype' ], 0 , 5 ) == 'video' ))
2013-02-08 20:11:44 +01:00
{
2016-05-03 21:17:44 +02:00
$image = Api\Html :: image ( 'mail' , 'attach' );
2013-10-03 12:05:05 +02:00
$datarowid = $this -> createRowID ( $_folderName , $message_uid , true );
2014-06-03 09:51:39 +02:00
$attachments = $header [ 'attachments' ];
2018-04-13 09:11:03 +02:00
if ( count ( $attachments ) == 1 )
2014-06-03 09:51:39 +02:00
{
2020-04-16 19:34:10 +02:00
$image = Api\Html :: image ( 'mail' , 'attach' , $attachments [ 0 ][ 'name' ]);
2013-10-01 13:29:54 +02:00
}
2018-04-13 09:11:03 +02:00
else
2013-10-01 13:29:54 +02:00
{
2016-05-03 21:17:44 +02:00
$image = Api\Html :: image ( 'mail' , 'attach' , lang ( '%1 attachments' , count ( $attachments )));
2013-02-08 20:11:44 +01:00
}
2018-04-13 09:11:03 +02:00
$imageHTMLBlock = self :: createAttachmentBlock ( $attachments , $datarowid , $header [ 'uid' ], $_folderName );
2013-02-08 20:11:44 +01:00
$attachmentFlag = $image ;
2018-04-13 09:11:03 +02:00
}
else
{
$attachmentFlag = ' ' ;
$imageHTMLBlock = '' ;
2013-02-08 20:11:44 +01:00
}
// show priority flag
2018-04-13 09:11:03 +02:00
if ( $header [ 'priority' ] < 3 )
{
2024-09-16 09:57:35 +02:00
$image = Api\Html :: image ( 'mail' , 'prio_high' , lang ( 'High priority' ));
2018-04-13 09:11:03 +02:00
}
elseif ( $header [ 'priority' ] > 3 )
{
2024-09-16 09:57:35 +02:00
$image = Api\Html :: image ( 'mail' , 'prio_low' , lang ( 'Low priority' ));
2018-04-13 09:11:03 +02:00
}
else
{
2013-02-08 20:11:44 +01:00
$image = '' ;
}
// show a flag for flagged messages
$imageflagged = '' ;
if ( $header [ 'flagged' ])
{
2024-09-16 09:57:35 +02:00
$imageflagged = Api\Html :: image ( 'mail' , 'unread_flagged_small' , lang ( 'Unread' ));
2013-02-08 20:11:44 +01:00
}
2024-09-16 09:57:35 +02:00
$data [ 'attachments' ] = $image . $attachmentFlag . $imageflagged ; // icon for attachments available
2013-02-08 20:11:44 +01:00
}
// sent or draft or template folder -> to address
if ( in_array ( " toaddress " , $cols ))
{
// sent or drafts or template folder means foldertype > 0, use to address instead of from
2016-03-28 20:51:38 +02:00
$data [ " toaddress " ] = $header [ 'to_address' ]; //Mail::htmlentities($header['to_address'],$this->charset);
2013-02-08 20:11:44 +01:00
}
2013-12-03 15:38:50 +01:00
if ( in_array ( " additionaltoaddress " , $cols ))
{
2013-12-17 00:41:39 +01:00
$data [ 'additionaltoaddress' ] = $header [ 'additional_to_addresses' ];
2013-12-03 15:38:50 +01:00
}
2013-02-08 20:11:44 +01:00
//fromaddress
if ( in_array ( " fromaddress " , $cols ))
{
2014-07-16 15:42:36 +02:00
$data [ " fromaddress " ] = $header [ 'sender_address' ];
2013-02-08 20:11:44 +01:00
}
2019-01-22 18:48:39 +01:00
$data [ 'additionalfromaddress' ] = $header [ 'additional_from_addresses' ];
2013-12-03 15:38:50 +01:00
if ( in_array ( " ccaddress " , $cols ))
{
2013-12-17 00:41:39 +01:00
$data [ 'ccaddress' ] = $header [ 'cc_addresses' ];
2013-12-03 15:38:50 +01:00
}
2023-08-14 17:19:12 +02:00
if ( in_array ( " bccaddress " , $cols ))
{
$data [ 'bccaddress' ] = $header [ 'bcc_addresses' ];
}
2013-02-08 20:11:44 +01:00
if ( in_array ( " date " , $cols ))
{
2014-07-16 15:42:36 +02:00
$data [ " date " ] = $header [ 'date' ];
2013-02-08 20:11:44 +01:00
}
2013-02-11 14:04:49 +01:00
if ( in_array ( " modified " , $cols ))
{
$data [ " modified " ] = $header [ 'internaldate' ];
}
2013-02-08 20:11:44 +01:00
if ( in_array ( " size " , $cols ))
2013-02-12 15:30:58 +01:00
$data [ " size " ] = $header [ 'size' ]; /// size
2013-02-08 20:11:44 +01:00
2013-02-14 18:10:20 +01:00
$data [ " class " ] = implode ( ' ' , $css_styles );
2013-12-06 11:35:39 +01:00
//translate style-classes back to flags
2014-01-13 15:22:58 +01:00
$data [ 'flags' ] = Array ();
2013-12-06 11:35:39 +01:00
if ( $header [ 'seen' ]) $data [ " flags " ][ 'read' ] = 'read' ;
2014-07-16 18:34:15 +02:00
foreach ( $css_styles as & $flag ) {
2013-12-05 16:09:35 +01:00
if ( $flag != 'mail' )
{
2020-08-05 15:38:14 +02:00
if ( $flag == 'label1' ) { $data [ " flags " ][ 'label1' ] = 'label1' ;}
elseif ( $flag == 'label2' ) { $data [ " flags " ][ 'label2' ] = 'label2' ;}
elseif ( $flag == 'label3' ) { $data [ " flags " ][ 'label3' ] = 'label3' ;}
elseif ( $flag == 'label4' ) { $data [ " flags " ][ 'label4' ] = 'label4' ;}
elseif ( $flag == 'label5' ) { $data [ " flags " ][ 'label5' ] = 'label5' ;}
2014-01-13 15:22:58 +01:00
elseif ( $flag == 'unseen' ) { unset ( $data [ " flags " ][ 'read' ]);}
2013-12-05 16:09:35 +01:00
else $data [ " flags " ][ $flag ] = $flag ;
}
}
2014-03-27 10:25:11 +01:00
if ( $header [ 'disposition-notification-to' ]) $data [ 'dispositionnotificationto' ] = $header [ 'disposition-notification-to' ];
2014-03-25 17:20:28 +01:00
if (( $header [ 'mdnsent' ] || $header [ 'mdnnotsent' ] | $header [ 'seen' ]) && isset ( $data [ 'dispositionnotificationto' ])) unset ( $data [ 'dispositionnotificationto' ]);
2013-10-01 13:29:54 +02:00
$data [ 'attachmentsBlock' ] = $imageHTMLBlock ;
2023-05-10 09:49:42 +02:00
$data [ 'address' ] = $_folderType ? $data [ " toaddress " ] : $data [ " fromaddress " ];
$data [ 'lavatar' ] = Api\Mail\Avatar :: getLavatar ( $data [ 'address' ]);
2023-06-27 08:59:43 +02:00
$data [ 'fromlavatar' ] = $_folderType ? Api\Mail\Avatar :: getLavatar ( $data [ 'fromaddress' ]) : $data [ 'lavatar' ];
2022-07-22 15:08:23 +02:00
2023-05-10 09:49:42 +02:00
if ( in_array ( " bodypreview " , $cols ) && $header [ 'bodypreview' ])
2015-11-20 16:16:37 +01:00
{
$data [ " bodypreview " ] = $header [ 'bodypreview' ];
}
2023-06-22 14:38:18 +02:00
$data [ 'emailTag' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'emailTag' ] ? ? " onlyname " ;
2013-02-08 20:11:44 +01:00
$rv [] = $data ;
2014-03-27 10:25:11 +01:00
//error_log(__METHOD__.__LINE__.array2string($data));
2013-02-08 20:11:44 +01:00
}
2016-03-28 20:51:38 +02:00
if ( Mail :: $debugTimes ) Mail :: logRunTimes ( $starttime , null , 'Folder:' . $_folderName , __METHOD__ . __LINE__ );
2014-02-27 18:47:06 +01:00
// ToDo: call this ONLY if labels change
2016-05-03 21:17:44 +02:00
Etemplate\Widget :: setElementAttribute ( 'toolbar' , 'actions' , $this -> get_toolbar_actions ());
2014-02-27 18:47:06 +01:00
2013-02-08 20:11:44 +01:00
return $rv ;
}
2013-02-28 10:28:08 +01:00
/**
* display messages header lines
*
* all params are passed as GET Parameters
*/
function displayHeader ()
{
if ( isset ( $_GET [ 'id' ])) $rowID = $_GET [ 'id' ];
if ( isset ( $_GET [ 'part' ])) $partID = $_GET [ 'part' ];
2013-03-05 15:09:35 +01:00
$hA = self :: splitRowID ( $rowID );
2013-02-28 10:28:08 +01:00
$uid = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
2014-11-06 14:11:44 +01:00
$icServerID = $hA [ 'profileID' ];
$rememberServerID = $this -> mail_bo -> profileID ;
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2013-02-28 10:28:08 +01:00
$this -> mail_bo -> reopen ( $mailbox );
2016-05-03 21:17:44 +02:00
$headers_in = $this -> mail_bo -> getMessageRawHeader ( $uid , $partID );
2013-02-28 10:28:08 +01:00
// add line breaks to $rawheaders
2016-05-03 21:17:44 +02:00
$newRawHeaders = explode ( " \n " , $headers_in );
2013-02-28 10:28:08 +01:00
reset ( $newRawHeaders );
// reset $rawheaders
$rawheaders = " " ;
// create it new, with good line breaks
reset ( $newRawHeaders );
2019-02-12 22:13:45 +01:00
foreach ( $newRawHeaders as $value )
{
2013-02-28 10:28:08 +01:00
$rawheaders .= wordwrap ( $value , 90 , " \n " );
}
$this -> mail_bo -> closeConnection ();
2014-11-06 14:11:44 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile back to where we came from->'.$rememberServerID);
$this -> changeProfile ( $rememberServerID );
}
2013-02-28 10:28:08 +01:00
header ( 'Content-type: text/html; charset=iso-8859-1' );
print '<pre>' . htmlspecialchars ( $rawheaders , ENT_NOQUOTES , 'iso-8859-1' ) . '</pre>' ;
}
2013-06-05 16:24:56 +02:00
/**
* display messages
2014-09-09 14:08:08 +02:00
* @ param array $_requesteddata etemplate content
2013-09-05 16:52:11 +02:00
* all params are passed as GET Parameters , but can be passed via ExecMethod2 as array too
2013-06-05 16:24:56 +02:00
*/
2013-09-05 16:52:11 +02:00
function displayMessage ( $_requesteddata = null )
2013-06-05 16:24:56 +02:00
{
2014-09-09 14:08:08 +02:00
if ( is_null ( $_requesteddata )) $_requesteddata = $_GET ;
2014-01-24 12:48:24 +01:00
$preventRedirect = false ;
2014-09-09 14:08:08 +02:00
if ( isset ( $_requesteddata [ 'id' ])) $rowID = $_requesteddata [ 'id' ];
2015-02-12 16:19:24 +01:00
if ( isset ( $_requesteddata [ 'part' ])) $partID = $_requesteddata [ 'part' ] != 'null' ? $_requesteddata [ 'part' ] : null ;
2014-09-09 14:08:08 +02:00
if ( isset ( $_requesteddata [ 'mode' ])) $preventRedirect = (( $_requesteddata [ 'mode' ] == 'display' || $_requesteddata [ 'mode' ] == 'print' ) ? true : false );
2013-06-05 16:24:56 +02:00
$hA = self :: splitRowID ( $rowID );
$uid = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
2014-11-06 14:11:44 +01:00
$icServerID = $hA [ 'profileID' ];
$rememberServerID = $this -> mail_bo -> profileID ;
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
$htmlOptions = $this -> mail_bo -> htmlOptions ;
if ( ! empty ( $_requesteddata [ 'tryastext' ])) $htmlOptions = " only_if_no_text " ;
if ( ! empty ( $_requesteddata [ 'tryashtml' ])) $htmlOptions = " always_display " ;
2013-09-05 16:52:11 +02:00
//error_log(__METHOD__.__LINE__.array2string($hA));
2014-09-09 14:08:08 +02:00
if (( $this -> mail_bo -> isDraftFolder ( $mailbox )) && $_requesteddata [ 'mode' ] == 'print' )
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-09-09 14:08:08 +02:00
$response -> call ( 'app.mail.print_for_compose' , $rowID );
}
2014-01-24 12:48:24 +01:00
if ( ! $preventRedirect && ( $this -> mail_bo -> isDraftFolder ( $mailbox ) || $this -> mail_bo -> isTemplateFolder ( $mailbox )))
2014-01-21 09:26:59 +01:00
{
2016-05-03 21:17:44 +02:00
Egw :: redirect_link ( '/index.php' , array ( 'menuaction' => 'mail.mail_compose.compose' , 'id' => $rowID , 'from' => 'composefromdraft' ));
2014-01-21 09:26:59 +01:00
}
2013-06-05 16:24:56 +02:00
$this -> mail_bo -> reopen ( $mailbox );
// retrieve the flags of the message, before touching it.
2016-01-08 15:47:31 +01:00
try
{
$headers = $this -> mail_bo -> getMessageHeader ( $uid , $partID , true , true , $mailbox );
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2016-01-08 15:47:31 +01:00
{
2013-06-05 16:24:56 +02:00
$error_msg [] = lang ( " ERROR: Message could not be displayed. " );
$error_msg [] = lang ( " In Mailbox: %1, with ID: %2, and PartID: %3 " , $mailbox , $uid , $partID );
2016-05-03 21:17:44 +02:00
Framework :: message ( $e -> getMessage (), 'error' );
2013-06-05 16:24:56 +02:00
}
2014-07-16 18:34:15 +02:00
if ( ! empty ( $uid )) $this -> mail_bo -> getFlags ( $uid );
2014-01-20 09:55:07 +01:00
$envelope = $this -> mail_bo -> getMessageEnvelope ( $uid , $partID , true , $mailbox );
2014-01-31 10:47:17 +01:00
//error_log(__METHOD__.__LINE__.array2string($envelope));
2014-07-16 18:34:15 +02:00
$this -> mail_bo -> getMessageRawHeader ( $uid , $partID , $mailbox );
2013-06-05 16:24:56 +02:00
$fetchEmbeddedImages = false ;
2015-05-19 11:26:08 +02:00
// if we are in HTML so its likely that we should show the embedded images; as a result
// we do NOT want to see those, that are embedded in the list of attachments
2013-06-05 16:24:56 +02:00
if ( $htmlOptions != 'always_display' ) $fetchEmbeddedImages = true ;
2017-07-19 18:16:22 +02:00
try {
$attachments = $this -> mail_bo -> getMessageAttachments ( $uid , $partID , null , $fetchEmbeddedImages , true , true , $mailbox );
2017-07-12 18:40:56 +02:00
}
2017-07-19 18:16:22 +02:00
catch ( Mail\Smime\PassphraseMissing $e )
2017-01-19 18:52:28 +01:00
{
2017-07-19 18:16:22 +02:00
//continue
2017-01-19 18:52:28 +01:00
}
2017-06-28 10:24:59 +02:00
//error_log(__METHOD__.__LINE__.array2string($attachments));
$attachmentHTMLBlock = self :: createAttachmentBlock ( $attachments , $rowID , $uid , $mailbox );
2013-06-05 16:24:56 +02:00
$nonDisplayAbleCharacters = array ( '[\016]' , '[\017]' ,
'[\020]' , '[\021]' , '[\022]' , '[\023]' , '[\024]' , '[\025]' , '[\026]' , '[\027]' ,
'[\030]' , '[\031]' , '[\032]' , '[\033]' , '[\034]' , '[\035]' , '[\036]' , '[\037]' );
2013-06-17 16:25:20 +02:00
//error_log(__METHOD__.__LINE__.$mailBody);
2013-06-05 16:24:56 +02:00
$this -> mail_bo -> closeConnection ();
2014-01-17 11:47:35 +01:00
//$GLOBALS['egw_info']['flags']['currentapp'] = 'mail';//should not be needed
2016-05-03 21:17:44 +02:00
$etpl = new Etemplate ( 'mail.display' );
2014-07-16 15:42:36 +02:00
$subject = $this -> mail_bo -> decode_subject ( preg_replace ( $nonDisplayAbleCharacters , '' , $envelope [ 'SUBJECT' ]), false );
2013-07-15 14:31:02 +02:00
2013-07-19 17:13:01 +02:00
// Set up data for taglist widget(s)
2013-07-20 11:27:37 +02:00
if ( $envelope [ 'FROM' ] == $envelope [ 'SENDER' ]) unset ( $envelope [ 'SENDER' ]);
2016-05-03 21:17:44 +02:00
$sel_options = array ();
2013-07-19 17:13:01 +02:00
foreach ( array ( 'SENDER' , 'FROM' , 'TO' , 'CC' , 'BCC' ) as $field )
{
2013-07-20 15:10:17 +02:00
if ( ! isset ( $envelope [ $field ])) continue ;
2013-07-19 17:13:01 +02:00
foreach ( $envelope [ $field ] as $field_data )
{
2013-07-20 10:20:04 +02:00
//error_log(__METHOD__.__LINE__.array2string($field_data));
2022-07-25 16:35:50 +02:00
$content [ strtolower ( $field )][] = $field_data ;
2013-07-19 17:13:01 +02:00
$sel_options [ $field ][] = array (
2013-11-25 19:14:33 +01:00
// taglist requires these - not optional
'id' => $field_data ,
'label' => str_replace ( '"' , " ' " , $field_data ),
2013-11-10 21:53:51 +01:00
);
2013-07-19 17:13:01 +02:00
}
}
2015-09-16 18:00:35 +02:00
$actionsenabled = $this -> getDisplayToolbarActions ();
2014-02-05 17:17:37 +01:00
$content [ 'displayToolbaractions' ] = json_encode ( $actionsenabled );
2013-06-05 16:24:56 +02:00
if ( empty ( $subject )) $subject = lang ( 'no subject' );
2013-07-17 14:01:01 +02:00
$content [ 'msg' ] = ( is_array ( $error_msg ) ? implode ( " <br> " , $error_msg ) : $error_msg );
2013-10-04 16:39:25 +02:00
// Send mail ID so we can use it for actions
$content [ 'mail_id' ] = $rowID ;
2014-10-02 10:44:48 +02:00
if ( ! is_array ( $headers ) || ! isset ( $headers [ 'DATE' ]))
{
$headers [ 'DATE' ] = ( is_array ( $envelope ) && $envelope [ 'DATE' ] ? $envelope [ 'DATE' ] : '' );
}
2016-03-28 20:51:38 +02:00
$content [ 'mail_displaydate' ] = Mail :: _strtotime ( $headers [ 'DATE' ], 'ts' , true );
2013-06-17 16:25:20 +02:00
$content [ 'mail_displaysubject' ] = $subject ;
2014-02-04 12:31:13 +01:00
$linkData = array ( 'menuaction' => " mail.mail_ui.loadEmailBody " , " _messageID " => $rowID );
if ( ! empty ( $partID )) $linkData [ '_partID' ] = $partID ;
if ( $htmlOptions != $this -> mail_bo -> htmlOptions ) $linkData [ '_htmloptions' ] = $htmlOptions ;
2016-05-03 21:17:44 +02:00
$content [ 'mailDisplayBodySrc' ] = Egw :: link ( '/index.php' , $linkData );
2022-07-25 16:35:50 +02:00
if ( ! empty ( $attachmentHTMLBlock ))
{
$content [ 'mail_displayattachments' ] = $attachmentHTMLBlock ;
2023-02-07 12:22:23 +01:00
$content [ 'attachmentsBlockTitle' ] = count ( $attachmentHTMLBlock ) > 1 ? '+' . ( count ( $attachmentHTMLBlock ) - 1 ) : '' ;
2022-07-27 14:21:21 +02:00
$sel_options [ 'mail_displayattachments' ][ 'actions' ] = mail_hooks :: attachmentsBlockActions ();
2022-07-25 16:35:50 +02:00
}
2013-10-05 11:03:51 +02:00
$content [ 'mail_id' ] = $rowID ;
2014-07-14 22:50:08 +02:00
2024-08-29 11:42:26 +02:00
if ( $headers [ 'SMIMETYPE' ])
{
$content [ 'smime' ] = Mail\Smime :: isSmimeSignatureOnly ( $headers [ 'SMIMETYPE' ]) ?
Mail\Smime :: TYPE_SIGN : Mail\Smime :: TYPE_ENCRYPT ;
}
2014-07-14 22:50:08 +02:00
// DRAG attachments actions
$etpl -> setElementAttribute ( 'mail_displayattachments' , 'actions' , array (
'file_drag' => array (
'dragType' => 'file' ,
'type' => 'drag' ,
'onExecute' => 'javaScript:app.mail.drag_attachment'
)
));
2013-06-17 16:25:20 +02:00
$readonlys = $preserv = $content ;
2023-02-28 19:14:07 +01:00
unset ( $readonlys [ 'mail_displayattachments' ]);
2019-09-09 20:04:13 +02:00
$readonlys [ 'mail_displaydate' ] = true ;
2014-11-06 14:11:44 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile back to where we came from->'.$rememberServerID);
$this -> changeProfile ( $rememberServerID );
}
2020-07-09 11:54:52 +02:00
// send configured image proxy to client-side
$content [ 'image_proxy' ] = self :: image_proxy ();
2023-05-10 09:54:03 +02:00
$content [ 'avatar' ] = Api\Mail\Avatar :: getAvatar ( $content [ 'from' ][ 0 ]);
2023-06-21 16:45:23 +02:00
$content [ 'emailTag' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'emailTag' ] ? ? 'onlyname' ;
2022-09-22 14:06:04 +02:00
$etpl -> exec ( 'mail.mail_ui.displayMessage' , $content , $sel_options , $readonlys , $preserv , 2 );
2013-06-05 16:24:56 +02:00
}
2015-11-11 13:26:14 +01:00
2017-07-12 18:40:56 +02:00
/**
* This is a helper function to trigger Push method
* faster than normal 60 sec cycle .
* @ todo : Once we have socket push implemented we should
* remove this function plus its client side companion .
*/
function ajax_smimeAttachmentsChecker ()
{
$response = Api\Json\Response :: get ();
$response -> data ( true );
2017-01-19 18:52:28 +01:00
}
2017-08-21 10:59:02 +02:00
/**
* Adds certificate to relevant contact
* @ param array $_metadata data of sender ' s certificate
*/
function ajax_smimeAddCertToContact ( $_metadata )
{
$response = Api\Json\Response :: get ();
$ab = new addressbook_bo ();
$response -> data ( $ab -> set_smime_keys ( array ( $_metadata [ 'email' ] => $_metadata [ 'cert' ])));
}
2017-08-24 12:14:06 +02:00
2017-08-22 17:25:29 +02:00
/**
* Generates certificate base on given data and send
* private key , pubkey and certificate back to client callback .
*
* @ param array $_data
*/
function ajax_smimeGenCertificate ( $_data )
{
$smime = new Mail\Smime ();
$response = Api\Json\Response :: get ();
// fields need to be excluded from data
2018-04-10 13:15:09 +02:00
$discards = array ( 'passphrase' , 'passphraseConf' , 'ca' , 'validity' );
2017-08-22 17:25:29 +02:00
$ca = $_data [ 'ca' ];
$passphrase = $_data [ 'passphrase' ];
2018-04-10 13:15:09 +02:00
foreach ( array_keys ( $_data ) as $key )
2017-08-22 17:25:29 +02:00
{
if ( empty ( $_data [ $key ]) || in_array ( $key , $discards )) unset ( $_data [ $key ]);
}
2018-04-10 13:15:09 +02:00
$response -> data ( $smime -> generate_certificate ( $_data , $ca , null , $passphrase , $_data [ 'validity' ]));
2017-08-22 17:25:29 +02:00
}
2017-08-21 10:59:02 +02:00
2017-08-30 17:00:28 +02:00
/**
* Export stored smime certificate in database
* @ return boolean return false if not successful
*/
function smimeExportCert ()
{
if ( empty ( $_GET [ 'acc_id' ])) return false ;
2017-08-31 11:39:50 +02:00
$acc_smime = Mail\Smime :: get_acc_smime ( $_GET [ 'acc_id' ]);
2017-08-30 17:00:28 +02:00
$length = 0 ;
$mime = 'application/x-pkcs12' ;
Api\Header\Content :: safe ( $acc_smime [ 'acc_smime_password' ], " certificate.p12 " , $mime , $length , true , true );
echo $acc_smime [ 'acc_smime_password' ];
exit ();
}
2015-09-16 18:00:35 +02:00
/**
* Build actions for display toolbar
*/
function getDisplayToolbarActions ()
{
$actions = $this -> get_toolbar_actions ();
$actions [ 'mark' ][ 'children' ][ 'flagged' ] = array (
'group' => $actions [ 'mark' ][ 'children' ][ 'flagged' ][ 'group' ],
'caption' => 'Flagged' ,
'icon' => 'unread_flagged_small' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
);
$actions [ 'mark' ][ 'children' ][ 'unflagged' ] = array (
'group' => $actions [ 'mark' ][ 'children' ][ 'flagged' ][ 'group' ],
'caption' => 'Unflagged' ,
'icon' => 'read_flagged_small' ,
'onExecute' => 'javaScript:app.mail.mail_flag' ,
);
$actions [ 'tracker' ][ 'toolbarDefault' ] = true ;
$actions [ 'forward' ][ 'toolbarDefault' ] = true ;
2016-03-09 13:31:55 +01:00
2015-09-16 18:00:35 +02:00
$compose = $actions [ 'composeasnew' ];
unset ( $actions [ 'composeasnew' ]);
2016-05-03 21:17:44 +02:00
$actions2 = array_reverse ( $actions , true );
$actions2 [ 'composeasnew' ] = $compose ;
return array_reverse ( $actions2 , true );
2015-09-16 18:00:35 +02:00
}
2015-11-11 13:26:14 +01:00
2013-06-17 16:25:20 +02:00
/**
* helper function to create the attachment block / table
*
2014-05-22 09:47:49 +02:00
* @ 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 mailbox identifier
* @ param boolean $_returnFullHTML flag wether to return HTML or data array
2016-05-03 21:17:44 +02:00
* @ return array | string data array or html or empty string
2013-06-17 16:25:20 +02:00
*/
2013-10-16 13:25:46 +02:00
static function createAttachmentBlock ( $attachments , $rowID , $uid , $mailbox , $_returnFullHTML = false )
2013-06-17 16:25:20 +02:00
{
$attachmentHTMLBlock = '' ;
2014-07-16 18:34:15 +02:00
$attachmentHTML = array ();
2017-07-04 13:17:33 +02:00
// skip message/delivery-status and set a title for original eml file
if (( $attachments [ 0 ][ 'mimeType' ] === 'message/delivery-status' ))
{
unset ( $attachments [ 0 ]);
if ( is_array ( $attachments ))
{
$attachments = array_values ( $attachments );
$attachments [ 0 ][ 'name' ] = lang ( 'Original Email Content' );
}
}
2013-06-17 16:25:20 +02:00
if ( is_array ( $attachments ) && count ( $attachments ) > 0 ) {
foreach ( $attachments as $key => $value )
{
2017-08-31 17:33:23 +02:00
if ( Mail\Smime :: isSmime ( $value [ 'mimeType' ])) continue ;
2014-07-29 10:13:34 +02:00
$attachmentHTML [ $key ][ 'filename' ] = ( $value [ 'name' ] ? ( $value [ 'filename' ] ? $value [ 'filename' ] : $value [ 'name' ] ) : lang ( '(no subject)' ));
2016-05-03 21:17:44 +02:00
$attachmentHTML [ $key ][ 'filename' ] = Api\Translation :: convert_jsonsafe ( $attachmentHTML [ $key ][ 'filename' ], 'utf-8' );
2015-03-24 12:40:06 +01:00
//error_log(array2string($value));
2016-05-03 21:17:44 +02:00
//error_log(strtoupper($value['mimeType']) .'<->'. Api\MimeMagic::filename2mime($attachmentHTML[$key]['filename']));
2021-03-11 14:56:26 +01:00
if ( strtoupper ( $value [ 'mimeType' ]) == 'APPLICATION/OCTET-STREAM' ) $value [ 'mimeType' ] = Api\MimeMagic :: filename2mime ( $attachmentHTML [ $key ][ 'filename' ]);
2013-10-16 13:25:46 +02:00
$attachmentHTML [ $key ][ 'type' ] = $value [ 'mimeType' ];
2016-05-03 21:17:44 +02:00
$attachmentHTML [ $key ][ 'mimetype' ] = Api\MimeMagic :: mime2label ( $value [ 'mimeType' ]);
2015-03-27 15:51:41 +01:00
$hA = self :: splitRowID ( $rowID );
$uid = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
$acc_id = $hA [ 'profileID' ];
2015-03-25 18:48:24 +01:00
2016-05-03 21:17:44 +02:00
$attachmentHTML [ $key ][ 'mime_data' ] = Link :: set_data ( $value [ 'mimeType' ], 'EGroupware\\Api\\Mail::getAttachmentAccount' , array (
2015-03-25 18:48:24 +01:00
$acc_id , $mailbox , $uid , $value [ 'partID' ], $value [ 'is_winmail' ], true
));
2016-05-03 21:17:44 +02:00
$attachmentHTML [ $key ][ 'size' ] = Vfs :: hsize ( $value [ 'size' ]);
2013-06-17 16:25:20 +02:00
$attachmentHTML [ $key ][ 'attachment_number' ] = $key ;
2013-10-16 13:25:46 +02:00
$attachmentHTML [ $key ][ 'partID' ] = $value [ 'partID' ];
2015-03-24 12:40:06 +01:00
$attachmentHTML [ $key ][ 'mail_id' ] = $rowID ;
2013-10-16 13:25:46 +02:00
$attachmentHTML [ $key ][ 'winmailFlag' ] = $value [ 'is_winmail' ];
2017-07-13 12:26:39 +02:00
$attachmentHTML [ $key ][ 'smime_type' ] = $value [ 'smime_type' ];
2023-03-01 13:20:35 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'apps' ][ 'collabora' ]
&& $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'document_doubleclick_action' ] === 'collabora'
2023-03-15 20:46:28 +01:00
&& array_key_exists ( $value [ 'mimeType' ], filemanager_hooks :: getEditorPrefMimes () ? : []))
2023-03-01 13:20:35 +01:00
{
$attachmentHTML [ $key ][ 'actions' ] = 'collabora' ;
$attachmentHTML [ $key ][ 'actionsDefaultLabel' ] = 'Open with Collabora' ;
}
else
{
$attachmentHTML [ $key ][ 'actions' ] = 'downloadOneAsFile' ;
$attachmentHTML [ $key ][ 'actionsDefaultLabel' ] = 'Download' ;
}
2022-07-27 14:21:21 +02:00
2016-08-30 11:27:13 +02:00
// reset mode array as it should be considered differently for
// each attachment
$mode = array ();
2013-06-17 16:25:20 +02:00
switch ( strtoupper ( $value [ 'mimeType' ]))
{
case 'MESSAGE/RFC822' :
$linkData = array
(
'menuaction' => 'mail.mail_ui.displayMessage' ,
2015-03-24 12:40:06 +01:00
'mode' => 'display' , //message/rfc822 attachments should be opened in display mode
2013-06-17 16:25:20 +02:00
'id' => $rowID ,
'part' => $value [ 'partID' ],
'is_winmail' => $value [ 'is_winmail' ]
);
$windowName = 'displayMessage_' . $rowID . '_' . $value [ 'partID' ];
2016-05-03 21:17:44 +02:00
$linkView = " egw_openWindowCentered(' " . Egw :: link ( '/index.php' , $linkData ) . " ',' $windowName ',700,egw_getWindowOuterHeight()); " ;
2013-06-17 16:25:20 +02:00
break ;
case 'IMAGE/JPEG' :
case 'IMAGE/PNG' :
case 'IMAGE/GIF' :
case 'IMAGE/BMP' :
2016-08-30 11:27:13 +02:00
// set mode for media mimetypes because we need
// to structure a download url to be used maybe in expose.
$mode = array (
'mode' => 'save'
);
2013-06-17 16:25:20 +02:00
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
2016-05-03 21:17:44 +02:00
if ( ! empty ( $suffix )) $sfxMimeType = Api\MimeMagic :: ext2mime ( $suffix );
2013-06-17 16:25:20 +02:00
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' :
2016-08-30 11:27:13 +02:00
$linkData = array_merge ( array
2013-06-17 16:25:20 +02:00
(
'menuaction' => 'mail.mail_ui.getAttachment' ,
'id' => $rowID ,
'part' => $value [ 'partID' ],
2017-07-13 12:26:39 +02:00
'is_winmail' => $value [ 'is_winmail' ],
2013-06-17 16:25:20 +02:00
'mailbox' => base64_encode ( $mailbox ),
2017-07-13 12:26:39 +02:00
'smime_type' => $value [ 'smime_type' ]
2016-08-30 11:27:13 +02:00
) , $mode );
2013-06-17 16:25:20 +02:00
$windowName = 'displayAttachment_' . $uid ;
$reg = '800x600' ;
// handle calendar/vcard
if ( strtoupper ( $value [ 'mimeType' ]) == 'TEXT/CALENDAR' )
{
$windowName = 'displayEvent_' . $rowID ;
2016-05-03 21:17:44 +02:00
$reg2 = Link :: get_registry ( 'calendar' , 'view_popup' );
2016-05-02 12:22:58 +02:00
$attachmentHTML [ $key ][ 'popup' ] = ( ! empty ( $reg2 ) ? $reg2 : $reg );
2013-06-17 16:25:20 +02:00
}
if ( strtoupper ( $value [ 'mimeType' ]) == 'TEXT/X-VCARD' || strtoupper ( $value [ 'mimeType' ]) == 'TEXT/VCARD' )
{
$windowName = 'displayContact_' . $rowID ;
2016-05-03 21:17:44 +02:00
$reg2 = Link :: get_registry ( 'addressbook' , 'add_popup' );
2016-05-02 12:22:58 +02:00
$attachmentHTML [ $key ][ 'popup' ] = ( ! empty ( $reg2 ) ? $reg2 : $reg );
2013-06-17 16:25:20 +02:00
}
// apply to action
list ( $width , $height ) = explode ( 'x' ,( ! empty ( $reg2 ) ? $reg2 : $reg ));
2016-05-03 21:17:44 +02:00
$linkView = " egw_openWindowCentered(' " . Egw :: link ( '/index.php' , $linkData ) . " ',' $windowName ', $width , $height ); " ;
2013-06-17 16:25:20 +02:00
break ;
default :
$linkData = array
(
'menuaction' => 'mail.mail_ui.getAttachment' ,
'id' => $rowID ,
'part' => $value [ 'partID' ],
'is_winmail' => $value [ 'is_winmail' ],
'mailbox' => base64_encode ( $mailbox ),
2017-07-13 12:26:39 +02:00
'smime_type' => $value [ 'smime_type' ]
2013-06-17 16:25:20 +02:00
);
2016-05-03 21:17:44 +02:00
$linkView = " window.location.href = ' " . Egw :: link ( '/index.php' , $linkData ) . " '; " ;
2013-06-17 16:25:20 +02:00
break ;
}
2015-03-25 18:48:24 +01:00
// we either use mime_data for server-side supported mime-types or mime_url for client-side or download
if ( empty ( $attachmentHTML [ $key ][ 'mime_data' ]))
{
2016-05-03 21:17:44 +02:00
$attachmentHTML [ $key ][ 'mime_url' ] = Egw :: link ( '/index.php' , $linkData );
2015-03-25 18:48:24 +01:00
unset ( $attachmentHTML [ $key ][ 'mime_data' ]);
}
2015-03-24 12:40:06 +01:00
$attachmentHTML [ $key ][ 'windowName' ] = $windowName ;
2015-03-25 18:48:24 +01:00
2013-06-17 16:25:20 +02:00
//error_log(__METHOD__.__LINE__.$linkView);
2013-10-01 13:29:54 +02:00
$attachmentHTML [ $key ][ 'link_view' ] = '<a href="#" ." title="' . $attachmentHTML [ $key ][ 'filename' ] . '" onclick="' . $linkView . ' return false;"><b>' .
2015-07-20 18:41:50 +02:00
( $value [ 'name' ] ? $value [ 'name' ] : lang ( '(no subject)' )) .
2013-06-17 16:25:20 +02:00
'</b></a>' ;
$linkData = array
(
'menuaction' => 'mail.mail_ui.getAttachment' ,
'mode' => 'save' ,
'id' => $rowID ,
'part' => $value [ 'partID' ],
'is_winmail' => $value [ 'is_winmail' ],
'mailbox' => base64_encode ( $mailbox ),
2017-07-13 12:26:39 +02:00
'smime_type' => $value [ 'smime_type' ]
2013-06-17 16:25:20 +02:00
);
2016-05-03 21:17:44 +02:00
$attachmentHTML [ $key ][ 'link_save' ] = " <a href=' " . Egw :: link ( '/index.php' , $linkData ) . " ' title=' " . $attachmentHTML [ $key ][ 'filename' ] . " '> " . Api\Html :: image ( 'mail' , 'fileexport' ) . " </a> " ;
2022-07-27 14:21:21 +02:00
2021-04-26 14:18:57 +02:00
if ( ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'filemanager' ]) $attachmentHTML [ $key ][ 'no_vfs' ] = true ;
2013-06-17 16:25:20 +02:00
}
$attachmentHTMLBlock = " <table width='100%'> " ;
foreach (( array ) $attachmentHTML as $row )
{
2013-10-01 13:29:54 +02:00
$attachmentHTMLBlock .= " <tr><td><div class='useEllipsis'> " . $row [ 'link_view' ] . '</div></td>' ;
2013-06-17 16:25:20 +02:00
$attachmentHTMLBlock .= " <td> " . $row [ 'mimetype' ] . '</td>' ;
$attachmentHTMLBlock .= " <td> " . $row [ 'size' ] . '</td>' ;
$attachmentHTMLBlock .= " <td> " . $row [ 'link_save' ] . '</td></tr>' ;
}
$attachmentHTMLBlock .= " </table> " ;
}
2013-10-18 11:58:25 +02:00
if ( ! $_returnFullHTML )
{
foreach (( array ) $attachmentHTML as $ikey => $value )
{
unset ( $attachmentHTML [ $ikey ][ 'link_view' ]);
unset ( $attachmentHTML [ $ikey ][ 'link_save' ]);
}
}
2013-10-16 13:25:46 +02:00
return ( $_returnFullHTML ? $attachmentHTMLBlock : $attachmentHTML );
2013-06-17 16:25:20 +02:00
}
2013-10-03 18:09:25 +02:00
/**
2014-05-21 13:24:34 +02:00
* fetch vacation info from active Server using icServer object
2013-10-03 18:09:25 +02:00
*
2014-08-11 14:14:27 +02:00
* @ param array $cachedVacations an array of cached vacations for an user
2014-05-21 13:24:34 +02:00
* @ return array | boolean array with vacation on success or false on failure
2014-04-03 14:20:23 +02:00
*/
2014-08-11 14:14:27 +02:00
function gatherVacation ( $cachedVacations = array ())
2014-04-03 14:20:23 +02:00
{
2014-08-11 14:14:27 +02:00
$isVacationEnabled = $this -> mail_bo -> icServer -> acc_sieve_enabled && ( $this -> mail_bo -> icServer -> acc_sieve_host || $this -> mail_bo -> icServer -> acc_imap_host );
2014-04-03 14:20:23 +02:00
//error_log(__METHOD__.__LINE__.' Server:'.self::$icServerID.' Sieve Enabled:'.array2string($vacation));
2014-05-21 13:24:34 +02:00
2014-08-11 14:14:27 +02:00
if ( $isVacationEnabled )
2014-05-21 13:24:34 +02:00
{
2014-05-13 19:09:05 +02:00
$sieveServer = $this -> mail_bo -> icServer ;
2014-08-05 11:26:28 +02:00
try
{
2014-08-11 14:14:27 +02:00
$sieveServer -> retrieveRules ();
$vacation = $sieveServer -> getVacation ();
2014-08-11 16:16:26 +02:00
$cachedVacations = array ( $sieveServer -> acc_id => $vacation ) + ( array ) $cachedVacations ;
2014-08-11 14:14:27 +02:00
// Set vacation to the instance cache for particular account with expiration of one day
2016-05-03 21:17:44 +02:00
Api\Cache :: setCache ( Api\Cache :: INSTANCE , 'email' , 'vacationNotice' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ], $cachedVacations , 60 * 60 * 24 );
2014-08-11 16:16:26 +02:00
}
catch ( PEAR_Exception $ex )
{
2014-08-08 15:36:33 +02:00
$this -> callWizard ( $ex -> getMessage (), true , 'error' );
2014-08-05 11:26:28 +02:00
}
2014-04-03 14:20:23 +02:00
}
2014-05-13 19:09:05 +02:00
//error_log(__METHOD__.__LINE__.' Server:'.self::$icServerID.' Vacation retrieved:'.array2string($vacation));
2014-04-03 14:20:23 +02:00
return $vacation ;
}
/**
* gather Info on how to display the quota info
2016-05-03 21:17:44 +02:00
*
2017-03-13 10:49:32 +01:00
* @ param int $_usage amount of usage in Kb
* @ param int $_limit amount of limit in Kb
2017-03-10 11:22:51 +01:00
* @ return array returns an array of info used for quota
* array (
2017-03-13 10:49:32 +01:00
* class = > string ,
* text => string ,
* percent => string ,
* freespace => integer
2017-03-10 11:22:51 +01:00
* )
2013-10-03 18:09:25 +02:00
*/
function quotaDisplay ( $_usage , $_limit )
{
2017-03-10 11:22:51 +01:00
$percent = $_limit == 0 ? 100 : round (( $_usage * 100 ) / $_limit );
2017-03-13 10:49:32 +01:00
$limit = Mail :: show_readable_size ( $_limit * 1024 );
$usage = Mail :: show_readable_size ( $_usage * 1024 );
2013-10-03 18:09:25 +02:00
2017-03-10 11:22:51 +01:00
if ( $_limit > 0 )
{
$text = $usage . '/' . $limit ;
switch ( $percent )
{
2017-06-13 16:40:03 +02:00
case ( $percent > 90 ) :
2017-03-10 11:22:51 +01:00
$class = 'mail-index_QuotaRed' ;
break ;
2017-06-13 16:40:03 +02:00
case ( $percent > 80 ) :
2017-03-10 11:22:51 +01:00
$class = 'mail-index_QuotaYellow' ;
break ;
default :
$class = 'mail-index_QuotaGreen' ;
}
2013-10-03 18:09:25 +02:00
}
2017-03-10 11:22:51 +01:00
else
{
$text = $usage ;
$class = 'mail-index_QuotaGreen' ;
2013-10-03 18:09:25 +02:00
}
2017-03-10 11:22:51 +01:00
return array (
'class' => $class ,
'text' => lang ( 'Quota: %1' , $text ),
2017-03-13 10:49:32 +01:00
'percent' => $percent ,
'freespace' => $_limit * 1024 - $_usage * 1024
2017-03-10 11:22:51 +01:00
);
2013-10-03 18:09:25 +02:00
}
2013-06-12 13:50:30 +02:00
/**
* display image
*
* all params are passed as GET Parameters
*/
function displayImage ()
{
2021-04-13 13:23:09 +02:00
$uid = base64_decode ( $_GET [ 'uid' ]);
2013-06-12 13:50:30 +02:00
$cid = base64_decode ( $_GET [ 'cid' ]);
$partID = urldecode ( $_GET [ 'partID' ]);
if ( ! empty ( $_GET [ 'mailbox' ])) $mailbox = base64_decode ( $_GET [ 'mailbox' ]);
2013-11-10 21:53:51 +01:00
2013-06-12 13:50:30 +02:00
//error_log(__METHOD__.__LINE__.":$uid, $cid, $partID");
$this -> mail_bo -> reopen ( $mailbox );
2013-11-10 21:53:51 +01:00
$attachment = $this -> mail_bo -> getAttachmentByCID ( $uid , $cid , $partID , true ); // true get contents as stream
2013-06-12 13:50:30 +02:00
$this -> mail_bo -> closeConnection ();
$GLOBALS [ 'egw' ] -> session -> commit_session ();
2013-11-10 21:53:51 +01:00
if ( $attachment )
{
2014-07-16 15:42:36 +02:00
header ( " Content-Type: " . $attachment -> getType ());
2013-11-10 21:53:51 +01:00
header ( 'Content-Disposition: inline; filename="' . $attachment -> getDispositionParameter ( 'filename' ) . '"' );
2014-02-04 13:31:11 +01:00
//header("Expires: 0");
2013-06-12 13:50:30 +02:00
// the next headers are for IE and SSL
2014-02-04 13:31:11 +01:00
//header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
//header("Pragma: public");
2016-05-03 21:17:44 +02:00
Api\Session :: cache_control ( true );
2013-11-10 21:53:51 +01:00
echo $attachment -> getContents ();
2013-06-12 13:50:30 +02:00
}
2013-11-10 21:53:51 +01:00
else
{
// send a 404 Not found
header ( " HTTP/1.1 404 Not found " );
}
2016-05-03 21:17:44 +02:00
exit ();
2013-06-12 13:50:30 +02:00
}
function getAttachment ()
{
if ( isset ( $_GET [ 'id' ])) $rowID = $_GET [ 'id' ];
$hA = self :: splitRowID ( $rowID );
$uid = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
2014-11-06 14:11:44 +01:00
$icServerID = $hA [ 'profileID' ];
$rememberServerID = $this -> mail_bo -> profileID ;
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2013-06-12 13:50:30 +02:00
$part = $_GET [ 'part' ];
$is_winmail = $_GET [ 'is_winmail' ] ? $_GET [ 'is_winmail' ] : 0 ;
$this -> mail_bo -> reopen ( $mailbox );
2017-07-19 18:16:22 +02:00
$attachment = $this -> mail_bo -> getAttachment ( $uid , $part , $is_winmail , false );
2013-06-12 13:50:30 +02:00
$this -> mail_bo -> closeConnection ();
2014-11-06 14:11:44 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile back to where we came from->'.$rememberServerID);
$this -> changeProfile ( $rememberServerID );
}
2013-06-12 13:50:30 +02:00
$GLOBALS [ 'egw' ] -> session -> commit_session ();
2014-02-10 14:24:08 +01:00
//error_log(__METHOD__.print_r($_GET,true));
2013-06-12 13:50:30 +02:00
if ( $_GET [ 'mode' ] != " save " )
{
2014-02-10 14:24:08 +01:00
if ( strtoupper ( $attachment [ 'type' ]) == 'TEXT/DIRECTORY' || empty ( $attachment [ 'type' ]))
2013-06-12 13:50:30 +02:00
{
$sfxMimeType = $attachment [ 'type' ];
$buff = explode ( '.' , $attachment [ 'filename' ]);
$suffix = '' ;
if ( is_array ( $buff )) $suffix = array_pop ( $buff ); // take the last extension to check with ext2mime
2016-05-03 21:17:44 +02:00
if ( ! empty ( $suffix )) $sfxMimeType = Api\MimeMagic :: ext2mime ( $suffix );
2013-06-12 13:50:30 +02:00
$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 ();
2021-11-15 17:57:06 +01:00
$event = $calendar_ical -> importVCal ( $attachment [ 'attachment' ], - 1 , null , true , 0 , '' , null , $attachment [ 'charset' ]);
2013-06-12 13:50:30 +02:00
//error_log(__METHOD__.$event);
if (( int ) $event > 0 )
{
$vars = array (
'menuaction' => 'calendar.calendar_uiforms.edit' ,
'cal_id' => $event ,
);
2016-05-03 21:17:44 +02:00
Egw :: redirect_link ( '../index.php' , $vars );
2013-06-12 13:50:30 +02:00
}
//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' ]);
2016-04-29 09:51:13 +02:00
$vcard = $addressbook_vcal -> vcardtoegw ( $attachment [ 'attachment' ], $attachment [ 'charset' ]);
2013-06-12 13:50:30 +02:00
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 )
{
2016-04-29 09:51:13 +02:00
$contact = $addressbook_vcal -> addVCard ( $attachment [ 'attachment' ],( is_array ( $contact ) ? array_shift ( $contact ) : $contact ), true , $attachment [ 'charset' ]);
2013-06-12 13:50:30 +02:00
}
if (( int ) $contact > 0 )
{
$vars = array (
'menuaction' => 'addressbook.addressbook_ui.edit' ,
'contact_id' => $contact ,
);
2016-05-03 21:17:44 +02:00
Egw :: redirect_link ( '../index.php' , $vars );
2013-06-12 13:50:30 +02:00
}
//Import failed, download content anyway
}
}
2014-02-10 14:24:08 +01:00
//error_log(__METHOD__.__LINE__.'->'.array2string($attachment));
2014-02-12 11:56:44 +01:00
$filename = ( $attachment [ 'name' ] ? $attachment [ 'name' ] : ( $attachment [ 'filename' ] ? $attachment [ 'filename' ] : $mailbox . '_uid' . $uid . '_part' . $part ));
2021-03-30 20:34:34 +02:00
$size = 0 ;
Api\Header\Content :: safe ( $attachment [ 'attachment' ], $filename , $attachment [ 'type' ], $size , True , $_GET [ 'mode' ] == " save " );
2013-06-12 13:50:30 +02:00
echo $attachment [ 'attachment' ];
2016-05-03 21:17:44 +02:00
exit ();
2013-06-12 13:50:30 +02:00
}
2013-02-28 10:28:08 +01:00
/**
* 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' ];
2014-07-16 18:34:15 +02:00
if ( isset ( $_GET [ 'part' ])) $partID = $_GET [ 'part' ];
2013-02-28 10:28:08 +01:00
if ( isset ( $_GET [ 'location' ]) && ( $_GET [ 'location' ] == 'display' || $_GET [ 'location' ] == 'filemanager' )) $display = $_GET [ 'location' ];
2013-03-05 15:09:35 +01:00
$hA = self :: splitRowID ( $rowID );
2013-02-28 10:28:08 +01:00
$uid = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
2014-11-06 14:11:44 +01:00
$icServerID = $hA [ 'profileID' ];
$rememberServerID = $this -> mail_bo -> profileID ;
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2013-02-28 10:28:08 +01:00
$this -> mail_bo -> reopen ( $mailbox );
2014-02-05 10:24:46 +01:00
$message = $this -> mail_bo -> getMessageRawBody ( $uid , $partID , $mailbox );
2013-02-28 10:28:08 +01:00
$this -> mail_bo -> closeConnection ();
2014-11-06 14:11:44 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile back to where we came from ->'.$rememberServerID);
$this -> changeProfile ( $rememberServerID );
}
2013-02-28 10:28:08 +01:00
$GLOBALS [ 'egw' ] -> session -> commit_session ();
2021-03-30 20:34:34 +02:00
$headers = Horde_Mime_Headers :: parseHeaders ( $message );
$subject = str_replace ( '$$' , '__' , Mail :: decode_header ( $headers [ 'SUBJECT' ]));
2015-02-14 20:32:21 +01:00
if ( ! $display )
2013-02-28 10:28:08 +01:00
{
2020-06-09 22:19:21 +02:00
$subject = Api\Mail :: clean_subject_for_filename ( $subject );
2021-03-30 20:34:34 +02:00
$mime = 'message/rfc822' ;
Api\Header\Content :: safe ( $message , $subject . " .eml " , $mime );
2013-02-28 10:28:08 +01:00
echo $message ;
}
else
{
2020-06-09 22:19:21 +02:00
$subject = Api\Mail :: clean_subject_for_filename ( $subject );
2023-01-31 23:03:18 +01:00
$mime = 'text/html' ;
$size = 0 ;
Api\Header\Content :: safe ( $message , $subject . " .eml " , $mime , $size , true , false );
print '<pre>' . htmlspecialchars ( $message , ENT_NOQUOTES | ENT_SUBSTITUTE , 'utf-8' ) . '</pre>' ;
2013-02-28 10:28:08 +01:00
}
}
2023-01-31 23:03:18 +01:00
/**
* Ajax function to save message ( s ) / attachment ( s ) in the vfs
*
* @ param string $attachment_id
* @ param string $filename
*
* @ return string Temporary path to open
*/
function ajax_vfsOpen ( $attachment_id , $filename )
{
// Use a sub-dir so we can give a nice filename
$temp_path = '/home/' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ] . " /.mail/ " ;
if ( ! Vfs :: is_dir ( $temp_path ))
{
Vfs :: mkdir ( $temp_path );
}
$result = $this -> vfsSaveAttachments ([ $attachment_id ], $temp_path . $filename , 'rename' );
$response = Api\Json\Response :: get ();
$response -> data ( $result [ 'savepath' ][ $attachment_id ] ? ? " " );
}
2017-10-12 13:19:42 +02:00
/**
2017-11-08 19:07:04 +01:00
* Ajax function to save message ( s ) / attachment ( s ) in the vfs
2017-10-12 13:19:42 +02:00
*
2017-11-08 19:07:04 +01:00
* @ param array $params array of mail ids and action name
2023-01-31 23:03:18 +01:00
* params = array (
* ids => array of string
* action => string
* )
2017-10-12 13:19:42 +02:00
* @ param string $path path to save the emails
2019-12-18 16:31:54 +01:00
* @ param string $submit_button_id dialog button id of triggered submit
* @ param string $savemode save mode : 'overwrite' or 'rename'
2017-10-12 13:19:42 +02:00
*/
2020-01-07 16:31:57 +01:00
function ajax_vfsSave ( $params , $path , $submit_button_id = '' , $savemode = 'rename' )
2017-10-12 13:19:42 +02:00
{
2019-12-18 16:31:54 +01:00
unset ( $submit_button_id ); // not used here
2017-10-12 13:19:42 +02:00
$response = Api\Json\Response :: get ();
2017-11-08 19:07:04 +01:00
switch ( $params [ 'action' ])
{
case 'message' :
2019-12-18 16:31:54 +01:00
$result = $this -> vfsSaveMessages ( $params [ 'ids' ], $path , $savemode );
2017-11-08 19:07:04 +01:00
break ;
case 'attachment' :
2019-12-18 16:31:54 +01:00
$result = $this -> vfsSaveAttachments ( $params [ 'ids' ], $path , $savemode );
2017-11-08 19:07:04 +01:00
break ;
}
$response -> call ( 'app.mail.vfsSaveCallback' , $result );
2017-10-12 13:19:42 +02:00
}
2013-03-05 15:09:35 +01:00
/**
2017-11-08 19:07:04 +01:00
* Save Message ( s ) in the vfs
2013-03-05 15:09:35 +01:00
*
* @ param string | array $ids use splitRowID , to separate values
2016-05-03 21:17:44 +02:00
* @ param string $path path in vfs ( no Vfs :: PREFIX ! ), only directory for multiple id ' s ( $ids is an array )
2019-12-18 16:31:54 +01:00
* @ param string $savemode save mode : 'overwrite' or 'rename'
2017-11-08 19:07:04 +01:00
*
* @ return array returns an array including message and success result
* array (
* 'msg' => STRING ,
* 'success' => BOOLEAN
* )
2013-03-05 15:09:35 +01:00
*/
2020-01-07 16:31:57 +01:00
function vfsSaveMessages ( $ids , $path , $savemode = 'rename' )
2013-03-05 15:09:35 +01:00
{
2017-11-08 19:07:04 +01:00
// add mail translation
Api\Translation :: add_app ( 'mail' );
$res = array ();
2013-04-12 11:22:23 +02:00
2017-11-08 19:07:04 +01:00
// extract dir from the path
$dir = Vfs :: is_dir ( $path ) ? $path : Vfs :: dirname ( $path );
// exit if user has no right to the dir
if ( ! Vfs :: is_writable ( $dir ))
2013-03-05 15:09:35 +01:00
{
2017-11-08 19:07:04 +01:00
return array (
'msg' => lang ( '%1 is NOT writable by you!' , $path ),
'success' => false
);
2013-03-05 15:09:35 +01:00
}
2014-10-17 00:41:39 +02:00
2017-11-08 19:07:04 +01:00
$preservedServerID = $this -> mail_bo -> profileID ;
2013-03-05 15:09:35 +01:00
foreach (( array ) $ids as $id )
{
$hA = self :: splitRowID ( $id );
$uid = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
2014-11-06 14:11:44 +01:00
$icServerID = $hA [ 'profileID' ];
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $icServerID );
}
2014-02-05 10:24:46 +01:00
$message = $this -> mail_bo -> getMessageRawBody ( $uid , $partID = '' , $mailbox );
2017-11-08 19:07:04 +01:00
// is multiple messages
if ( Vfs :: is_dir ( $path ))
2014-10-17 00:41:39 +02:00
{
$headers = $this -> mail_bo -> getMessageHeader ( $uid , $partID , true , false , $mailbox );
2020-06-09 22:19:21 +02:00
$file = $dir . '/' . Api\Mail :: clean_subject_for_filename ( $headers [ 'SUBJECT' ]) . '.eml' ;
2014-10-17 00:41:39 +02:00
}
else
{
2020-06-09 22:19:21 +02:00
$file = $dir . '/' . Api\Mail :: clean_subject_for_filename ( str_replace ( $dir . '/' , '' , $path ));
2014-10-17 00:41:39 +02:00
}
2017-11-08 19:07:04 +01:00
2019-12-18 16:31:54 +01:00
if ( $savemode != 'overwrite' )
2017-11-08 19:07:04 +01:00
{
2019-12-18 16:31:54 +01:00
// Check if file already exists, then try to assign a none existance filename
$counter = 1 ;
2017-11-08 19:07:04 +01:00
$tmp_file = $file ;
2019-12-18 16:31:54 +01:00
while ( Vfs :: file_exists ( $tmp_file ))
{
$tmp_file = $file ;
$pathinfo = pathinfo ( Vfs :: basename ( $tmp_file ));
$tmp_file = $dir . '/' . $pathinfo [ 'filename' ] . '(' . $counter . ')' . '.' . $pathinfo [ 'extension' ];
$counter ++ ;
}
$file = $tmp_file ;
2017-11-08 19:07:04 +01:00
}
2021-11-13 17:30:57 +01:00
if ( ! is_string ( $message ) || ! ( $fp = Vfs :: fopen ( $file , 'wb' )) || ! fwrite ( $fp , $message ))
2013-03-05 15:09:35 +01:00
{
2017-11-08 19:07:04 +01:00
$res [ 'msg' ] = lang ( 'Error saving %1!' , $file );
$res [ 'success' ] = false ;
2013-08-21 12:47:20 +02:00
}
else
{
2017-11-08 19:07:04 +01:00
$res [ 'success' ] = true ;
2013-03-05 15:09:35 +01:00
}
if ( $fp ) fclose ( $fp );
2017-11-08 19:07:04 +01:00
if ( $res [ 'success' ])
2013-08-21 12:47:20 +02:00
{
unset ( $headers [ 'SUBJECT' ]); //already in filename
2016-03-28 20:51:38 +02:00
$infoSection = Mail :: createHeaderInfoSection ( $headers , 'SUPPRESS' , false );
2013-08-21 12:47:20 +02:00
$props = array ( array ( 'name' => 'comment' , 'val' => $infoSection ));
2016-05-03 21:17:44 +02:00
Vfs :: proppatch ( $file , $props );
2013-08-21 12:47:20 +02:00
}
2013-03-05 15:09:35 +01:00
}
2017-11-08 19:07:04 +01:00
if ( $preservedServerID != $this -> mail_bo -> profileID )
2014-11-06 14:11:44 +01:00
{
2017-11-08 19:07:04 +01:00
//change Profile back to where we came from
$this -> changeProfile ( $preservedServerID );
2014-11-06 14:11:44 +01:00
}
2017-11-08 19:07:04 +01:00
return $res ;
2013-04-12 11:22:23 +02:00
}
2013-07-15 15:37:28 +02:00
/**
2017-11-08 19:07:04 +01:00
* Save attachment ( s ) in the vfs
2013-07-15 15:37:28 +02:00
*
* @ param string | array $ids '::' delimited mailbox :: uid :: part - id :: is_winmail :: name ( :: name for multiple id ' s )
2016-05-03 21:17:44 +02:00
* @ param string $path path in vfs ( no Vfs :: PREFIX ! ), only directory for multiple id ' s ( $ids is an array )
2019-12-18 16:31:54 +01:00
* @ param string $savemode save mode : 'overwrite' or 'rename'
2017-11-08 19:07:04 +01:00
*
* @ return array returns an array including message and success result
* array (
* 'msg' => STRING ,
* 'success' => BOOLEAN
* )
2013-07-15 15:37:28 +02:00
*/
2020-01-07 16:31:57 +01:00
function vfsSaveAttachments ( $ids , $path , $savemode = 'rename' )
2013-07-15 15:37:28 +02:00
{
2017-11-08 19:07:04 +01:00
$res = array (
2018-05-30 19:43:41 +02:00
'msg' => lang ( 'Attachment has been saved successfully.' ),
2017-11-08 19:07:04 +01:00
'success' => true
);
2016-03-09 13:31:55 +01:00
2017-12-18 11:27:23 +01:00
if ( Vfs :: is_dir ( $path ))
{
$dir = $path ;
}
else
{
$dir = Vfs :: dirname ( $path );
2018-01-15 19:52:15 +01:00
// Need to deal with any ? here, or basename will truncate
2020-06-09 22:19:21 +02:00
$filename = Api\Mail :: clean_subject_for_filename ( str_replace ( '?' , '_' , Vfs :: basename ( $path )));
2017-12-18 11:27:23 +01:00
}
2017-11-08 19:07:04 +01:00
if ( ! Vfs :: is_writable ( $dir ))
2013-07-15 15:37:28 +02:00
{
2017-11-08 19:07:04 +01:00
return array (
'msg' => lang ( '%1 is NOT writable by you!' , $path ),
'success' => false
);
2013-07-15 15:37:28 +02:00
}
2017-11-08 19:07:04 +01:00
$preservedServerID = $this -> mail_bo -> profileID ;
2016-03-09 13:31:55 +01:00
2015-12-02 12:10:26 +01:00
/**
* Extract all parameteres from the given id
* @ param int $id message id ( '::' delimited mailbox :: uid :: part - id :: is_winmail :: name )
*
* @ return array an array of parameters
*/
$getParams = function ( $id ) {
2013-07-15 15:37:28 +02:00
list ( $app , $user , $serverID , $mailbox , $uid , $part , $is_winmail , $name ) = explode ( '::' , $id , 8 );
$lId = implode ( '::' , array ( $app , $user , $serverID , $mailbox , $uid ));
2016-01-12 14:37:36 +01:00
$hA = mail_ui :: splitRowID ( $lId );
2015-12-02 12:10:26 +01:00
return array (
'is_winmail' => $is_winmail == " null " || ! $is_winmail ? false : $is_winmail ,
'user' => $user ,
'name' => $name ,
'part' => $part ,
'uid' => $hA [ 'msgUID' ],
'mailbox' => $hA [ 'folder' ],
'icServer' => $hA [ 'profileID' ]
);
};
2016-03-09 13:31:55 +01:00
2015-12-02 12:10:26 +01:00
//Examine the first attachment to see if attachment
//is winmail.dat embedded attachments.
2016-01-12 16:11:41 +01:00
$p = $getParams (( is_array ( $ids ) ? $ids [ 0 ] : $ids ));
2015-12-02 12:10:26 +01:00
if ( $p [ 'is_winmail' ])
{
if ( $p [ 'icServer' ] && $p [ 'icServer' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $p [ 'icServer' ]);
}
$this -> mail_bo -> reopen ( $p [ 'mailbox' ]);
2017-05-08 10:07:32 +02:00
// retrieve all embedded attachments at once
2015-12-02 12:10:26 +01:00
// avoids to fetch heavy winmail.dat content
// for each file.
2019-02-22 11:00:47 +01:00
$attachments = $this -> mail_bo -> getTnefAttachments ( $p [ 'uid' ], $p [ 'part' ], false , $p [ 'mailbox' ]);
2015-12-02 12:10:26 +01:00
}
2016-01-12 16:11:41 +01:00
2015-12-02 12:10:26 +01:00
foreach (( array ) $ids as $id )
{
$params = $getParams ( $id );
2017-11-08 19:07:04 +01:00
2015-12-02 12:10:26 +01:00
if ( $params [ 'icServer' ] && $params [ 'icServer' ] != $this -> mail_bo -> profileID )
2014-11-06 14:11:44 +01:00
{
2015-12-02 12:10:26 +01:00
$this -> changeProfile ( $params [ 'icServer' ]);
2014-11-06 14:11:44 +01:00
}
2015-12-02 12:10:26 +01:00
$this -> mail_bo -> reopen ( $params [ 'mailbox' ]);
2017-11-08 19:07:04 +01:00
// is multiple attachments
if ( Vfs :: is_dir ( $path ) || $params [ 'is_winmail' ])
2015-12-02 12:10:26 +01:00
{
2017-11-08 19:07:04 +01:00
if ( $params [ 'is_winmail' ])
2015-12-02 12:10:26 +01:00
{
2017-11-08 19:07:04 +01:00
// Try to find the right content for file id
foreach ( $attachments as $key => $val )
{
if ( $key == $params [ 'is_winmail' ]) $attachment = $val ;
}
}
else
{
$attachment = $this -> mail_bo -> getAttachment ( $params [ 'uid' ], $params [ 'part' ], $params [ 'is_winmail' ], false );
2015-12-02 12:10:26 +01:00
}
}
else
{
$attachment = $this -> mail_bo -> getAttachment ( $params [ 'uid' ], $params [ 'part' ], $params [ 'is_winmail' ], false );
}
2015-10-26 20:25:01 +01:00
2020-07-27 08:07:45 +02:00
$file = $dir . '/' . ( $filename ? $filename : Mail :: clean_subject_for_filename ( $attachment [ 'filename' ]));
2017-11-08 19:07:04 +01:00
2019-12-18 16:31:54 +01:00
if ( $savemode != 'overwrite' )
2015-10-26 20:25:01 +01:00
{
2019-12-18 16:31:54 +01:00
$counter = 1 ;
2017-11-08 19:07:04 +01:00
$tmp_file = $file ;
2019-12-18 16:31:54 +01:00
while ( Vfs :: file_exists ( $tmp_file ))
{
$tmp_file = $file ;
$pathinfo = pathinfo ( Vfs :: basename ( $tmp_file ));
$tmp_file = $dir . '/' . $pathinfo [ 'filename' ] . '(' . $counter . ')' . '.' . $pathinfo [ 'extension' ];
$counter ++ ;
}
$file = $tmp_file ;
2017-11-08 19:07:04 +01:00
}
if ( ! ( $fp = Vfs :: fopen ( $file , 'wb' )) ||
2013-07-15 15:37:28 +02:00
! fwrite ( $fp , $attachment [ 'attachment' ]))
{
2017-11-08 19:07:04 +01:00
$res [ 'msg' ] = lang ( 'Error saving %1!' , $file );
$res [ 'success' ] = false ;
2013-07-15 15:37:28 +02:00
}
2015-10-26 20:25:01 +01:00
if ( $fp )
{
fclose ( $fp );
}
2023-01-31 23:03:18 +01:00
$res [ 'savepath' ][ $id ] = $file ;
2013-07-15 15:37:28 +02:00
}
2017-11-08 19:07:04 +01:00
2013-07-15 15:37:28 +02:00
$this -> mail_bo -> closeConnection ();
2017-11-08 19:07:04 +01:00
if ( $preservedServerID != $this -> mail_bo -> profileID )
2014-11-06 14:11:44 +01:00
{
2017-11-08 19:07:04 +01:00
//change Profile back to where we came from
$this -> changeProfile ( $preservedServerID );
2014-11-06 14:11:44 +01:00
}
2017-11-08 19:07:04 +01:00
return $res ;
2013-07-15 15:37:28 +02:00
}
2014-07-03 18:57:14 +02:00
/**
* Zip all attachments and send to user
2014-07-16 18:34:15 +02:00
* @ param string $message_id = null
2014-07-03 18:57:14 +02:00
*/
2014-07-08 14:01:29 +02:00
function download_zip ( $message_id = null )
2014-07-03 18:57:14 +02:00
{
2014-11-06 12:42:44 +01:00
//error_log(__METHOD__.__LINE__.array2string($_GET));
2014-07-03 18:57:14 +02:00
// First, get all attachment IDs
2014-07-08 14:01:29 +02:00
if ( isset ( $_GET [ 'id' ])) $message_id = $_GET [ 'id' ];
//error_log(__METHOD__.__LINE__.$message_id);
2014-11-06 14:11:44 +01:00
$rememberServerID = $this -> mail_bo -> profileID ;
2014-07-03 19:17:54 +02:00
if ( ! is_numeric ( $message_id ))
{
$hA = self :: splitRowID ( $message_id );
$message_id = $hA [ 'msgUID' ];
$mailbox = $hA [ 'folder' ];
2014-11-06 14:11:44 +01:00
$icServerID = $hA [ 'profileID' ];
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2014-07-03 19:17:54 +02:00
}
else
{
$mailbox = $this -> mail_bo -> sessionData [ 'mailbox' ];
}
2014-11-06 12:42:44 +01:00
// always fetch all, even inline (images)
$fetchEmbeddedImages = true ;
$attachments = $this -> mail_bo -> getMessageAttachments ( $message_id , null , null , $fetchEmbeddedImages , true , true , $mailbox );
2014-07-03 18:57:14 +02:00
// put them in VFS so they can be zipped
2014-07-08 12:20:19 +02:00
$header = $this -> mail_bo -> getMessageHeader ( $message_id , '' , true , false , $mailbox );
2014-08-26 14:37:27 +02:00
//get_home_dir may fetch the users startfolder if set; if not writeable, action will fail. TODO: use temp_dir
$homedir = '/home/' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ];
2016-05-03 21:17:44 +02:00
$temp_path = $homedir /*Vfs::get_home_dir()*/ . " /.mail_ $message_id " ;
if ( Vfs :: is_dir ( $temp_path )) Vfs :: remove ( $temp_path );
2014-07-03 18:57:14 +02:00
2017-03-01 17:58:56 +01:00
// Add subject to path, so it gets used as the file name, replacing ':'
// as it seems to cause an error
2020-07-20 23:42:05 +02:00
$path = $temp_path . '/' . ( $header [ 'SUBJECT' ] ? Vfs :: encodePathComponent ( Api\Mail :: clean_subject_for_filename ( str_replace ( ':' , '-' , $header [ 'SUBJECT' ]))) : lang ( 'mail' )) . '/' ;
2016-05-03 21:17:44 +02:00
if ( ! Vfs :: mkdir ( $path , 0700 , true ))
2014-07-03 18:57:14 +02:00
{
2017-03-01 17:58:56 +01:00
echo " Unable to open temp directory $path " ;
2014-07-03 18:57:14 +02:00
return ;
}
$file_list = array ();
2015-10-20 01:45:38 +02:00
$dupe_count = array ();
2014-07-03 19:17:54 +02:00
$this -> mail_bo -> reopen ( $mailbox );
2015-12-02 15:00:34 +01:00
if ( $attachments [ 0 ][ 'is_winmail' ] && $attachments [ 0 ][ 'is_winmail' ] != 'null' )
{
2019-02-22 11:00:47 +01:00
$tnefAttachments = $this -> mail_bo -> getTnefAttachments ( $message_id , $attachments [ 0 ][ 'partID' ], true , $mailbox );
2015-12-02 15:00:34 +01:00
}
2014-07-03 18:57:14 +02:00
foreach ( $attachments as $file )
{
2015-12-02 15:00:34 +01:00
if ( $file [ 'is_winmail' ])
{
// Try to find the right content for file id
foreach ( $tnefAttachments as $key => $val )
{
error_log ( __METHOD__ . ' winmail = ' . $key );
if ( $key == $file [ 'is_winmail' ]) $attachment = $val ;
}
}
else
{
$attachment = $this -> mail_bo -> getAttachment ( $message_id , $file [ 'partID' ], $file [ 'is_winmail' ], false , true );
}
2014-11-06 12:42:44 +01:00
$success = true ;
2014-12-08 19:24:08 +01:00
if ( empty ( $file [ 'filename' ])) $file [ 'filename' ] = $file [ 'name' ];
2015-10-20 01:45:38 +02:00
if ( in_array ( $path . $file [ 'filename' ], $file_list ))
{
$dupe_count [ $path . $file [ 'filename' ]] ++ ;
$file [ 'filename' ] = pathinfo ( $file [ 'filename' ], PATHINFO_FILENAME ) .
' (' . ( $dupe_count [ $path . $file [ 'filename' ]] + 1 ) . ')' . '.' .
pathinfo ( $file [ 'filename' ], PATHINFO_EXTENSION );
}
2017-03-15 16:20:06 +01:00
// Strip special characters to make sure the files are visible for all OS (windows has issues)
2020-06-09 22:19:21 +02:00
$target_name = Api\Mail :: clean_subject_for_filename ( iconv ( $file [ 'charset' ] ? $file [ 'charset' ] : $GLOBALS [ 'egw_info' ][ 'server' ][ 'system_charset' ], 'ASCII//IGNORE' , $file [ 'filename' ]));
2017-03-16 11:30:45 +01:00
2017-03-15 16:20:06 +01:00
if ( ! ( $fp = Vfs :: fopen ( $path . $target_name , 'wb' )) ||
2014-12-08 19:24:08 +01:00
! ( ! fseek ( $attachment [ 'attachment' ], 0 , SEEK_SET ) && stream_copy_to_stream ( $attachment [ 'attachment' ], $fp )))
2014-07-03 18:57:14 +02:00
{
2014-11-06 12:42:44 +01:00
$success = false ;
2017-03-15 16:20:06 +01:00
Framework :: message ( " Unable to zip { $target_name } " , 'error' );
2014-07-03 18:57:14 +02:00
}
2017-03-15 16:20:06 +01:00
if ( $success ) $file_list [] = $path . $target_name ;
2014-07-03 18:57:14 +02:00
if ( $fp ) fclose ( $fp );
}
$this -> mail_bo -> closeConnection ();
2014-11-06 14:11:44 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile back to where we came from ->'.$rememberServerID);
$this -> changeProfile ( $rememberServerID );
}
2014-07-08 13:09:31 +02:00
2014-07-03 18:57:14 +02:00
// Zip it up
2016-05-03 21:17:44 +02:00
Vfs :: download_zip ( $file_list );
2014-07-03 18:57:14 +02:00
// Clean up
2016-05-03 21:17:44 +02:00
Vfs :: remove ( $temp_path );
2014-07-08 13:09:31 +02:00
2016-05-03 21:17:44 +02:00
exit ();
2014-07-03 18:57:14 +02:00
}
2017-01-27 17:59:59 +01:00
function get_load_email_data ( $uid , $partID , $mailbox , $htmlOptions = null , $smimePassphrase = '' )
2013-04-12 15:10:27 +02:00
{
// 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 );
2014-07-16 15:42:36 +02:00
$this -> mailbox = $mailbox ;
$this -> uid = $uid ;
$this -> partID = $partID ;
2013-07-20 09:23:55 +02:00
$bufferHtmlOptions = $this -> mail_bo -> htmlOptions ;
if ( empty ( $htmlOptions )) $htmlOptions = $this -> mail_bo -> htmlOptions ;
2014-09-25 14:43:06 +02:00
// fetching structure now, to supply it to getMessageBody and getMessageAttachment, so it does not get fetched twice
2017-07-19 18:16:22 +02:00
try
2017-01-26 17:45:07 +01:00
{
2017-07-19 18:16:22 +02:00
if ( $smimePassphrase )
2017-01-26 17:45:07 +01:00
{
2017-07-25 17:13:49 +02:00
if ( $this -> mail_bo -> mailPreferences [ 'smime_pass_exp' ] != $_POST [ 'smime_pass_exp' ])
{
$GLOBALS [ 'egw' ] -> preferences -> add ( 'mail' , 'smime_pass_exp' , $_POST [ 'smime_pass_exp' ]);
$GLOBALS [ 'egw' ] -> preferences -> save_repository ();
}
2021-04-09 10:40:40 +02:00
Api\Cache :: setSession ( 'mail' , 'smime_passphrase' , $smimePassphrase , ( int )( $_POST [ 'smime_pass_exp' ] ? : 10 ) * 60 );
2017-01-26 17:45:07 +01:00
}
2017-07-19 18:16:22 +02:00
$structure = $this -> mail_bo -> getStructure ( $uid , $partID , $mailbox , false );
if (( $smime = $structure -> getMetadata ( 'X-EGroupware-Smime' )))
2017-01-27 17:59:59 +01:00
{
2020-05-07 17:39:02 +02:00
$smime [ 'msg' ] = lang ( $smime [ 'msg' ]);
2017-12-07 14:14:01 +01:00
$acc_smime = Mail\Smime :: get_acc_smime ( $this -> mail_bo -> profileID );
2023-06-20 11:37:48 +02:00
$attachments = $this -> mail_bo -> getMessageAttachments ( $uid , $partID , $structure , false , true , true , $mailbox );
2017-08-21 12:01:51 +02:00
$push = new Api\Json\Push ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]);
2017-12-07 14:14:01 +01:00
if ( ! empty ( $acc_smime ) && ! empty ( $smime [ 'addtocontact' ])) $push -> call ( 'app.mail.smime_certAddToContact' , $smime );
2017-07-19 18:16:22 +02:00
if ( is_array ( $attachments ))
{
$push -> call ( 'app.mail.set_smimeAttachments' , $this -> createAttachmentBlock ( $attachments , $_GET [ '_messageID' ], $uid , $mailbox ));
}
$push -> call ( 'app.mail.set_smimeFlags' , $smime );
2017-01-27 17:59:59 +01:00
}
2017-01-26 17:45:07 +01:00
}
2017-07-19 18:16:22 +02:00
catch ( Mail\Smime\PassphraseMissing $e )
{
2017-08-30 17:00:28 +02:00
$acc_smime = Mail\Smime :: get_acc_smime ( $this -> mail_bo -> profileID );
if ( empty ( $acc_smime ))
2017-07-21 12:34:22 +02:00
{
2021-04-13 16:13:24 +02:00
self :: callWizard ( $e -> getMessage () . ' ' . lang ( 'Please configure your S/MIME certificate in Encryption tab located at Edit Account dialog.' ), true , 'error' );
2017-07-21 12:34:22 +02:00
}
2017-07-25 17:13:49 +02:00
Framework :: message ( $e -> getMessage ());
2019-01-11 16:53:22 +01:00
$configs = Api\Config :: read ( 'mail' );
2017-07-19 18:16:22 +02:00
// do NOT include any default CSS
$smimeHtml = $this -> get_email_header () .
'<div class="smime-message">' . lang ( " This message is smime encrypted and password protected. " ) . '</div>' .
'<form id="smimePasswordRequest" method="post">' .
'<div class="bg-style"></div>' .
'<div>' .
'<input type="password" placeholder="' . lang ( " Please enter password " ) . '" name="smime_passphrase"/>' .
'<input type="submit" value="' . lang ( " submit " ) . '"/>' .
2017-08-29 15:42:49 +02:00
'<div style="margin-top:10px;position:relative;text-align:center;margin-left:-15px;">' .
2019-01-11 16:53:22 +01:00
lang ( " Remember the password for " ) .
'<input name="smime_pass_exp" type="number" max="480" min="1" placeholder="' .
( is_array ( $configs ) && $configs [ 'smime_pass_exp' ] ? $configs [ 'smime_pass_exp' ] : " 10 " ) .
'" value="' . $this -> mail_bo -> mailPreferences [ 'smime_pass_exp' ] . '"/> ' . lang ( " minutes. " ) .
2017-08-29 15:42:49 +02:00
'</div>' .
2017-07-25 17:13:49 +02:00
'</div>' .
'</form>' ;
2017-07-19 18:16:22 +02:00
return $smimeHtml ;
}
$calendar_part = null ;
$bodyParts = $this -> mail_bo -> getMessageBody ( $uid , ( $htmlOptions ? $htmlOptions : '' ), $partID , $structure , false , $mailbox , $calendar_part );
2018-06-26 15:57:09 +02:00
2016-08-23 17:22:03 +02:00
// for meeting requests (multipart alternative with text/calendar part) let calendar render it
2023-04-27 13:54:40 +02:00
if ( $calendar_part && isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'calendar' ]))
2016-08-23 17:22:03 +02:00
{
$charset = $calendar_part -> getContentTypeParameter ( 'charset' );
2021-06-24 14:05:43 +02:00
// Do not try to fetch raw part content if it's smime signed message
2023-04-27 13:54:40 +02:00
if ( empty ( $smime )) $this -> mail_bo -> fetchPartContents ( $uid , $calendar_part );
2022-07-26 14:13:17 +02:00
$headers = $this -> mail_bo -> getHeaders ( $mailbox , 0 , 1 , '' , false , null , $uid );
2016-08-23 17:22:03 +02:00
Api\Cache :: setSession ( 'calendar' , 'ical' , array (
2022-07-26 14:13:17 +02:00
'charset' => $charset ? : 'utf-8' ,
2016-08-23 17:22:03 +02:00
'attachment' => $calendar_part -> getContents (),
'method' => $calendar_part -> getContentTypeParameter ( 'method' ),
2022-07-26 14:13:17 +02:00
'sender' => empty ( $headers [ 'header' ][ 0 ][ 'sender_address' ]) ? null :
( preg_match ( '/<([^>]+?)>$/' , $sender = strtolower ( $headers [ 'header' ][ 0 ][ 'sender_address' ]), $matches ) ?
$matches [ 1 ] : $sender ),
2016-08-23 17:22:03 +02:00
));
$this -> mail_bo -> htmlOptions = $bufferHtmlOptions ;
Api\Translation :: add_app ( 'calendar' );
return ExecMethod ( 'calendar.calendar_uiforms.meeting' ,
array ( 'event' => null , 'msg' => '' , 'useSession' => true )
);
2013-04-12 15:10:27 +02:00
}
2018-06-26 15:57:09 +02:00
if ( ! $smime )
{
Api\Session :: cache_control ( true );
2020-01-28 17:45:36 +01:00
// more strict CSP for displaying mail
2020-01-29 14:40:30 +01:00
foreach ([ 'frame-src' , 'connect-src' , 'manifest-src' ] as $src )
2020-01-28 17:45:36 +01:00
{
Api\Header\ContentSecurityPolicy :: add ( $src , 'none' );
}
Api\Header\ContentSecurityPolicy :: add ( 'script-src' , 'self' , true ); // true = remove default 'unsafe-eval'
2020-01-29 14:40:30 +01:00
Api\Header\ContentSecurityPolicy :: add ( 'img-src' , 'http:' );
Api\Header\ContentSecurityPolicy :: add ( 'media-src' , [ 'https:' , 'http:' ]);
2018-06-26 15:57:09 +02:00
}
2013-04-12 15:10:27 +02:00
// Compose the content of the frame
$frameHtml =
2014-03-03 15:56:12 +01:00
$this -> get_email_header ( $this -> mail_bo -> getStyles ( $bodyParts )) .
2015-11-20 16:16:37 +01:00
$this -> showBody ( $this -> getdisplayableBody ( $bodyParts , true , false ), false );
2013-04-12 15:10:27 +02:00
//IE10 eats away linebreaks preceeded by a whitespace in PRE sections
$frameHtml = str_replace ( " \r \n " , " \r \n " , $frameHtml );
2013-07-20 09:23:55 +02:00
$this -> mail_bo -> htmlOptions = $bufferHtmlOptions ;
2013-04-12 15:10:27 +02:00
return $frameHtml ;
}
2014-03-03 15:56:12 +01:00
static function get_email_header ( $additionalStyle = '' )
2013-04-12 15:10:27 +02:00
{
2014-03-03 15:56:12 +01:00
// egw_info[flags][css] already include <style> tags
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'css' ] = preg_replace ( '|</?style[^>]*>|i' , '' , $additionalStyle );
2014-03-07 15:26:16 +01:00
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'nofooter' ] = true ;
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'nonavbar' ] = true ;
2014-03-03 15:56:12 +01:00
// do NOT include any default CSS
2016-05-03 21:17:44 +02:00
Framework :: includeCSS ( 'mail' , 'preview' , true , true );
2014-03-03 15:56:12 +01:00
// load preview.js to activate mailto links
2016-05-03 21:17:44 +02:00
Framework :: includeJS ( '/mail/js/preview.js' );
2014-03-03 15:56:12 +01:00
// send CSP and content-type header
return $GLOBALS [ 'egw' ] -> framework -> header ();
2013-04-12 15:10:27 +02:00
}
2013-06-05 16:24:56 +02:00
function showBody ( & $body , $print = true , $fullPageTags = true )
2013-04-12 15:10:27 +02:00
{
2014-03-04 11:48:35 +01:00
$BeginBody = ' < div class = " mailDisplayBody " >
2014-07-16 15:42:36 +02:00
< table width = " 100% " style = " table-layout:fixed " >< tr >< td class = " td_display " > ' ;
2013-04-12 15:10:27 +02:00
$EndBody = '</td></tr></table></div>' ;
2013-06-05 16:24:56 +02:00
if ( $fullPageTags ) $EndBody .= " </body></html> " ;
2013-04-12 15:10:27 +02:00
if ( $print ) {
print $BeginBody . $body . $EndBody ;
} else {
return $BeginBody . $body . $EndBody ;
}
}
2015-11-20 16:16:37 +01:00
function & getdisplayableBody ( $_bodyParts , $modifyURI = true , $useTidy = true )
2013-04-12 15:10:27 +02:00
{
$bodyParts = $_bodyParts ;
$nonDisplayAbleCharacters = array ( '[\016]' , '[\017]' ,
'[\020]' , '[\021]' , '[\022]' , '[\023]' , '[\024]' , '[\025]' , '[\026]' , '[\027]' ,
'[\030]' , '[\031]' , '[\032]' , '[\033]' , '[\034]' , '[\035]' , '[\036]' , '[\037]' );
$body = '' ;
//error_log(__METHOD__.array2string($bodyParts)); //exit;
2021-03-30 20:34:34 +02:00
if ( empty ( $bodyParts ))
{
$ret = '' ;
return $ret ;
}
2013-04-12 15:10:27 +02:00
foreach (( array ) $bodyParts as $singleBodyPart ) {
if ( ! isset ( $singleBodyPart [ 'body' ])) {
2015-11-20 16:16:37 +01:00
$singleBodyPart [ 'body' ] = $this -> getdisplayableBody ( $singleBodyPart , $modifyURI , $useTidy );
2013-04-12 15:10:27 +02:00
$body .= $singleBodyPart [ 'body' ];
continue ;
}
2013-09-10 15:39:44 +02:00
$bodyPartIsSet = strlen ( trim ( $singleBodyPart [ 'body' ]));
if ( ! $bodyPartIsSet )
{
$body .= '' ;
continue ;
}
2013-04-12 15:10:27 +02:00
if ( ! empty ( $body )) {
$body .= '<hr style="border:dotted 1px silver;">' ;
}
//error_log($singleBodyPart['body']);
//error_log(__METHOD__.__LINE__.' CharSet:'.$singleBodyPart['charSet'].' mimeType:'.$singleBodyPart['mimeType']);
// some characterreplacements, as they fail to translate
$sar = array (
'@(\x84|\x93|\x94)@' ,
'@(\x96|\x97|\x1a)@' ,
'@(\x82|\x91|\x92)@' ,
'@(\x85)@' ,
'@(\x86)@' ,
'@(\x99)@' ,
'@(\xae)@' ,
);
$rar = array (
'"' ,
'-' ,
'\'' ,
'...' ,
'&' ,
'(TM)' ,
'(R)' ,
);
if (( $singleBodyPart [ 'mimeType' ] == 'text/html' || $singleBodyPart [ 'mimeType' ] == 'text/plain' ) &&
strtoupper ( $singleBodyPart [ 'charSet' ]) != 'UTF-8' )
{
2019-03-29 16:50:33 +01:00
// check if client set a wrong charset and content is utf-8 --> use utf-8
if ( preg_match ( '//u' , $singleBodyPart [ 'body' ]))
{
$singleBodyPart [ 'charSet' ] = 'UTF-8' ;
}
else
{
$singleBodyPart [ 'body' ] = preg_replace ( $sar , $rar , $singleBodyPart [ 'body' ]);
}
2013-04-12 15:10:27 +02:00
}
2015-10-23 12:02:18 +02:00
//error_log(__METHOD__.__LINE__.'reports:'.$singleBodyPart['charSet']);
2016-08-05 15:12:21 +02:00
if ( $singleBodyPart [ 'charSet' ] == 'us-ascii' )
{
$orgCharSet = $singleBodyPart [ 'charSet' ];
$singleBodyPart [ 'charSet' ] = Api\Translation :: detect_encoding ( $singleBodyPart [ 'body' ]);
error_log ( __METHOD__ . __LINE__ . 'reports:' . $orgCharSet . ' but seems to be:' . $singleBodyPart [ 'charSet' ]);
}
2016-05-03 21:17:44 +02:00
$singleBodyPart [ 'body' ] = Api\Translation :: convert_jsonsafe ( $singleBodyPart [ 'body' ], $singleBodyPart [ 'charSet' ]);
2013-04-12 15:30:54 +02:00
//error_log(__METHOD__.__LINE__.array2string($singleBodyPart));
2013-04-12 15:10:27 +02:00
if ( $singleBodyPart [ 'mimeType' ] == 'text/plain' )
{
2016-03-28 20:51:38 +02:00
$newBody = @ htmlentities ( $singleBodyPart [ 'body' ], ENT_QUOTES , strtoupper ( Mail :: $displayCharset ));
2015-10-23 12:02:18 +02:00
//error_log(__METHOD__.__LINE__.'..'.$newBody);
2013-04-12 15:10:27 +02:00
// if empty and charset is utf8 try sanitizing the string in question
2016-03-28 20:51:38 +02:00
if ( empty ( $newBody ) && strtolower ( $singleBodyPart [ 'charSet' ]) == 'utf-8' ) $newBody = @ htmlentities ( iconv ( 'utf-8' , 'utf-8' , $singleBodyPart [ 'body' ]), ENT_QUOTES , strtoupper ( Mail :: $displayCharset ));
2013-04-12 15:10:27 +02:00
// if the conversion to htmlentities fails somehow, try without specifying the charset, which defaults to iso-
if ( empty ( $newBody )) $newBody = htmlentities ( $singleBodyPart [ 'body' ], ENT_QUOTES );
// search http[s] links and make them as links available again
// to understand what's going on here, have a look at
// http://www.php.net/manual/en/function.preg-replace.php
// create links for websites
2016-05-03 21:17:44 +02:00
if ( $modifyURI ) $newBody = Api\Html :: activate_links ( $newBody );
2013-04-12 15:10:27 +02:00
// create links for email addresses
// create links for inline images
if ( $modifyURI )
{
2015-05-15 16:00:37 +02:00
$newBody = self :: resolve_inline_images ( $newBody , $this -> mailbox , $this -> uid , $this -> partID , 'plain' );
2013-04-12 15:10:27 +02:00
}
// to display a mailpart of mimetype plain/text, may be better taged as preformatted
2016-03-28 20:51:38 +02:00
$newBody = " <pre> " . Mail :: wordwrap ( $newBody , 90 , " \n " , '>' ) . " </pre> " ;
2013-04-12 15:10:27 +02:00
}
else
{
2015-11-20 16:16:37 +01:00
$alreadyHtmlLawed = false ;
2013-04-12 15:10:27 +02:00
$newBody = $singleBodyPart [ 'body' ];
2024-09-24 13:46:44 +02:00
// remove script tags incl. their content, includes e.g. <script type="application/ld+json">
// before HtmLawed below only removes the script-tags but leaves the content
Mail\Html :: replaceTagsCompletley ( $newBody , 'script' );
2013-04-12 15:10:27 +02:00
//TODO:$newBody = $this->highlightQuotes($newBody);
#error_log(print_r($newBody,true));
2015-11-20 16:16:37 +01:00
if ( $useTidy && extension_loaded ( 'tidy' ))
2015-10-27 10:16:37 +01:00
{
$tidy = new tidy ();
2016-03-28 20:51:38 +02:00
$cleaned = $tidy -> repairString ( $newBody , Mail :: $tidy_config , 'utf8' );
2015-10-27 10:16:37 +01:00
// Found errors. Strip it all so there's some output
if ( $tidy -> getStatus () == 2 )
{
error_log ( __METHOD__ . ' (' . __LINE__ . ') ' . ' ->' . $tidy -> errorBuffer );
}
else
{
$newBody = $cleaned ;
}
2024-09-24 13:46:44 +02:00
// filter only the 'body', as we only want that part, if we throw away the html
2021-03-30 20:34:34 +02:00
if ( preg_match ( '`(<htm.+?<body[^>]*>)(.+?)(</body>.*?</html>)`ims' , $newBody , $matches ) && ! empty ( $matches [ 2 ]))
2015-10-27 10:16:37 +01:00
{
2021-03-30 20:34:34 +02:00
$hasOther = true ;
$newBody = $matches [ 2 ];
2015-10-27 10:16:37 +01:00
}
}
else
{
2016-03-13 12:56:00 +01:00
$htmLawed = new Api\Html\HtmLawed ();
2015-10-27 10:16:37 +01:00
// the next line should not be needed, but produces better results on HTML 2 Text conversion,
// as we switched off HTMLaweds tidy functionality
$newBody = str_replace ( array ( '&amp;' , '<DIV><BR></DIV>' , " <DIV> </DIV> " , '<div> </div>' ), array ( '&' , '<BR>' , '<BR>' , '<BR>' ), $newBody );
2016-03-28 20:51:38 +02:00
$newBody = $htmLawed -> run ( $newBody , Mail :: $htmLawed_config );
2015-11-20 16:16:37 +01:00
$alreadyHtmlLawed = true ;
2015-10-27 10:16:37 +01:00
}
2013-04-12 15:10:27 +02:00
// do the cleanup, set for the use of purifier
2021-03-30 20:34:34 +02:00
Mail :: getCleanHTML ( $newBody );
2013-04-12 15:10:27 +02:00
// removes stuff between http and ?http
$Protocol = '(http:\/\/|(ftp:\/\/|https:\/\/))' ; // only http:// gets removed, other protocolls are shown
$newBody = preg_replace ( '~' . $Protocol . '[^>]*\?' . $Protocol . '~sim' , '$1' , $newBody ); // removes stuff between http:// and ?http://
// TRANSFORM MAILTO LINKS TO EMAILADDRESS ONLY, WILL BE SUBSTITUTED BY parseEmail TO CLICKABLE LINK
$newBody = preg_replace ( '/(?<!"|href=|href\s=\s|href=\s|href\s=)' . 'mailto:([a-z0-9._-]+)@([a-z0-9_-]+)\.([a-z0-9._-]+)/i' ,
" \\ 1@ \\ 2. \\ 3 " ,
$newBody );
// create links for inline images
if ( $modifyURI )
{
2015-05-15 16:00:37 +02:00
$newBody = self :: resolve_inline_images ( $newBody , $this -> mailbox , $this -> uid , $this -> partID );
2013-04-12 15:10:27 +02:00
}
2014-03-03 15:56:12 +01:00
// email addresses / mailto links get now activated on client-side
2013-04-12 15:10:27 +02:00
}
$body .= $newBody ;
}
// create links for windows shares
// \\\\\\\\ == '\\' in real life!! :)
$body = preg_replace ( " /( \\ \\ \\ \\ )([ \ w, \\ \\ ,-]+)/i " ,
" <a href= \" file: $ 1 $ 2 \" target= \" _blank \" ><font color= \" blue \" > $ 1 $ 2</font></a> " , $body );
$body = preg_replace ( $nonDisplayAbleCharacters , '' , $body );
return $body ;
}
2015-07-16 11:34:55 +02:00
2013-04-12 15:10:27 +02:00
/**
2015-05-15 16:00:37 +02:00
* Resolve inline images from CID to proper url
2013-04-12 15:10:27 +02:00
*
2015-05-15 16:00:37 +02:00
* @ param string $_body message content
* @ param string $_mailbox mail folder
* @ param string $_uid uid
* @ param string $_partID part id
* @ param string $_messageType = 'html' , message type is either html or plain
* @ return string message body including all CID images replaced
2013-04-12 15:10:27 +02:00
*/
2015-05-15 16:00:37 +02:00
public static function resolve_inline_images ( $_body , $_mailbox , $_uid , $_partID , $_messageType = 'html' )
2013-04-12 15:10:27 +02:00
{
2015-05-15 16:00:37 +02:00
if ( $_messageType === 'plain' )
2013-04-12 15:10:27 +02:00
{
2015-05-15 16:00:37 +02:00
return self :: resolve_inline_image_byType ( $_body , $_mailbox , $_uid , $_partID , 'plain' );
2013-04-12 15:10:27 +02:00
}
2015-05-15 16:00:37 +02:00
else
2013-04-12 15:10:27 +02:00
{
2015-05-15 16:00:37 +02:00
foreach ( array ( 'src' , 'url' , 'background' ) as $type )
2013-04-12 15:10:27 +02:00
{
2015-05-15 16:00:37 +02:00
$_body = self :: resolve_inline_image_byType ( $_body , $_mailbox , $_uid , $_partID , $type );
2013-04-12 15:10:27 +02:00
}
2015-05-15 16:00:37 +02:00
return $_body ;
2013-04-12 15:10:27 +02:00
}
}
2015-07-16 11:34:55 +02:00
2013-04-12 15:10:27 +02:00
/**
2015-05-15 16:00:37 +02:00
* Replace CID with proper type of content understandable by browser
2013-04-12 15:10:27 +02:00
*
2015-05-15 16:00:37 +02:00
* @ param type $_body content of message
* @ param type $_mailbox mail box
* @ param type $_uid uid
* @ param type $_partID part id
* @ param type $_type = 'src' type of inline image that needs to be resolved and replaced
* - types : { plain | src | url | background }
2017-11-08 21:09:31 +01:00
* @ param callback $_link_callback Function to generate the link to the image . If
* not provided , a default ( using mail ) will be used .
2015-05-15 16:00:37 +02:00
* @ return string returns body content including all CID replacements
2013-04-12 15:10:27 +02:00
*/
2017-11-08 21:09:31 +01:00
public static function resolve_inline_image_byType ( $_body , $_mailbox , $_uid , $_partID , $_type = 'src' , callable $_link_callback = null )
2013-04-12 15:10:27 +02:00
{
2017-11-08 21:09:31 +01:00
/**
* Callback to generate the link
*/
if ( is_null ( $_link_callback ))
{
$_link_callback = function ( $_cid ) use ( $_mailbox , $_uid , $_partID )
{
$linkData = array (
'menuaction' => 'mail.mail_ui.displayImage' ,
2021-04-13 13:23:09 +02:00
'uid' => base64_encode ( $_uid ),
2017-11-08 21:09:31 +01:00
'mailbox' => base64_encode ( $_mailbox ),
2017-11-27 16:12:18 +01:00
'cid' => base64_encode ( $_cid ),
2017-11-08 21:09:31 +01:00
'partID' => $_partID ,
);
return Egw :: link ( '/index.php' , $linkData );
};
}
2015-05-15 16:00:37 +02:00
/**
* Callback for preg_replace_callback function
* returns matched CID replacement string based on given type
* @ param array $matches
* @ param string $_mailbox
* @ param string $_uid
* @ param string $_partID
* @ param string $_type
* @ return string | boolean returns the replace
*/
2017-11-08 21:09:31 +01:00
$replace_callback = function ( $matches ) use ( $_mailbox , $_uid , $_partID , $_type , $_link_callback )
2015-05-15 16:00:37 +02:00
{
if ( ! $_type ) return false ;
$CID = '' ;
// Build up matches according to selected type
switch ( $_type )
{
case " plain " :
$CID = $matches [ 1 ];
break ;
case " src " :
2015-05-19 11:26:08 +02:00
// as src:cid contains some kind of url, it is likely to be urlencoded
$CID = urldecode ( $matches [ 2 ]);
2015-05-15 16:00:37 +02:00
break ;
case " url " :
$CID = $matches [ 1 ];
break ;
case " background " :
$CID = $matches [ 2 ];
break ;
}
2013-04-12 15:10:27 +02:00
2015-05-15 16:00:37 +02:00
static $cache = array (); // some caching, if mails containing the same image multiple times
2013-04-12 15:10:27 +02:00
2015-05-15 16:00:37 +02:00
if ( is_array ( $matches ) && $CID )
{
2017-11-08 21:09:31 +01:00
$imageURL = call_user_func ( $_link_callback , $CID );
2015-05-15 16:00:37 +02:00
// to test without data uris, comment the if close incl. it's body
2016-05-03 21:17:44 +02:00
if ( Api\Header\UserAgent :: type () != 'msie' || Api\Header\UserAgent :: version () >= 8 )
2013-04-12 15:10:27 +02:00
{
2015-05-15 16:00:37 +02:00
if ( ! isset ( $cache [ $imageURL ]))
{
2018-05-15 18:15:00 +02:00
if ( $_type != " background " && ! $imageURL )
2015-05-15 16:00:37 +02:00
{
2016-03-28 20:51:38 +02:00
$bo = Mail :: getInstance ( false , mail_ui :: $icServerID );
2015-05-15 16:00:37 +02:00
$attachment = $bo -> getAttachmentByCID ( $_uid , $CID , $_partID );
// only use data uri for "smaller" images, as otherwise the first display of the mail takes to long
if (( $attachment instanceof Horde_Mime_Part ) && $attachment -> getBytes () < 8192 ) // msie=8 allows max 32k data uris
{
$bo -> fetchPartContents ( $_uid , $attachment );
$cache [ $imageURL ] = 'data:' . $attachment -> getType () . ';base64,' . base64_encode ( $attachment -> getContents ());
}
else
{
$cache [ $imageURL ] = $imageURL ;
}
}
else
{
$cache [ $imageURL ] = $imageURL ;
}
}
$imageURL = $cache [ $imageURL ];
2013-04-12 15:10:27 +02:00
}
2015-05-15 16:00:37 +02:00
// Decides the final result of replacement according to the type
switch ( $_type )
2013-04-12 15:10:27 +02:00
{
2015-05-15 16:00:37 +02:00
case " plain " :
return '<img src="' . $imageURL . '" />' ;
case " src " :
return 'src="' . $imageURL . '"' ;
case " url " :
return 'url(' . $imageURL . ');' ;
case " background " :
return 'background="' . $imageURL . '"' ;
2013-04-12 15:10:27 +02:00
}
}
2015-05-15 16:00:37 +02:00
return false ;
};
2015-07-16 11:34:55 +02:00
2015-05-15 16:00:37 +02:00
// return new body content base on chosen type
switch ( $_type )
{
case " plain " :
return preg_replace_callback ( " / \ [cid:(.*) \ ]/iU " , $replace_callback , $_body );
case " src " :
return preg_replace_callback ( " /src=( \" | \ ')cid:(.*)( \" | \ ')/iU " , $replace_callback , $_body );
case " url " :
return preg_replace_callback ( " /url \ (cid:(.*) \ );/iU " , $replace_callback , $_body );
case " background " :
return preg_replace_callback ( " /background=( \" | \ ')cid:(.*)( \" | \ ')/iU " , $replace_callback , $_body );
2013-04-12 15:10:27 +02:00
}
}
2018-02-26 12:34:08 +01:00
/**
* Create a new message from modified message then sends the original one to
* the trash .
*
* @ param string $_rowID row id
* @ param string $_subject subject to be replaced with old subject
*
* Sends json response to client with following data :
* array (
* success => boolean
* msg => string
* )
*/
function ajax_saveModifiedMessageSubject ( $_rowID , $_subject )
{
$response = Api\Json\Response :: get ();
$idData = self :: splitRowID ( $_rowID );
$folder = $idData [ 'folder' ];
try {
$raw = $this -> mail_bo -> getMessageRawBody ( $idData [ 'msgUID' ], '' , $folder );
$result = array ( 'success' => true , 'msg' => '' );
if ( $raw && $_subject )
{
$mailer = new Api\Mailer ();
$this -> mail_bo -> parseRawMessageIntoMailObject ( $mailer , $raw );
$mailer -> removeHeader ( 'subject' );
$mailer -> addHeader ( 'subject' , $_subject );
$this -> mail_bo -> openConnection ();
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ();
if ( $folder == 'INBOX' . $delimiter ) $folder = 'INBOX' ;
if ( $this -> mail_bo -> folderExists ( $folder , true ))
{
$this -> mail_bo -> appendMessage ( $folder , $mailer -> getRaw (), null , '\\Seen' );
$this -> mail_bo -> deleteMessages ( $idData [ 'msgUID' ], $folder );
}
else
{
$result [ 'success' ] = false ;
$result [ 'msg' ] = lang ( 'Changing subject failed folder %1 does not exist' , $folder );
}
}
} catch ( Exception $e ) {
$result [ 'success' ] = false ;
$result [ 'msg' ] = lang ( 'Changing subject failed because of %1 ' , $e -> getMessage ());
}
$response -> data ( $result );
}
2013-04-12 11:22:23 +02:00
/**
* importMessage
2014-07-16 13:37:02 +02:00
* @ param array $content = null an array of content
2013-04-12 11:22:23 +02:00
*/
2013-09-05 16:52:11 +02:00
function importMessage ( $content = null )
2013-04-12 11:22:23 +02:00
{
2013-09-05 16:52:11 +02:00
//error_log(__METHOD__.__LINE__.$this->mail_bo->getDraftFolder());
2013-09-24 15:38:02 +02:00
2013-09-05 16:52:11 +02:00
if ( ! empty ( $content ))
{
2014-07-08 10:50:43 +02:00
//error_log(__METHOD__.__LINE__.array2string($content));
2014-07-16 13:37:02 +02:00
if ( $content [ 'vfsfile' ])
2013-10-16 13:25:46 +02:00
{
2014-07-16 13:37:02 +02:00
$file = $content [ 'vfsfile' ] = array (
2016-05-03 21:17:44 +02:00
'name' => Vfs :: basename ( $content [ 'vfsfile' ]),
'type' => Vfs :: mime_content_type ( $content [ 'vfsfile' ]),
'file' => Vfs :: PREFIX . $content [ 'vfsfile' ],
'size' => filesize ( Vfs :: PREFIX . $content [ 'vfsfile' ]),
2013-10-16 13:25:46 +02:00
);
}
else
{
2014-07-16 13:37:02 +02:00
$file = $content [ 'uploadForImport' ];
2013-10-16 13:25:46 +02:00
}
2022-11-15 21:15:17 +01:00
$destination = $content [ 'FOLDER' ];
2015-03-27 15:51:41 +01:00
if ( stripos ( $destination , self :: $delimiter ) !== false ) list ( $icServerID , $destination ) = explode ( self :: $delimiter , $destination , 2 );
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2015-03-27 13:59:03 +01:00
//error_log(__METHOD__.__LINE__.self::$delimiter.array2string($destination));
2016-03-28 20:51:38 +02:00
$importID = Mail :: getRandomString ();
2013-09-05 16:52:11 +02:00
$importFailed = false ;
try
2013-04-12 11:22:23 +02:00
{
2013-10-16 13:25:46 +02:00
$messageUid = $this -> importMessageToFolder ( $file , $destination , $importID );
2013-09-05 16:52:11 +02:00
$linkData = array
(
2014-07-16 13:37:02 +02:00
'id' => $this -> createRowID ( $destination , $messageUid , true ),
2013-09-05 16:52:11 +02:00
);
2013-04-12 11:22:23 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-04-12 11:22:23 +02:00
{
2013-09-05 16:52:11 +02:00
$importFailed = true ;
$content [ 'msg' ] = $e -> getMessage ();
2013-04-12 11:22:23 +02:00
}
2013-09-05 16:52:11 +02:00
if ( ! $importFailed )
2013-04-12 11:22:23 +02:00
{
2018-04-09 17:39:49 +02:00
Api\Json\Response :: get () -> call ( 'egw.open' , $linkData [ 'id' ], 'mail' , 'view' );
Api\Json\Response :: get () -> call ( 'window.close' );
2014-10-15 17:49:41 +02:00
return ;
2013-04-12 11:22:23 +02:00
}
2013-09-05 16:52:11 +02:00
}
if ( ! is_array ( $content )) $content = array ();
2020-07-24 14:38:33 +02:00
if ( empty ( $content [ 'FOLDER' ]))
{
$draft = $this -> mail_bo -> getDraftFolder ();
$content [ 'FOLDER' ] = ( array )( preg_match ( $draft , " /::/ " ) ? $draft : $this -> mail_bo -> profileID . '::' . $draft );
}
2017-01-16 21:02:19 +01:00
if ( ! empty ( $content [ 'FOLDER' ]))
{
$compose = new mail_compose ();
$sel_options [ 'FOLDER' ] = $compose -> ajax_searchFolder ( 0 , true );
}
2013-04-12 11:22:23 +02:00
2016-05-03 21:17:44 +02:00
$etpl = new Etemplate ( 'mail.importMessage' );
2013-09-05 16:52:11 +02:00
$etpl -> setElementAttribute ( 'uploadForImport' , 'onFinish' , 'app.mail.uploadForImport' );
2014-07-16 18:34:15 +02:00
$etpl -> exec ( 'mail.mail_ui.importMessage' , $content , $sel_options , array (), array (), 2 );
2013-09-05 16:52:11 +02:00
}
/**
* importMessageToFolder
*
* @ param array $_formData Array with information of name , type , file and size
* @ param string $_folder ( passed by reference ) will set the folder used . must be set with a folder , but will hold modifications if
* folder is modified
* @ param string $importID ID for the imported message , used by attachments to identify them unambiguously
* @ return mixed $messageUID or exception
*/
function importMessageToFolder ( $_formData , & $_folder , $importID = '' )
{
$importfailed = false ;
//error_log(__METHOD__.__LINE__.array2string($_formData));
if ( empty ( $_formData [ 'file' ])) $_formData [ 'file' ] = $_formData [ 'tmp_name' ];
// check if formdata meets basic restrictions (in tmp dir, or vfs, mimetype, etc.)
2021-03-30 20:34:34 +02:00
$alert_msg = '' ;
2013-09-05 16:52:11 +02:00
try
{
2016-03-28 20:51:38 +02:00
$tmpFileName = Mail :: checkFileBasics ( $_formData , $importID );
2013-09-05 16:52:11 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-09-05 16:52:11 +02:00
{
$importfailed = true ;
$alert_msg .= $e -> getMessage ();
}
// -----------------------------------------------------------------------
if ( $importfailed === false )
{
2016-05-03 21:17:44 +02:00
$mailObject = new Api\Mailer ();
2013-09-05 16:52:11 +02:00
try
2013-04-12 11:22:23 +02:00
{
2014-11-26 15:08:52 +01:00
$this -> mail_bo -> parseFileIntoMailObject ( $mailObject , $tmpFileName );
2013-04-12 11:22:23 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\AssertionFailed $e )
2013-04-12 11:22:23 +02:00
{
2013-09-05 16:52:11 +02:00
$importfailed = true ;
$alert_msg .= $e -> getMessage ();
2013-04-12 11:22:23 +02:00
}
2013-09-05 16:52:11 +02:00
$this -> mail_bo -> openConnection ();
if ( empty ( $_folder ))
2013-04-12 11:22:23 +02:00
{
2013-09-05 16:52:11 +02:00
$importfailed = true ;
$alert_msg .= lang ( " Import of message %1 failed. Destination Folder not set. " , $_formData [ 'name' ]);
2013-04-12 11:22:23 +02:00
}
2013-09-05 16:52:11 +02:00
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ();
if ( $_folder == 'INBOX' . $delimiter ) $_folder = 'INBOX' ;
if ( $importfailed === false )
{
if ( $this -> mail_bo -> folderExists ( $_folder , true )) {
try
{
$messageUid = $this -> mail_bo -> appendMessage ( $_folder ,
2014-11-26 15:08:52 +01:00
$mailObject -> getRaw (),
null , '\\Seen' );
2013-09-05 16:52:11 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-09-05 16:52:11 +02:00
{
$importfailed = true ;
$alert_msg .= lang ( " Import of message %1 failed. Could not save message to folder %2 due to: %3 " , $_formData [ 'name' ], $_folder , $e -> getMessage ());
}
}
else
{
$importfailed = true ;
$alert_msg .= lang ( " Import of message %1 failed. Destination Folder %2 does not exist. " , $_formData [ 'name' ], $_folder );
}
}
}
// set the url to open when refreshing
if ( $importfailed == true )
{
2016-05-03 21:17:44 +02:00
throw new Api\Exception\WrongUserinput ( $alert_msg );
2013-09-05 16:52:11 +02:00
}
else
{
return $messageUid ;
}
}
2013-04-12 11:22:23 +02:00
2013-09-05 16:52:11 +02:00
/**
* importMessageFromVFS2DraftAndEdit
*
* @ param array $formData Array with information of name , type , file and size ; file is required ,
* name , type and size may be set here to meet the requirements
* Example : $formData [ 'name' ] = 'a_email.eml' ;
* $formData [ 'type' ] = 'message/rfc822' ;
* $formData [ 'file' ] = 'vfs://default/home/leithoff/a_email.eml' ;
* $formData [ 'size' ] = 2136 ;
* @ return void
*/
function importMessageFromVFS2DraftAndEdit ( $formData = '' )
{
$this -> importMessageFromVFS2DraftAndDisplay ( $formData , 'edit' );
}
2013-04-12 11:22:23 +02:00
2013-09-05 16:52:11 +02:00
/**
* importMessageFromVFS2DraftAndDisplay
*
* @ param array $formData Array with information of name , type , file and size ; file is required ,
* name , type and size may be set here to meet the requirements
* Example : $formData [ 'name' ] = 'a_email.eml' ;
* $formData [ 'type' ] = 'message/rfc822' ;
* $formData [ 'file' ] = 'vfs://default/home/leithoff/a_email.eml' ;
* $formData [ 'size' ] = 2136 ;
* @ param string $mode mode to open ImportedMessage display and edit are supported
* @ return void
*/
function importMessageFromVFS2DraftAndDisplay ( $formData = '' , $mode = 'display' )
{
if ( empty ( $formData )) if ( isset ( $_REQUEST [ 'formData' ])) $formData = $_REQUEST [ 'formData' ];
2014-01-24 12:48:24 +01:00
//error_log(__METHOD__.__LINE__.':'.array2string($formData).' Mode:'.$mode.'->'.function_backtrace());
2013-09-05 16:52:11 +02:00
$draftFolder = $this -> mail_bo -> getDraftFolder ( false );
2016-03-28 20:51:38 +02:00
$importID = Mail :: getRandomString ();
2015-03-25 18:48:24 +01:00
// handling for mime-data hash
if ( ! empty ( $formData [ 'data' ]))
{
$formData [ 'file' ] = 'egw-data://' . $formData [ 'data' ];
}
2013-09-05 16:52:11 +02:00
// name should be set to meet the requirements of checkFileBasics
2015-03-25 18:48:24 +01:00
if ( parse_url ( $formData [ 'file' ], PHP_URL_SCHEME ) == 'vfs' && empty ( $formData [ 'name' ]))
2013-09-05 16:52:11 +02:00
{
$buff = explode ( '/' , $formData [ 'file' ]);
if ( is_array ( $buff )) $formData [ 'name' ] = array_pop ( $buff ); // take the last part as name
}
// type should be set to meet the requirements of checkFileBasics
2015-03-25 18:48:24 +01:00
if ( parse_url ( $formData [ 'file' ], PHP_URL_SCHEME ) == 'vfs' && empty ( $formData [ 'type' ]))
2013-09-05 16:52:11 +02:00
{
$buff = explode ( '.' , $formData [ 'file' ]);
$suffix = '' ;
if ( is_array ( $buff )) $suffix = array_pop ( $buff ); // take the last extension to check with ext2mime
2016-05-03 21:17:44 +02:00
if ( ! empty ( $suffix )) $formData [ 'type' ] = Api\MimeMagic :: ext2mime ( $suffix );
2013-09-05 16:52:11 +02:00
}
// size should be set to meet the requirements of checkFileBasics
2015-03-25 18:48:24 +01:00
if ( parse_url ( $formData [ 'file' ], PHP_URL_SCHEME ) == 'vfs' && ! isset ( $formData [ 'size' ]))
2013-09-05 16:52:11 +02:00
{
$formData [ 'size' ] = strlen ( $formData [ 'file' ]); // set some size, to meet requirements of checkFileBasics
}
try
{
$messageUid = $this -> importMessageToFolder ( $formData , $draftFolder , $importID );
2013-04-12 11:22:23 +02:00
$linkData = array
(
2013-09-05 16:52:11 +02:00
'menuaction' => ( $mode == 'display' ? 'mail.mail_ui.displayMessage' : 'mail.mail_compose.composeFromDraft' ),
'id' => $this -> createRowID ( $draftFolder , $messageUid , true ),
'deleteDraftOnClose' => 1 ,
2013-04-12 11:22:23 +02:00
);
2013-09-05 16:52:11 +02:00
if ( $mode != 'display' )
2013-04-12 11:22:23 +02:00
{
2013-09-05 16:52:11 +02:00
unset ( $linkData [ 'deleteDraftOnClose' ]);
$linkData [ 'method' ] = 'importMessageToMergeAndSend' ;
2013-04-12 11:22:23 +02:00
}
2014-01-24 12:48:24 +01:00
else
{
$linkData [ 'mode' ] = $mode ;
}
2016-05-03 21:17:44 +02:00
Egw :: redirect_link ( '/index.php' , $linkData );
2013-09-05 16:52:11 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-09-05 16:52:11 +02:00
{
2016-05-03 21:17:44 +02:00
Framework :: window_close ( $e -> getMessage ());
2013-09-05 16:52:11 +02:00
}
2013-03-05 15:09:35 +01:00
}
2013-04-12 15:10:27 +02:00
/**
* loadEmailBody
*
* @ param string _messageID UID
*
* @ return xajax response
*/
2014-03-03 15:56:12 +01:00
function loadEmailBody ( $_messageID = null , $_partID = null , $_htmloptions = null )
2013-04-12 15:10:27 +02:00
{
2014-02-04 13:31:11 +01:00
//error_log(__METHOD__.__LINE__.array2string($_GET));
2014-02-04 12:31:13 +01:00
if ( ! $_messageID && ! empty ( $_GET [ '_messageID' ])) $_messageID = $_GET [ '_messageID' ];
if ( ! $_partID && ! empty ( $_GET [ '_partID' ])) $_partID = $_GET [ '_partID' ];
if ( ! $_htmloptions && ! empty ( $_GET [ '_htmloptions' ])) $_htmloptions = $_GET [ '_htmloptions' ];
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> " . print_r ( $_messageID , true ) . " , $_partID , $_htmloptions " );
2013-04-30 16:16:52 +02:00
if ( empty ( $_messageID )) return " " ;
2013-04-12 15:10:27 +02:00
$uidA = self :: splitRowID ( $_messageID );
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
$messageID = $uidA [ 'msgUID' ];
2014-11-06 14:11:44 +01:00
$icServerID = $uidA [ 'profileID' ];
2016-02-11 14:03:28 +01:00
//something went wrong. there is a $_messageID but no $messageID: means $_messageID is crippeled
if ( empty ( $messageID )) return " " ;
2014-11-06 14:11:44 +01:00
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2024-02-28 07:55:13 +01:00
$bodyResponse = $this -> get_load_email_data ( $messageID , $_partID , $folder , $_htmloptions , $_POST [ 'smime_passphrase' ] ? ? null );
2013-04-12 15:10:27 +02:00
//error_log(array2string($bodyResponse));
echo $bodyResponse ;
}
2013-02-19 17:30:59 +01:00
/**
2013-04-12 11:22:23 +02:00
* ajax_setFolderStatus - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
2013-02-19 17:30:59 +01:00
* gets the counters and sets the text of a treenode if needed ( unread Messages found )
2013-04-12 11:22:23 +02:00
* @ param array $_folder folders to refresh its unseen message counters
2013-02-19 17:30:59 +01:00
* @ return nothing
*/
2024-09-26 12:54:29 +02:00
function ajax_setFolderStatus ( $_folder , $force_change = false )
2013-02-19 17:30:59 +01:00
{
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2013-04-09 18:00:12 +02:00
//error_log(__METHOD__.__LINE__.array2string($_folder));
2013-02-19 17:30:59 +01:00
if ( $_folder )
{
2016-06-08 10:02:53 +02:00
$this -> mail_bo -> getHierarchyDelimiter ( false );
2013-02-19 17:30:59 +01:00
$oA = array ();
foreach ( $_folder as $_folderName )
{
2013-02-20 17:27:10 +01:00
list ( $profileID , $folderName ) = explode ( self :: $delimiter , $_folderName , 2 );
2024-09-26 16:07:39 +02:00
if ( is_numeric ( $profileID )) //things like mail::xxx will be ignored
2013-02-19 17:30:59 +01:00
{
2013-02-20 17:27:10 +01:00
if ( $profileID != $this -> mail_bo -> profileID ) continue ; // only current connection
2013-02-19 17:30:59 +01:00
if ( $folderName )
{
2016-06-07 15:25:33 +02:00
try
{
$fS = $this -> mail_bo -> getFolderStatus ( $folderName , false , false , false );
}
catch ( Exception $e )
{
2017-02-27 17:45:46 +01:00
if ( Mail :: $debug ) error_log ( __METHOD__ , ' ()' . $e -> getMessage ());
2016-06-07 15:25:33 +02:00
continue ;
}
2013-02-19 17:30:59 +01:00
//error_log(__METHOD__.__LINE__.array2string($fS));
2024-09-26 12:54:29 +02:00
if ( $fS [ 'unseen' ] || $force_change )
2013-02-19 17:30:59 +01:00
{
2024-03-15 10:54:40 +01:00
$oA [ $_folderName ] = '' . $fS [ 'unseen' ];
2013-02-19 17:30:59 +01:00
}
2024-03-15 10:54:40 +01:00
2013-02-19 17:30:59 +01:00
}
}
}
2013-04-09 18:00:12 +02:00
//error_log(__METHOD__.__LINE__.array2string($oA));
2013-02-19 17:30:59 +01:00
if ( $oA )
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-01-11 15:16:36 +01:00
$response -> call ( 'app.mail.mail_setFolderStatus' , $oA );
2013-02-19 17:30:59 +01:00
}
}
}
2013-05-21 10:46:54 +02:00
/**
2017-03-07 12:21:00 +01:00
* This function creates folder / subfolder based on its selected parent
*
* @ param string $_parent folder name or profile + folder name to add a folder to
* @ param string $_new new folder name to be created
*
2013-05-21 10:46:54 +02:00
*/
2017-03-07 12:21:00 +01:00
function ajax_addFolder ( $_parent , $_new )
2013-05-21 10:46:54 +02:00
{
2017-03-07 12:21:00 +01:00
$error = '' ;
$created = false ;
2018-10-17 18:02:36 +02:00
$response = Api\Json\Response :: get ();
2019-01-15 14:55:35 +01:00
$del = $this -> mail_bo -> getHierarchyDelimiter ( false );
2018-10-17 18:02:36 +02:00
if ( strpos ( $_new , $del ) !== FALSE )
{
return $response -> call ( 'egw.message' , lang ( 'failed to rename %1 ! Reason: %2 is not allowed!' , $_parent , $del ));
}
2017-03-07 12:21:00 +01:00
if ( $_parent )
2013-05-21 10:46:54 +02:00
{
2017-03-07 12:21:00 +01:00
$parent = $this -> mail_bo -> decodeEntityFolderName ( $_parent );
2013-12-12 14:34:35 +01:00
//the conversion is handeled by horde, frontend interaction is all utf-8
2017-03-07 12:21:00 +01:00
$new = $this -> mail_bo -> decodeEntityFolderName ( $_new );
2014-11-20 15:57:34 +01:00
2017-03-07 12:21:00 +01:00
list ( $profileID , $p_no_delimiter ) = explode ( self :: $delimiter , $parent , 2 );
2017-03-07 14:05:42 +01:00
if ( is_numeric ( $profileID ))
2017-03-07 12:21:00 +01:00
{
2017-03-07 14:05:42 +01:00
if ( $profileID != $this -> mail_bo -> profileID ) $this -> changeProfile ( $profileID );
2017-03-07 12:21:00 +01:00
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ( false );
$parts = explode ( $delimiter , $new );
2013-05-21 10:46:54 +02:00
2017-03-07 12:21:00 +01:00
if ( !! empty ( $parent )) $folderStatus = $this -> mail_bo -> getFolderStatus ( $parent , false );
2014-07-16 15:42:36 +02:00
2017-03-07 12:21:00 +01:00
//open the INBOX
2014-07-16 15:42:36 +02:00
$this -> mail_bo -> reopen ( 'INBOX' );
2017-03-07 12:21:00 +01:00
// if $new has delimiter ($del) in it, we need to create the subtree
if ( ! empty ( $parts ))
2014-07-16 15:42:36 +02:00
{
2017-03-07 12:21:00 +01:00
$counter = 0 ;
foreach ( $parts as $subTree )
2013-05-21 12:57:07 +02:00
{
2017-03-07 12:21:00 +01:00
$err = null ;
if (( $new = $this -> mail_bo -> createFolder ( $p_no_delimiter , $subTree , $err )))
2013-05-21 12:57:07 +02:00
{
2017-03-07 12:21:00 +01:00
$counter ++ ;
if ( ! $p_no_delimiter )
{
2020-06-08 11:59:32 +02:00
// we first test below INBOX, because testing just the name wrongly reports it as subscribed
// for servers not allowing to create folders parallel to INBOX
$status = $this -> mail_bo -> getFolderStatus ( 'INBOX' . $delimiter . $new , false , true , true ) ? :
$this -> mail_bo -> getFolderStatus ( $new , false , true , true );
2017-03-07 12:21:00 +01:00
if ( ! $status [ 'subscribed' ])
{
try
{
$this -> mail_bo -> icServer -> subscribeMailbox ( 'INBOX' . $delimiter . $new );
}
catch ( Horde_Imap_Client_Exception $e )
{
$error = Lang ( 'Folder %1 has been created successfully,' .
' although the subscription failed because of %2' , $new , $e -> getMessage ());
}
}
}
2013-05-21 12:57:07 +02:00
}
2014-11-20 15:57:34 +01:00
else
{
2017-03-07 12:21:00 +01:00
if ( ! $p_no_delimiter )
{
$new = $this -> mail_bo -> createFolder ( 'INBOX' , $subTree , $err );
if ( $new ) $counter ++ ;
}
else
{
$error .= $err ;
}
2014-11-20 15:57:34 +01:00
}
2013-05-21 10:46:54 +02:00
}
2017-03-07 12:21:00 +01:00
if ( $counter == count ( $parts )) $created = true ;
2013-05-21 10:46:54 +02:00
}
2017-03-07 12:21:00 +01:00
if ( ! empty ( $new )) $this -> mail_bo -> reopen ( $new );
2013-05-21 10:46:54 +02:00
}
2017-03-07 15:20:11 +01:00
2018-10-17 18:02:36 +02:00
2017-03-07 12:29:45 +01:00
if ( $created === true && $error == '' )
2013-05-21 10:46:54 +02:00
{
2013-05-21 12:57:07 +02:00
$this -> mail_bo -> resetFolderObjectCache ( $profileID );
2017-03-07 12:21:00 +01:00
if ( $folderStatus [ 'shortDisplayName' ])
2014-11-20 15:57:34 +01:00
{
2017-03-07 12:21:00 +01:00
$nodeInfo = array ( $parent => $folderStatus [ 'shortDisplayName' ]);
2014-11-20 15:57:34 +01:00
}
else
{
$nodeInfo = array ( $profileID => lang ( 'INBOX' ));
}
$response -> call ( 'app.mail.mail_reloadNode' , $nodeInfo );
}
else
{
2017-03-07 12:21:00 +01:00
if ( $error )
2014-11-20 15:57:34 +01:00
{
2017-03-07 12:21:00 +01:00
$response -> call ( 'egw.message' , $error );
2014-11-20 15:57:34 +01:00
}
2013-05-21 10:46:54 +02:00
}
}
2017-03-07 12:21:00 +01:00
else {
error_log ( __METHOD__ . __LINE__ . " () " . " This function needs a parent folder to work! " );
}
2013-05-21 10:46:54 +02:00
}
2013-04-12 11:22:23 +02:00
/**
* ajax_renameFolder - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
* @ param string $_folderName folder to rename and refresh
* @ param string $_newName new foldername
* @ return nothing
*/
function ajax_renameFolder ( $_folderName , $_newName )
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' OldFolderName:' . array2string ( $_folderName ) . ' NewName:' . array2string ( $_newName ));
2018-10-17 18:02:36 +02:00
//error_log(__METHOD__.__LINE__.array2string($oA));
$response = Api\Json\Response :: get ();
$del = $this -> mail_bo -> getHierarchyDelimiter ( false );
if ( strpos ( $_newName , $del ) !== FALSE )
{
return $response -> call ( 'egw.message' , lang ( 'failed to rename %1 ! Reason: %2 is not allowed!' , $_folderName , $del ));
}
2013-04-12 11:22:23 +02:00
if ( $_folderName )
{
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2013-04-29 16:56:33 +02:00
$decodedFolderName = $this -> mail_bo -> decodeEntityFolderName ( $_folderName );
2013-12-12 16:10:25 +01:00
$_newName = $this -> mail_bo -> decodeEntityFolderName ( $_newName );
2018-10-17 18:02:36 +02:00
2013-04-12 11:22:23 +02:00
$oA = array ();
2013-04-29 16:56:33 +02:00
list ( $profileID , $folderName ) = explode ( self :: $delimiter , $decodedFolderName , 2 );
2013-05-10 09:24:27 +02:00
$hasChildren = false ;
2013-04-12 11:22:23 +02:00
if ( is_numeric ( $profileID ))
{
2017-04-13 16:26:59 +02:00
if ( $profileID != $this -> mail_bo -> profileID ) $this -> changeProfile ( $profileID );
2013-04-12 11:22:23 +02:00
$pA = explode ( $del , $folderName );
array_pop ( $pA );
$parentFolder = implode ( $del , $pA );
if ( strtoupper ( $folderName ) != 'INBOX' )
{
//error_log(__METHOD__.__LINE__."$folderName, $parentFolder, $_newName");
2013-05-07 10:26:17 +02:00
$oldFolderInfo = $this -> mail_bo -> getFolderStatus ( $folderName , false );
2013-05-10 09:24:27 +02:00
//error_log(__METHOD__.__LINE__.array2string($oldFolderInfo));
if ( ! empty ( $oldFolderInfo [ 'attributes' ]) && stripos ( array2string ( $oldFolderInfo [ 'attributes' ]), '\hasnochildren' ) === false )
{
$hasChildren = true ; // translates to: hasChildren -> dynamicLoading
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ();
$nameSpace = $this -> mail_bo -> _getNameSpaces ();
$prefix = $this -> mail_bo -> getFolderPrefixFromNamespace ( $nameSpace , $folderName );
//error_log(__METHOD__.__LINE__.'->'."$_folderName, $delimiter, $prefix");
$fragments = array ();
$subFolders = $this -> mail_bo -> getMailBoxesRecursive ( $folderName , $delimiter , $prefix );
foreach ( $subFolders as $k => $folder )
{
// we do not monitor failure or success on subfolders
if ( $folder == $folderName )
{
unset ( $subFolders [ $k ]);
}
else
{
2014-08-18 12:33:22 +02:00
$rv = $this -> mail_bo -> icServer -> subscribeMailbox ( $folder , false );
2013-05-10 09:24:27 +02:00
$fragments [ $profileID . self :: $delimiter . $folder ] = substr ( $folder , strlen ( $folderName ));
}
}
//error_log(__METHOD__.__LINE__.' Fetched Subfolders->'.array2string($fragments));
}
2013-04-29 16:56:33 +02:00
$this -> mail_bo -> reopen ( 'INBOX' );
2013-12-12 16:10:25 +01:00
$success = false ;
try
{
2014-05-22 09:47:49 +02:00
if (( $newFolderName = $this -> mail_bo -> renameFolder ( $folderName , $parentFolder , $_newName )))
{
2013-12-12 16:10:25 +01:00
$this -> mail_bo -> resetFolderObjectCache ( $profileID );
//enforce the subscription to the newly named server, as it seems to fail for names with umlauts
2016-05-03 21:17:44 +02:00
$this -> mail_bo -> icServer -> subscribeMailbox ( $newFolderName , true );
$this -> mail_bo -> icServer -> subscribeMailbox ( $folderName , false );
2013-12-12 16:10:25 +01:00
$success = true ;
}
}
catch ( Exception $e )
{
$newFolderName = $folderName ;
$msg = $e -> getMessage ();
2013-04-12 11:22:23 +02:00
}
2013-04-29 16:56:33 +02:00
$this -> mail_bo -> reopen ( $newFolderName );
2013-04-12 11:22:23 +02:00
$fS = $this -> mail_bo -> getFolderStatus ( $newFolderName , false );
//error_log(__METHOD__.__LINE__.array2string($fS));
2013-05-10 09:24:27 +02:00
if ( $hasChildren )
{
$subFolders = $this -> mail_bo -> getMailBoxesRecursive ( $newFolderName , $delimiter , $prefix );
foreach ( $subFolders as $k => $folder )
{
// we do not monitor failure or success on subfolders
if ( $folder == $folderName )
{
unset ( $subFolders [ $k ]);
}
else
{
2014-08-18 12:33:22 +02:00
$rv = $this -> mail_bo -> icServer -> subscribeMailbox ( $folder , true );
2013-05-10 09:24:27 +02:00
}
}
//error_log(__METHOD__.__LINE__.' Fetched Subfolders->'.array2string($subFolders));
}
2013-04-29 16:56:33 +02:00
$oA [ $_folderName ][ 'id' ] = $profileID . self :: $delimiter . $newFolderName ;
2013-05-07 10:26:17 +02:00
$oA [ $_folderName ][ 'olddesc' ] = $oldFolderInfo [ 'shortDisplayName' ];
2013-04-12 11:22:23 +02:00
if ( $fS [ 'unseen' ])
{
2024-03-27 09:33:32 +01:00
$oA [ $_folderName ][ 'desc' ] = $fS [ 'shortDisplayName' ];
$oA [ $_folderName ][ 'unseenCount' ] = $fS [ 'unseen' ];
2013-04-12 11:22:23 +02:00
}
2013-04-29 16:56:33 +02:00
else
{
$oA [ $_folderName ][ 'desc' ] = $fS [ 'shortDisplayName' ];
}
2013-05-10 09:24:27 +02:00
foreach ( $fragments as $oldFolderName => $fragment )
{
//error_log(__METHOD__.__LINE__.':'.$oldFolderName.'->'.$profileID.self::$delimiter.$newFolderName.$fragment);
$oA [ $oldFolderName ][ 'id' ] = $profileID . self :: $delimiter . $newFolderName . $fragment ;
$oA [ $oldFolderName ][ 'olddesc' ] = '#skip-user-interaction-message#' ;
$fS = $this -> mail_bo -> getFolderStatus ( $newFolderName . $fragment , false );
if ( $fS [ 'unseen' ])
{
2014-02-05 13:23:04 +01:00
$oA [ $oldFolderName ][ 'desc' ] = $fS [ 'shortDisplayName' ] . ' (' . $fS [ 'unseen' ] . ')' ;
2013-05-10 09:24:27 +02:00
}
else
{
$oA [ $oldFolderName ][ 'desc' ] = $fS [ 'shortDisplayName' ];
}
}
2013-04-12 11:22:23 +02:00
}
}
2013-12-03 15:38:50 +01:00
if ( $folderName == $this -> mail_bo -> sessionData [ 'mailbox' ])
{
$this -> mail_bo -> sessionData [ 'mailbox' ] = $newFolderName ;
$this -> mail_bo -> saveSessionData ();
}
2013-04-12 11:22:23 +02:00
//error_log(__METHOD__.__LINE__.array2string($oA));
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2013-12-12 16:10:25 +01:00
if ( $oA && $success )
2013-04-12 11:22:23 +02:00
{
2014-01-13 14:06:29 +01:00
$response -> call ( 'app.mail.mail_setLeaf' , $oA );
2013-04-12 11:22:23 +02:00
}
2013-12-12 16:10:25 +01:00
else
{
2014-05-27 15:31:37 +02:00
$response -> call ( 'egw.refresh' , lang ( 'failed to rename %1 ! Reason: %2' , $oldFolderName , $msg ), 'mail' );
2013-12-12 16:10:25 +01:00
}
2013-04-12 11:22:23 +02:00
}
}
2014-02-06 10:09:57 +01:00
/**
* reload node
*
* @ param string _folderName folder to reload
2014-07-16 15:42:36 +02:00
* @ param boolean $_subscribedOnly = true
2014-02-06 10:09:57 +01:00
* @ return void
*/
function ajax_reloadNode ( $_folderName , $_subscribedOnly = true )
{
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2014-02-07 09:33:23 +01:00
$oldPrefForSubscribedOnly = ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ];
2014-02-06 10:09:57 +01:00
$decodedFolderName = $this -> mail_bo -> decodeEntityFolderName ( $_folderName );
list ( $profileID , $folderName ) = explode ( self :: $delimiter , $decodedFolderName , 2 );
2017-04-13 16:26:59 +02:00
if ( $profileID != $this -> mail_bo -> profileID ) $this -> changeProfile ( $profileID );
2014-02-07 09:33:23 +01:00
// if pref and required mode dont match -> reset the folderObject cache to ensure
// that we get what we request
if ( $_subscribedOnly != $oldPrefForSubscribedOnly ) $this -> mail_bo -> resetFolderObjectCache ( $profileID );
2017-04-13 16:26:59 +02:00
2014-05-20 16:28:23 +02:00
if ( ! empty ( $folderName ))
2014-02-06 10:09:57 +01:00
{
2014-05-20 16:28:23 +02:00
$parentFolder = ( ! empty ( $folderName ) ? $folderName : 'INBOX' );
2014-07-31 12:10:07 +02:00
$folderInfo = $this -> mail_bo -> getFolderStatus ( $parentFolder , false , false , false );
2014-05-20 16:28:23 +02:00
if ( $folderInfo [ 'unseen' ])
{
$folderInfo [ 'shortDisplayName' ] = $folderInfo [ 'shortDisplayName' ] . ' (' . $folderInfo [ 'unseen' ] . ')' ;
}
if ( $folderInfo [ 'unseen' ] == 0 && $folderInfo [ 'shortDisplayName' ])
{
$folderInfo [ 'shortDisplayName' ] = $folderInfo [ 'shortDisplayName' ];
}
$refreshData = array (
$profileID . self :: $delimiter . $parentFolder => $folderInfo [ 'shortDisplayName' ]);
2014-02-06 10:09:57 +01:00
}
2014-05-20 16:28:23 +02:00
else
2014-02-06 10:09:57 +01:00
{
2014-05-20 16:28:23 +02:00
$refreshData = array (
$profileID => lang ( 'INBOX' ) //string with no meaning lateron
);
2014-02-06 10:09:57 +01:00
}
// Send full info back in the response
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-02-06 10:09:57 +01:00
foreach ( $refreshData as $folder => & $name )
{
2015-08-03 16:33:18 +02:00
$name = $this -> mail_tree -> getTree ( $folder , $profileID , 1 , false , $_subscribedOnly , true );
2014-02-06 10:09:57 +01:00
}
$response -> call ( 'app.mail.mail_reloadNode' , $refreshData );
}
2016-03-09 13:31:55 +01:00
2015-11-27 17:17:59 +01:00
/**
* ResolveWinmail fetches the encoded attachments
2015-12-02 12:10:26 +01:00
* from winmail . dat and will response expected structure back
2015-11-27 17:17:59 +01:00
* to client in order to display them .
*
* Note : this ajax function should only be called via
* nm mail selection as it does not support profile change
* and uses the current available ic_server connection .
*
* @ param type $_rowid row id from nm
*
*/
function ajax_resolveWinmail ( $_rowid )
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2016-03-09 13:31:55 +01:00
2015-11-27 17:17:59 +01:00
$idParts = self :: splitRowID ( $_rowid );
$uid = $idParts [ 'msgUID' ];
$mbox = $idParts [ 'folder' ];
2016-03-09 13:31:55 +01:00
2015-11-27 17:17:59 +01:00
$attachments = $this -> mail_bo -> getMessageAttachments ( $uid , null , null , false , true , true , $mbox );
if ( is_array ( $attachments ))
{
$attachments = $this -> createAttachmentBlock ( $attachments , $_rowid , $uid , $mbox , false );
$response -> data ( $attachments );
}
else
{
2015-12-02 12:10:26 +01:00
$response -> call ( 'egw.message' , lang ( 'Can not resolve the winmail.dat attachment!' ));
2015-11-27 17:17:59 +01:00
}
}
2016-03-09 13:31:55 +01:00
2014-01-06 13:57:53 +01:00
/**
* move folder
*
2014-01-11 12:58:31 +01:00
* @ param string _folderName folder to vove
* @ param string _target target folder
2014-01-06 13:57:53 +01:00
*
2014-01-11 12:58:31 +01:00
* @ return void
2014-01-06 13:57:53 +01:00
*/
function ajax_MoveFolder ( $_folderName , $_target )
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . " Move Folder: $_folderName to Target: $_target " );
2014-01-06 13:57:53 +01:00
if ( $_folderName )
{
$decodedFolderName = $this -> mail_bo -> decodeEntityFolderName ( $_folderName );
2016-05-03 21:17:44 +02:00
$_newLocation2 = $this -> mail_bo -> decodeEntityFolderName ( $_target );
2014-01-06 13:57:53 +01:00
list ( $profileID , $folderName ) = explode ( self :: $delimiter , $decodedFolderName , 2 );
2016-05-03 21:17:44 +02:00
list ( $newProfileID , $_newLocation ) = explode ( self :: $delimiter , $_newLocation2 , 2 );
2017-04-13 16:26:59 +02:00
if ( $profileID != $this -> mail_bo -> profileID || $profileID != $newProfileID ) $this -> changeProfile ( $profileID );
$del = $this -> mail_bo -> getHierarchyDelimiter ( false );
2014-01-06 13:57:53 +01:00
$hasChildren = false ;
if ( is_numeric ( $profileID ))
{
$pA = explode ( $del , $folderName );
$namePart = array_pop ( $pA );
$_newName = $namePart ;
2014-01-06 15:26:33 +01:00
$oldParentFolder = implode ( $del , $pA );
2014-01-06 13:57:53 +01:00
$parentFolder = $_newLocation ;
2014-07-16 15:42:36 +02:00
2014-01-10 14:07:01 +01:00
if ( strtoupper ( $folderName ) != 'INBOX' &&
(( $oldParentFolder === $parentFolder ) || //$oldParentFolder == $parentFolder means move on same level
(( $oldParentFolder != $parentFolder &&
strlen ( $parentFolder ) > 0 && strlen ( $folderName ) > 0 &&
strpos ( $parentFolder , $folderName ) === false )))) // indicates that we move the older up the tree within its own branch
2014-01-06 13:57:53 +01:00
{
//error_log(__METHOD__.__LINE__."$folderName, $parentFolder, $_newName");
2014-07-31 12:10:07 +02:00
$oldFolderInfo = $this -> mail_bo -> getFolderStatus ( $folderName , false , false , false );
2014-01-06 13:57:53 +01:00
//error_log(__METHOD__.__LINE__.array2string($oldFolderInfo));
if ( ! empty ( $oldFolderInfo [ 'attributes' ]) && stripos ( array2string ( $oldFolderInfo [ 'attributes' ]), '\hasnochildren' ) === false )
{
$hasChildren = true ; // translates to: hasChildren -> dynamicLoading
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ();
$nameSpace = $this -> mail_bo -> _getNameSpaces ();
$prefix = $this -> mail_bo -> getFolderPrefixFromNamespace ( $nameSpace , $folderName );
//error_log(__METHOD__.__LINE__.'->'."$_folderName, $delimiter, $prefix");
2014-08-11 16:16:26 +02:00
2014-01-06 13:57:53 +01:00
$subFolders = $this -> mail_bo -> getMailBoxesRecursive ( $folderName , $delimiter , $prefix );
foreach ( $subFolders as $k => $folder )
{
// we do not monitor failure or success on subfolders
if ( $folder == $folderName )
{
unset ( $subFolders [ $k ]);
}
else
{
2014-08-18 12:33:22 +02:00
$rv = $this -> mail_bo -> icServer -> subscribeMailbox ( $folder , false );
2014-01-06 13:57:53 +01:00
}
}
}
$this -> mail_bo -> reopen ( 'INBOX' );
$success = false ;
try
{
2014-05-22 09:47:49 +02:00
if (( $newFolderName = $this -> mail_bo -> renameFolder ( $folderName , $parentFolder , $_newName )))
{
2014-01-06 13:57:53 +01:00
$this -> mail_bo -> resetFolderObjectCache ( $profileID );
//enforce the subscription to the newly named server, as it seems to fail for names with umlauts
2016-05-03 21:17:44 +02:00
$this -> mail_bo -> icServer -> subscribeMailbox ( $newFolderName , true );
$this -> mail_bo -> icServer -> subscribeMailbox ( $folderName , false );
2014-01-06 16:47:19 +01:00
$this -> mail_bo -> resetFolderObjectCache ( $profileID );
2014-01-06 13:57:53 +01:00
$success = true ;
}
}
catch ( Exception $e )
{
$newFolderName = $folderName ;
$msg = $e -> getMessage ();
}
2014-01-06 15:26:33 +01:00
$this -> mail_bo -> reopen ( $parentFolder );
2014-07-31 12:10:07 +02:00
$this -> mail_bo -> getFolderStatus ( $parentFolder , false , false , false );
2014-01-06 13:57:53 +01:00
//error_log(__METHOD__.__LINE__.array2string($fS));
if ( $hasChildren )
{
2014-01-06 15:26:33 +01:00
$subFolders = $this -> mail_bo -> getMailBoxesRecursive ( $parentFolder , $delimiter , $prefix );
2014-01-06 13:57:53 +01:00
foreach ( $subFolders as $k => $folder )
{
// we do not monitor failure or success on subfolders
if ( $folder == $folderName )
{
unset ( $subFolders [ $k ]);
}
else
{
2014-08-18 12:33:22 +02:00
$rv = $this -> mail_bo -> icServer -> subscribeMailbox ( $folder , true );
2014-01-06 13:57:53 +01:00
}
}
//error_log(__METHOD__.__LINE__.' Fetched Subfolders->'.array2string($subFolders));
}
}
}
if ( $folderName == $this -> mail_bo -> sessionData [ 'mailbox' ])
{
$this -> mail_bo -> sessionData [ 'mailbox' ] = $newFolderName ;
$this -> mail_bo -> saveSessionData ();
}
//error_log(__METHOD__.__LINE__.array2string($oA));
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-01-06 16:47:19 +01:00
if ( $success )
2014-01-06 13:57:53 +01:00
{
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2014-01-27 13:18:16 +01:00
2014-07-31 12:10:07 +02:00
$oldFolderInfo = $this -> mail_bo -> getFolderStatus ( $oldParentFolder , false , false , false );
$folderInfo = $this -> mail_bo -> getFolderStatus ( $parentFolder , false , false , false );
2014-01-06 16:47:19 +01:00
$refreshData = array (
2014-01-06 15:26:33 +01:00
$profileID . self :: $delimiter . $oldParentFolder => $oldFolderInfo [ 'shortDisplayName' ],
2014-01-06 16:47:19 +01:00
$profileID . self :: $delimiter . $parentFolder => $folderInfo [ 'shortDisplayName' ]);
// if we move the folder within the same parent-branch of the tree, there is no need no refresh the upper part
2014-01-09 09:36:22 +01:00
if ( strlen ( $parentFolder ) > strlen ( $oldParentFolder ) && strpos ( $parentFolder , $oldParentFolder ) !== false ) unset ( $refreshData [ $profileID . self :: $delimiter . $parentFolder ]);
if ( count ( $refreshData ) > 1 && strlen ( $oldParentFolder ) > strlen ( $parentFolder ) && strpos ( $oldParentFolder , $parentFolder ) !== false ) unset ( $refreshData [ $profileID . self :: $delimiter . $oldParentFolder ]);
2014-01-18 15:52:47 +01:00
2014-01-11 12:58:31 +01:00
// Send full info back in the response
foreach ( $refreshData as $folder => & $name )
{
2015-08-03 16:33:18 +02:00
$name = $this -> mail_tree -> getTree ( $folder , $profileID , 1 , false , ! $this -> mail_bo -> mailPreferences [ 'showAllFoldersInFolderPane' ], true );
2014-01-11 12:58:31 +01:00
}
$response -> call ( 'app.mail.mail_reloadNode' , $refreshData );
2014-01-06 15:26:33 +01:00
2014-01-06 13:57:53 +01:00
}
else
{
2014-05-27 15:31:37 +02:00
$response -> call ( 'egw.refresh' , lang ( 'failed to move %1 ! Reason: %2' , $folderName , $msg ), 'mail' );
2014-01-06 13:57:53 +01:00
}
}
}
2013-05-13 16:42:42 +02:00
/**
* ajax_deleteFolder - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
* @ param string $_folderName folder to delete
2015-08-11 18:28:59 +02:00
* @ param boolean $_return = false wheter return the success value ( true ) or send response to client ( false )
2013-05-13 16:42:42 +02:00
* @ return nothing
*/
2015-08-11 18:28:59 +02:00
function ajax_deleteFolder ( $_folderName , $_return = false )
2013-05-13 16:42:42 +02:00
{
2013-05-21 10:46:54 +02:00
//error_log(__METHOD__.__LINE__.' OldFolderName:'.array2string($_folderName));
2013-05-13 16:42:42 +02:00
$success = false ;
if ( $_folderName )
{
$decodedFolderName = $this -> mail_bo -> decodeEntityFolderName ( $_folderName );
$oA = array ();
list ( $profileID , $folderName ) = explode ( self :: $delimiter , $decodedFolderName , 2 );
2017-04-13 16:26:59 +02:00
if ( is_numeric ( $profileID ) && $profileID != $this -> mail_bo -> profileID ) $this -> changeProfile ( $profileID );
$del = $this -> mail_bo -> getHierarchyDelimiter ( false );
2013-05-13 16:42:42 +02:00
$hasChildren = false ;
if ( is_numeric ( $profileID ))
{
$pA = explode ( $del , $folderName );
array_pop ( $pA );
if ( strtoupper ( $folderName ) != 'INBOX' )
{
2014-07-16 18:34:15 +02:00
//error_log(__METHOD__.__LINE__."$folderName, implode($del,$pA), $_newName");
2013-05-13 16:42:42 +02:00
$oA = array ();
2013-12-12 14:34:35 +01:00
$subFolders = array ();
2014-07-31 12:10:07 +02:00
$oldFolderInfo = $this -> mail_bo -> getFolderStatus ( $folderName , false , false , false );
2013-05-13 16:42:42 +02:00
//error_log(__METHOD__.__LINE__.array2string($oldFolderInfo));
if ( ! empty ( $oldFolderInfo [ 'attributes' ]) && stripos ( array2string ( $oldFolderInfo [ 'attributes' ]), '\hasnochildren' ) === false )
{
$hasChildren = true ; // translates to: hasChildren -> dynamicLoading
2014-07-16 18:34:15 +02:00
$ftD = array ();
2013-12-12 14:34:35 +01:00
$delimiter = $this -> mail_bo -> getHierarchyDelimiter ();
$nameSpace = $this -> mail_bo -> _getNameSpaces ();
$prefix = $this -> mail_bo -> getFolderPrefixFromNamespace ( $nameSpace , $folderName );
//error_log(__METHOD__.__LINE__.'->'."$_folderName, $delimiter, $prefix");
$subFolders = $this -> mail_bo -> getMailBoxesRecursive ( $folderName , $delimiter , $prefix );
//error_log(__METHOD__.__LINE__.'->'."$folderName, $delimiter, $prefix");
foreach ( $subFolders as $k => $f )
{
$ftD [ substr_count ( $f , $delimiter )][] = $f ;
}
krsort ( $ftD , SORT_NUMERIC ); //sort per level
//we iterate per level of depth of the subtree, deepest nesting is to be deleted first, and then up the tree
foreach ( $ftD as $k => $lc ) //collection per level
{
2016-05-03 21:17:44 +02:00
foreach ( $lc as $f ) //folders contained in that level
2013-12-12 14:34:35 +01:00
{
try
{
//error_log(__METHOD__.__LINE__.array2string($f).'<->'.$folderName);
$this -> mail_bo -> deleteFolder ( $f );
$success = true ;
if ( $f == $folderName ) $oA [ $_folderName ] = $oldFolderInfo [ 'shortDisplayName' ];
}
catch ( Exception $e )
{
$msg .= ( $msg ? ' ' : '' ) . lang ( " Failed to delete %1. Server responded: " , $f ) . $e -> getMessage ();
$success = false ;
}
}
}
2013-05-13 16:42:42 +02:00
}
else
{
2013-12-12 14:34:35 +01:00
try
2013-05-13 16:42:42 +02:00
{
2013-12-12 14:34:35 +01:00
$this -> mail_bo -> deleteFolder ( $folderName );
$success = true ;
$oA [ $_folderName ] = $oldFolderInfo [ 'shortDisplayName' ];
2013-05-13 16:42:42 +02:00
}
2013-12-12 14:34:35 +01:00
catch ( Exception $e )
2013-05-13 16:42:42 +02:00
{
2013-12-12 14:34:35 +01:00
$msg = $e -> getMessage ();
$success = false ;
2013-05-13 16:42:42 +02:00
}
}
}
else
{
$msg = lang ( " refused to delete folder INBOX " );
}
}
2015-08-11 18:28:59 +02:00
if ( $_return ) return $success ;
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2013-05-13 16:42:42 +02:00
if ( $success )
{
2013-05-21 10:46:54 +02:00
//error_log(__METHOD__.__LINE__.array2string($oA));
2014-01-13 14:06:29 +01:00
$response -> call ( 'app.mail.mail_removeLeaf' , $oA );
2013-05-13 16:42:42 +02:00
}
else
{
2014-05-27 15:31:37 +02:00
$response -> call ( 'egw.refresh' , lang ( 'failed to delete %1 ! Reason: %2' , $oldFolderInfo [ 'shortDisplayName' ], $msg ), 'mail' );
2013-05-13 16:42:42 +02:00
}
}
}
2013-02-20 12:31:57 +01:00
/**
* empty changeProfile - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
*
2014-08-20 16:58:12 +02:00
* Made static to NOT call __construct , as it would connect to old server , before going to new one
*
2014-05-22 09:47:49 +02:00
* @ param int $icServerID New profile / server ID
2014-01-22 10:32:18 +01:00
* @ param bool $getFolders The client needs the folders for the profile
2013-02-20 12:31:57 +01:00
* @ return nothing
*/
2014-08-20 16:58:12 +02:00
public static function ajax_changeProfile ( $icServerID , $getFolders = true , $exec_id = null )
2013-02-20 12:31:57 +01:00
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-07-08 13:09:31 +02:00
2014-08-20 16:58:12 +02:00
$previous_id = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ];
if ( $icServerID && $icServerID != $previous_id )
2013-10-18 11:58:25 +02:00
{
2014-08-20 16:58:12 +02:00
$mail_ui = new mail_ui ( false ); // do NOT run constructor, as we call changeProfile anyway
2014-06-30 17:48:49 +02:00
try
{
2014-08-20 16:58:12 +02:00
$mail_ui -> changeProfile ( $icServerID );
2014-08-13 13:45:55 +02:00
// if we have an eTemplate exec_id, also send changed actions
2014-08-20 16:58:12 +02:00
if ( $exec_id && ( $actions = $mail_ui -> get_actions ()))
2014-08-13 13:45:55 +02:00
{
$response -> generic ( 'assign' , array (
'etemplate_exec_id' => $exec_id ,
'id' => 'nm' ,
'key' => 'actions' ,
'value' => $actions ,
));
}
2014-06-30 17:48:49 +02:00
}
catch ( Exception $e ) {
2014-08-08 15:36:33 +02:00
self :: callWizard ( $e -> getMessage (), true , 'error' );
2014-06-30 17:48:49 +02:00
}
2014-08-20 16:58:12 +02:00
}
else
{
$mail_ui = new mail_ui ( true ); // run constructor
2013-10-18 11:58:25 +02:00
}
2013-02-20 12:31:57 +01:00
}
2014-04-03 14:20:23 +02:00
/**
* ajax_refreshVacationNotice - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
* Note : only the activeProfile VacationNotice is refreshed
2014-05-22 09:47:49 +02:00
* @ param int $icServerID profileId / server ID to work on ; may be empty -> then activeProfile is used
2014-04-03 14:20:23 +02:00
* if other than active profile ; nothing is done !
* @ return nothing
*/
2014-08-11 14:14:27 +02:00
public static function ajax_refreshVacationNotice ( $icServerID = null )
2014-04-03 14:20:23 +02:00
{
2014-08-11 14:14:27 +02:00
//Get vacation from cache if it's available
2016-05-03 21:17:44 +02:00
$cachedVacations = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'vacationNotice' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ]);
2014-08-11 14:14:27 +02:00
$vacation = $cachedVacations [ $icServerID ];
if ( ! $vacation )
{
2016-06-09 15:46:51 +02:00
try
{
// Create mail app object
$mail = new mail_ui ();
2014-08-11 16:16:26 +02:00
2016-06-09 15:46:51 +02:00
if ( empty ( $icServerID )) $icServerID = $mail -> Mail -> profileID ;
if ( $icServerID != $mail -> Mail -> profileID ) return ;
2014-08-11 16:16:26 +02:00
2016-06-09 15:46:51 +02:00
$vacation = $mail -> gatherVacation ( $cachedVacations );
} catch ( Exception $e ) {
$vacation = false ;
error_log ( __METHOD__ . __LINE__ . " " . $e -> getMessage ());
unset ( $e );
}
2014-08-11 14:14:27 +02:00
}
2014-08-11 16:16:26 +02:00
2014-04-03 14:20:23 +02:00
if ( $vacation ) {
if ( is_array ( $vacation ) && ( $vacation [ 'status' ] == 'on' || $vacation [ 'status' ] == 'by_date' ))
{
2014-07-16 15:42:36 +02:00
$dtfrmt = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'dateformat' ];
2014-04-03 14:20:23 +02:00
$refreshData [ 'vacationnotice' ] = lang ( 'Vacation notice is active' );
2016-05-03 21:17:44 +02:00
$refreshData [ 'vacationrange' ] = ( $vacation [ 'status' ] == 'by_date' ? Api\DateTime :: server2user ( $vacation [ 'start_date' ], $dtfrmt , true ) . ( $vacation [ 'end_date' ] > $vacation [ 'start_date' ] ? '->' . Api\DateTime :: server2user ( $vacation [ 'end_date' ] + 24 * 3600 - 1 , $dtfrmt , true ) : '' ) : '' );
2022-12-06 00:27:39 +01:00
if ( $vacation [ 'status' ] == 'by_date' && $vacation [ 'end_date' ] + 24 * 3600 < time ())
{
$refreshData = null ;
}
2014-04-03 14:20:23 +02:00
}
}
if ( $vacation == false )
{
2022-12-06 00:27:39 +01:00
$refreshData = null ;
2014-04-03 14:20:23 +02:00
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-04-03 14:20:23 +02:00
$response -> call ( 'app.mail.mail_refreshVacationNotice' , $refreshData );
}
2014-04-11 15:52:58 +02:00
/**
* ajax_refreshFilters - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
* Note : only the activeProfile Filters are refreshed
2014-05-22 09:47:49 +02:00
* @ param int $icServerID profileId / server ID to work on ; may be empty -> then activeProfile is used
2014-04-11 15:52:58 +02:00
* if other than active profile ; nothing is done !
* @ return nothing
*/
2014-05-22 09:47:49 +02:00
function ajax_refreshFilters ( $icServerID = null )
2014-04-11 15:52:58 +02:00
{
//error_log(__METHOD__.__LINE__.array2string($icServerId));
if ( empty ( $icServerID )) $icServerID = $this -> mail_bo -> profileID ;
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $supportsORinQuery ) || ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ]))
2014-04-11 15:52:58 +02:00
{
2016-05-03 21:17:44 +02:00
Mail :: $supportsORinQuery = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'supportsORinQuery' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), 60 * 60 * 10 );
2016-03-28 20:51:38 +02:00
if ( ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])) Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] = true ;
2014-04-11 15:52:58 +02:00
}
2016-03-28 20:51:38 +02:00
if ( ! Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])
2014-04-11 15:52:58 +02:00
{
unset ( $this -> searchTypes [ 'quick' ]);
2016-03-24 11:38:35 +01:00
unset ( $this -> searchTypes [ 'quickwithcc' ]);
2014-04-11 15:52:58 +02:00
}
if ( $this -> mail_bo -> icServer -> hasCapability ( 'SUPPORTS_KEYWORDS' ))
{
$this -> statusTypes = array_merge ( $this -> statusTypes , array (
'keyword1' => 'important' , //lang('important'),
'keyword2' => 'job' , //lang('job'),
'keyword3' => 'personal' , //lang('personal'),
'keyword4' => 'to do' , //lang('to do'),
'keyword5' => 'later' , //lang('later'),
));
}
else
{
2014-07-16 18:34:15 +02:00
$keywords = array ( 'keyword1' , 'keyword2' , 'keyword3' , 'keyword4' , 'keyword5' );
foreach ( $keywords as & $k )
2014-04-11 15:52:58 +02:00
{
if ( array_key_exists ( $k , $this -> statusTypes )) unset ( $this -> statusTypes [ $k ]);
}
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2016-02-25 13:26:50 +01:00
$response -> call ( 'app.mail.mail_refreshCatIdOptions' , $this -> searchTypes );
2014-04-11 15:52:58 +02:00
$response -> call ( 'app.mail.mail_refreshFilterOptions' , $this -> statusTypes );
2016-07-15 09:57:18 +02:00
$response -> call ( 'app.mail.mail_refreshFilter2Options' , array ( '' => lang ( 'No Sneak Preview in list' ), 1 => lang ( 'Sneak Preview in list' )));
2014-04-11 15:52:58 +02:00
}
2013-10-18 11:58:25 +02:00
/**
2017-03-10 11:22:51 +01:00
* This function asks quota from IMAP server and makes the
* result as JSON response to send it to mail_sendQuotaDisplay
* function in client side .
*
* @ param string $icServerID = null
2013-10-18 11:58:25 +02:00
*
*/
function ajax_refreshQuotaDisplay ( $icServerID = null )
{
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2013-10-18 11:58:25 +02:00
if ( is_null ( $icServerID )) $icServerID = $this -> mail_bo -> profileID ;
2014-01-17 10:59:25 +01:00
$rememberServerID = $this -> mail_bo -> profileID ;
2014-07-31 12:42:56 +02:00
try
{
2016-06-09 15:46:51 +02:00
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $icServerID );
}
2013-10-18 11:58:25 +02:00
$quota = $this -> mail_bo -> getQuotaRoot ();
2014-07-31 12:42:56 +02:00
} catch ( Exception $e ) {
2013-10-18 11:58:25 +02:00
$quota [ 'limit' ] = 'NOT SET' ;
2014-10-23 15:59:12 +02:00
error_log ( __METHOD__ . __LINE__ . " " . $e -> getMessage ());
2016-06-07 15:25:33 +02:00
unset ( $e );
2013-10-18 11:58:25 +02:00
}
if ( $quota !== false && $quota [ 'limit' ] != 'NOT SET' ) {
$quotainfo = $this -> quotaDisplay ( $quota [ 'usage' ], $quota [ 'limit' ]);
2017-04-18 17:48:16 +02:00
$quotaMin = ceil ( $quotainfo [ 'freespace' ] / pow ( 1024 , 2 ));
$quota_limit_warning = isset ( mail :: $mailConfig [ 'quota_limit_warning' ]) ? mail :: $mailConfig [ 'quota_limit_warning' ] : 30 ;
2017-03-10 11:22:51 +01:00
$content = array (
'quota' => $quotainfo [ 'text' ],
2017-03-10 11:40:28 +01:00
'quotainpercent' => ( string ) $quotainfo [ 'percent' ],
2017-03-10 11:22:51 +01:00
'quotaclass' => $quotainfo [ 'class' ],
'quotanotsupported' => " " ,
2017-03-13 10:49:32 +01:00
'profileid' => $icServerID ,
2017-04-18 17:48:16 +02:00
'quotawarning' => $quotaMin < $quota_limit_warning ? true : false ,
'quotafreespace' => Mail :: show_readable_size ( $quotainfo [ 'freespace' ])
2017-03-10 11:22:51 +01:00
);
}
else
{
$content = array (
'quota' => lang ( " Quota not provided by server " ),
'quotaclass' => " mail_DisplayNone " ,
'quotanotsupported' => " mail_DisplayNone "
);
2013-10-18 11:58:25 +02:00
}
2014-01-17 10:59:25 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
2016-06-09 15:46:51 +02:00
try
{
$this -> changeProfile ( $rememberServerID );
} catch ( Exception $e ) {
unset ( $e );
}
2014-01-17 10:59:25 +01:00
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-01-13 14:06:29 +01:00
$response -> call ( 'app.mail.mail_setQuotaDisplay' , array ( 'data' => $content ));
2013-10-18 11:58:25 +02:00
}
2015-02-19 13:01:18 +01:00
/**
* 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);
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
$response = Api\Json\Response :: get ();
2015-02-19 13:01:18 +01:00
$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 )
{
2015-02-19 14:41:40 +01:00
// Lock the tree if the active folder is junk folder
2015-02-19 13:01:18 +01:00
$response -> call ( 'app.mail.lock_tree' );
}
$this -> mail_bo -> deleteMessages ( 'all' , $junkFolder , 'remove_immediately' );
$fStatus = array (
2024-09-06 12:21:11 +02:00
$icServerID . self :: $delimiter . $junkFolder => 0
2015-02-19 13:01:18 +01:00
);
//Call to reset folder status counter, after junkFolder triggered not from Junk folder
2015-02-19 14:41:40 +01:00
//-as we don't have junk folder specific information available on client-side we need to deal with it on server
2015-02-19 13:01:18 +01:00
$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' );
}
}
2013-02-12 18:48:04 +01:00
/**
2014-08-08 12:04:49 +02:00
* Empty trash folder
2013-02-12 18:48:04 +01:00
*
2014-01-17 10:59:25 +01:00
* @ param string $icServerID id of the server to empty its trashFolder
2014-08-08 12:04:49 +02:00
* @ param string $selectedFolder seleted ( active ) folder by nm filter
2013-02-12 18:48:04 +01:00
* @ return nothing
*/
2014-08-08 12:04:49 +02:00
function ajax_emptyTrash ( $icServerID , $selectedFolder )
2013-02-12 18:48:04 +01:00
{
2014-01-27 13:18:16 +01:00
//error_log(__METHOD__.__LINE__.' '.$icServerID);
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
$response = Api\Json\Response :: get ();
2014-01-17 10:59:25 +01:00
$rememberServerID = $this -> mail_bo -> profileID ;
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2013-02-12 18:48:04 +01:00
$trashFolder = $this -> mail_bo -> getTrashFolder ();
if ( ! empty ( $trashFolder )) {
2014-08-08 12:04:49 +02:00
if ( $selectedFolder == $icServerID . self :: $delimiter . $trashFolder )
{
// Lock the tree if the active folder is Trash folder
$response -> call ( 'app.mail.lock_tree' );
}
2013-02-12 18:48:04 +01:00
$this -> mail_bo -> compressFolder ( $trashFolder );
2014-08-14 13:28:55 +02:00
$fStatus = array (
2024-09-06 12:21:11 +02:00
$icServerID . self :: $delimiter . $trashFolder => 0
2014-08-14 13:28:55 +02:00
);
//Call to reset folder status counter, after emptyTrash triggered not from Trash folder
//-as we don't have trash folder specific information available on client-side we need to deal with it on server
$response -> call ( 'app.mail.mail_setFolderStatus' , $fStatus );
2013-02-12 18:48:04 +01:00
}
2014-01-17 10:59:25 +01:00
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
2014-07-31 12:10:07 +02:00
$oldFolderInfo = $this -> mail_bo -> getFolderStatus ( $trashFolder , false , false , false );
2014-05-27 15:31:37 +02:00
$response -> call ( 'egw.message' , lang ( 'empty trash' ));
2014-01-17 10:59:25 +01:00
$response -> call ( 'app.mail.mail_reloadNode' , array ( $icServerID . self :: $delimiter . $trashFolder => $oldFolderInfo [ 'shortDisplayName' ]));
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$rememberServerID);
$this -> changeProfile ( $rememberServerID );
}
2014-08-08 12:04:49 +02:00
else if ( $selectedFolder == $icServerID . self :: $delimiter . $trashFolder )
2014-01-17 10:59:25 +01:00
{
2014-05-27 15:31:37 +02:00
$response -> call ( 'egw.refresh' , lang ( 'empty trash' ), 'mail' );
2014-01-17 10:59:25 +01:00
}
2013-02-12 18:48:04 +01:00
}
2013-02-13 16:35:12 +01:00
/**
* compress folder - its called via json , so the function must start with ajax ( or the class - name must contain ajax )
* fetches the current folder from session and compresses it
2014-01-17 10:59:25 +01:00
* @ param string $_folderName id of the folder to compress
2013-02-13 16:35:12 +01:00
* @ return nothing
*/
2014-01-17 10:59:25 +01:00
function ajax_compressFolder ( $_folderName )
2013-02-13 16:35:12 +01:00
{
2014-01-27 13:18:16 +01:00
//error_log(__METHOD__.__LINE__.' '.$_folderName);
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2014-01-27 13:18:16 +01:00
2013-02-13 16:35:12 +01:00
$this -> mail_bo -> restoreSessionData ();
2014-01-17 10:59:25 +01:00
$decodedFolderName = $this -> mail_bo -> decodeEntityFolderName ( $_folderName );
list ( $icServerID , $folderName ) = explode ( self :: $delimiter , $decodedFolderName , 2 );
if ( empty ( $folderName )) $folderName = $this -> mail_bo -> sessionData [ 'mailbox' ];
if ( $this -> mail_bo -> folderExists ( $folderName ))
2013-02-13 16:35:12 +01:00
{
2014-01-17 10:59:25 +01:00
$rememberServerID = $this -> mail_bo -> profileID ;
if ( $icServerID && $icServerID != $this -> mail_bo -> profileID )
{
//error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID);
$this -> changeProfile ( $icServerID );
}
2015-04-27 15:42:45 +02:00
if ( ! empty ( $_folderName )) {
2014-01-17 10:59:25 +01:00
$this -> mail_bo -> compressFolder ( $folderName );
}
if ( $rememberServerID != $this -> mail_bo -> profileID )
{
2014-11-06 14:11:44 +01:00
//error_log(__METHOD__.__LINE__.' change Profile back to where we came from ->'.$rememberServerID);
2014-01-17 10:59:25 +01:00
$this -> changeProfile ( $rememberServerID );
2013-02-13 16:35:12 +01:00
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-05-27 15:31:37 +02:00
$response -> call ( 'egw.refresh' , lang ( 'compress folder' ) . ': ' . $folderName , 'mail' );
2013-02-13 16:35:12 +01:00
}
}
2014-03-25 17:20:28 +01:00
/**
* sendMDN , ...
*
* @ param array _messageList list of UID ' s
*
* @ return nothing
*/
function ajax_sendMDN ( $_messageList )
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> " . array2string ( $_messageList ));
2014-03-25 17:20:28 +01:00
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
2021-10-26 11:09:59 +02:00
if ( $uidA [ 'profileID' ] && $uidA [ 'profileID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $uidA [ 'profileID' ]);
}
2014-03-25 17:20:28 +01:00
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
$this -> mail_bo -> sendMDN ( $uidA [ 'msgUID' ], $folder );
}
2013-02-19 17:30:59 +01:00
/**
* flag messages as read , unread , flagged , ...
*
* @ param string _flag name of the flag
* @ param array _messageList list of UID ' s
2014-01-21 15:46:00 +01:00
* @ param bool _sendJsonResponse tell fuction to send the JsonResponse
2013-02-19 17:30:59 +01:00
*
* @ return xajax response
*/
2014-01-21 15:46:00 +01:00
function ajax_flagMessages ( $_flag , $_messageList , $_sendJsonResponse = true )
2013-02-19 17:30:59 +01:00
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> " . $_flag . ':' . array2string ( $_messageList ));
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
2014-05-27 14:05:23 +02:00
$alreadyFlagged = false ;
2014-07-08 10:50:43 +02:00
$flag2check = '' ;
$filter2toggle = $query = array ();
2013-02-19 17:30:59 +01:00
if ( $_messageList == 'all' || ! empty ( $_messageList [ 'msg' ]))
{
2014-05-27 14:05:23 +02:00
if ( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ])
2013-02-19 17:30:59 +01:00
{
2014-05-27 14:05:23 +02:00
// we have both messageIds AND allFlag folder information
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
2021-10-26 11:09:59 +02:00
if ( $uidA [ 'profileID' ] && $uidA [ 'profileID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $uidA [ 'profileID' ]);
}
2014-05-27 14:05:23 +02:00
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
2024-09-27 13:47:31 +02:00
//_messageList['msg'][0] was in form of {accountID}::{folderName}
// so we need to correct $folder and $profileID
2019-05-14 22:08:36 +02:00
if ( ! $folder && ! $uidA [ 'msg' ] && $uidA [ 'accountID' ])
{
$folder = $uidA [ 'accountID' ];
}
2024-09-27 13:47:31 +02:00
$profileID = $uidA [ 'profileID' ];
if ( ! $profileID && ! $uidA [ 'msg' ] && $uidA [ 'app' ])
{
$profileID = $uidA [ 'app' ];
}
//end correction
2014-05-27 14:05:23 +02:00
if ( isset ( $_messageList [ 'activeFilters' ]) && $_messageList [ 'activeFilters' ])
{
$query = $_messageList [ 'activeFilters' ];
2016-04-12 17:17:57 +02:00
if ( ! empty ( $query [ 'search' ]) || ! empty ( $query [ 'filter' ]) || ( $query [ 'cat_id' ] == 'bydate' && ( ! empty ( $query [ 'startdate' ]) ||! empty ( $query [ 'enddate' ]))))
2014-05-27 14:05:23 +02:00
{
//([filterName] => Schnellsuche[type] => quick[string] => ebay[status] => any
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $supportsORinQuery ) || ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ]))
2014-05-27 14:05:23 +02:00
{
2016-05-03 21:17:44 +02:00
Mail :: $supportsORinQuery = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'supportsORinQuery' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), 60 * 60 * 10 );
2016-03-28 20:51:38 +02:00
if ( ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])) Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] = true ;
2014-05-27 14:05:23 +02:00
}
2016-04-12 17:17:57 +02:00
//error_log(__METHOD__.__LINE__.' Startdate:'.$query['startdate'].' Enddate'.$query['enddate']);
$cutoffdate = $cutoffdate2 = null ;
2016-05-03 21:17:44 +02:00
if ( $query [ 'startdate' ]) $cutoffdate = Api\DateTime :: to ( $query [ 'startdate' ], 'ts' ); //SINCE, enddate
if ( $query [ 'enddate' ]) $cutoffdate2 = Api\DateTime :: to ( $query [ 'enddate' ], 'ts' ); //BEFORE, startdate
2016-04-12 17:17:57 +02:00
//error_log(__METHOD__.__LINE__.' Startdate:'.$cutoffdate2.' Enddate'.$cutoffdate);
$filter = array (
2021-03-30 20:34:34 +02:00
'filterName' => lang ( 'subject' ),
'type' => ( $query [ 'cat_id' ] ? $query [ 'cat_id' ] : 'subject' ),
2016-04-12 17:17:57 +02:00
'string' => $query [ 'search' ],
'status' => 'any' , //this is a status change. status will be manipulated later on
//'range'=>"BETWEEN",'since'=> date("d-M-Y", $cutoffdate),'before'=> date("d-M-Y", $cutoffdate2)
);
if ( $query [ 'enddate' ] || $query [ 'startdate' ]) {
$filter [ 'range' ] = " BETWEEN " ;
if ( $cutoffdate ) {
$filter [( empty ( $cutoffdate2 ) ? 'date' : 'since' )] = date ( " d-M-Y " , $cutoffdate );
if ( empty ( $cutoffdate2 )) $filter [ 'range' ] = " SINCE " ;
}
if ( $cutoffdate2 ) {
$filter [( empty ( $cutoffdate ) ? 'date' : 'before' )] = date ( " d-M-Y " , $cutoffdate2 );
if ( empty ( $cutoffdate )) $filter [ 'range' ] = " BEFORE " ;
}
}
$filter2toggle = $filter ;
2014-05-27 14:05:23 +02:00
}
else
{
$filter = $filter2toggle = array ();
}
// flags read,flagged,label1,label2,label3,label4,label5 can be toggled: handle this when all mails in a folder
// should be affected serverside. here.
$messageList = $messageListForToggle = array ();
2014-07-08 10:50:43 +02:00
$flag2check = ( $_flag == 'read' ? 'seen' : $_flag );
if ( in_array ( $_flag , array ( 'read' , 'flagged' , 'label1' , 'label2' , 'label3' , 'label4' , 'label5' )) &&
! ( $flag2check == $query [ 'filter' ] || stripos ( $query [ 'filter' ], $flag2check ) !== false ))
2014-05-27 14:05:23 +02:00
{
$filter2toggle [ 'status' ] = array ( 'un' . $_flag );
2014-07-08 10:50:43 +02:00
if ( $query [ 'filter' ] && $query [ 'filter' ] != 'any' )
2014-05-27 14:05:23 +02:00
{
$filter2toggle [ 'status' ][] = $query [ 'filter' ];
}
2021-03-30 20:34:34 +02:00
$reverse = 1 ;
$rByUid = true ;
2014-07-08 10:50:43 +02:00
$_sRt = $this -> mail_bo -> getSortedList (
2014-05-27 14:05:23 +02:00
$folder ,
2017-03-07 15:20:11 +01:00
$sort = 0 ,
2021-03-30 20:34:34 +02:00
$reverse ,
2014-05-27 14:05:23 +02:00
$filter2toggle ,
2021-03-30 20:34:34 +02:00
$rByUid ,
2014-05-27 14:05:23 +02:00
false
);
2014-07-08 10:50:43 +02:00
$messageListForToggle = $_sRt [ 'match' ] -> ids ;
2014-05-27 14:05:23 +02:00
$filter [ 'status' ] = array ( $_flag );
2014-07-08 10:50:43 +02:00
if ( $query [ 'filter' ] && $query [ 'filter' ] != 'any' )
2014-05-27 14:05:23 +02:00
{
$filter [ 'status' ][] = $query [ 'filter' ];
}
2021-03-30 20:34:34 +02:00
$reverse = 1 ;
$rByUid = true ;
2014-05-27 14:05:23 +02:00
$_sR = $this -> mail_bo -> getSortedList (
$folder ,
2017-03-07 15:20:11 +01:00
$sort = 0 ,
2021-03-30 20:34:34 +02:00
$reverse ,
2014-05-27 14:05:23 +02:00
$filter ,
2021-03-30 20:34:34 +02:00
$rByUid ,
2014-05-27 14:05:23 +02:00
false
);
$messageList = $_sR [ 'match' ] -> ids ;
if ( count ( $messageListForToggle ) > 0 )
{
$flag2set = ( strtolower ( $_flag ));
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . " toggle un $_flag -> $flag2set " . array2string ( $filter2toggle ) . array2string ( $messageListForToggle ));
2014-05-27 14:05:23 +02:00
$this -> mail_bo -> flagMessages ( $flag2set , $messageListForToggle , $folder );
}
if ( count ( $messageList ) > 0 )
{
$flag2set = 'un' . $_flag ;
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . " $_flag -> $flag2set " . array2string ( $filter ) . array2string ( $messageList ));
2014-05-27 14:05:23 +02:00
$this -> mail_bo -> flagMessages ( $flag2set , $messageList , $folder );
}
$alreadyFlagged = true ;
}
2014-07-08 10:50:43 +02:00
elseif ( ! empty ( $filter ) &&
( ! in_array ( $_flag , array ( 'read' , 'flagged' , 'label1' , 'label2' , 'label3' , 'label4' , 'label5' )) ||
( in_array ( $_flag , array ( 'read' , 'flagged' , 'label1' , 'label2' , 'label3' , 'label4' , 'label5' )) &&
( $flag2check == $query [ 'filter' ] || stripos ( $query [ 'filter' ], $flag2check ) !== false ))))
2014-05-27 14:05:23 +02:00
{
2014-08-14 15:49:14 +02:00
if ( $query [ 'filter' ] && $query [ 'filter' ] != 'any' )
{
$filter [ 'status' ] = $query [ 'filter' ];
// since we toggle and we toggle by the filtered flag we must must change _flag
$_flag = ( $query [ 'filter' ] == 'unseen' && $_flag == 'read' ? 'read' : ( $query [ 'filter' ] == 'seen' && $_flag == 'read' ? 'unread' : ( $_flag == $query [ 'filter' ] ? 'un' . $_flag : $_flag )));
}
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . " flag all with $_flag on filter used: " . array2string ( $filter ));
2016-06-14 11:28:03 +02:00
$rByUid = true ;
$reverse = 1 ;
2014-05-27 14:05:23 +02:00
$_sR = $this -> mail_bo -> getSortedList (
$folder ,
$sort = 0 ,
2016-06-14 11:28:03 +02:00
$reverse ,
2014-05-27 14:05:23 +02:00
$filter ,
2016-06-14 11:28:03 +02:00
$rByUid ,
2014-05-27 14:05:23 +02:00
false
);
$messageList = $_sR [ 'match' ] -> ids ;
unset ( $_messageList [ 'all' ]);
$_messageList [ 'msg' ] = array ();
}
else
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . " $_flag all " . array2string ( $filter ));
2014-05-27 14:05:23 +02:00
$alreadyFlagged = true ;
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
$this -> mail_bo -> flagMessages ( $_flag , 'all' , $folder );
2014-07-08 13:09:31 +02:00
}
2014-05-27 14:05:23 +02:00
}
2013-02-19 17:30:59 +01:00
}
else
{
2013-03-05 15:09:35 +01:00
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
2021-10-26 11:09:59 +02:00
if ( $uidA [ 'profileID' ] && $uidA [ 'profileID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $uidA [ 'profileID' ]);
}
2013-02-19 17:30:59 +01:00
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
}
2014-05-27 14:05:23 +02:00
if ( ! $alreadyFlagged )
2013-02-19 17:30:59 +01:00
{
2014-05-27 14:05:23 +02:00
foreach ( $_messageList [ 'msg' ] as $rowID )
{
$hA = self :: splitRowID ( $rowID );
$messageList [] = $hA [ 'msgUID' ];
}
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . " $_flag in $folder : " . array2string ((( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ]) ? 'all' : $messageList )));
2014-05-27 14:05:23 +02:00
$this -> mail_bo -> flagMessages ( $_flag , (( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ]) ? 'all' : $messageList ), $folder );
2013-02-19 17:30:59 +01:00
}
}
else
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> No messages selected. " );
2013-02-19 17:30:59 +01:00
}
2014-01-21 15:46:00 +01:00
if ( $_sendJsonResponse )
{
2016-01-29 15:24:12 +01:00
$flag = array (
'label1' => 'important' , //lang('important'),
'label2' => 'job' , //lang('job'),
'label3' => 'personal' , //lang('personal'),
'label4' => 'to do' , //lang('to do'),
'label5' => 'later' , //lang('later'),
);
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2015-09-21 16:04:48 +02:00
if ( isset ( $_messageList [ 'msg' ]) && $_messageList [ 'popup' ])
{
2018-12-17 10:24:26 +01:00
$response -> call ( 'egw.refresh' , lang ( 'flagged %1 messages as %2 in %3' , $_messageList [ 'msg' ], lang (( $flag [ $_flag ] ? $flag [ $_flag ] : $_flag )), lang ( $folder )), 'mail' , $_messageList [ 'msg' ], 'update' );
2015-09-21 16:04:48 +02:00
}
else if (( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ]) || ( $query [ 'filter' ] && ( $flag2check == $query [ 'filter' ] || stripos ( $query [ 'filter' ], $flag2check ) !== false )))
2014-07-08 10:50:43 +02:00
{
2024-09-27 13:47:31 +02:00
self :: ajax_setFolderStatus ([ $profileID . " :: " . $folder ], true );
2018-12-17 10:24:26 +01:00
$response -> call ( 'egw.refresh' , lang ( 'flagged %1 messages as %2 in %3' ,( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ] ? lang ( 'all' ) : count ( $_messageList [ 'msg' ])), lang (( $flag [ $_flag ] ? $flag [ $_flag ] : $_flag )), lang ( $folder )), 'mail' );
2014-07-08 10:50:43 +02:00
}
else
{
2023-10-04 01:03:37 +02:00
$response -> call (
'egw.refresh' ,
lang ( 'flagged %1 messages as %2 in %3' , ( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ] ? lang ( 'all' ) : count ( $_messageList [ 'msg' ])), lang (( $flag [ $_flag ] ? $flag [ $_flag ] : $_flag )), lang ( $folder )),
'mail' ,
$_messageList [ 'msg' ],
'update-in-place'
);
2014-07-08 10:50:43 +02:00
}
2014-01-21 15:46:00 +01:00
}
2013-02-19 17:30:59 +01:00
}
2013-02-28 10:28:08 +01:00
/**
* delete messages
*
* @ param array _messageList list of UID ' s
2013-05-27 15:48:55 +02:00
* @ param string _forceDeleteMethod - method of deletion to be enforced
2013-02-28 10:28:08 +01:00
* @ return xajax response
*/
2013-05-27 15:48:55 +02:00
function ajax_deleteMessages ( $_messageList , $_forceDeleteMethod = null )
2013-02-28 10:28:08 +01:00
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> " . print_r ( $_messageList , true ) . ' Method:' . $_forceDeleteMethod );
2013-05-27 15:48:55 +02:00
$error = null ;
2014-07-17 11:59:14 +02:00
$filtered = false ;
2013-02-28 10:28:08 +01:00
if ( $_messageList == 'all' || ! empty ( $_messageList [ 'msg' ]))
{
2014-06-20 14:05:03 +02:00
if ( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ])
2013-02-28 10:28:08 +01:00
{
2014-06-20 14:05:03 +02:00
// we have both messageIds AND allFlag folder information
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
2021-10-26 11:09:59 +02:00
if ( $uidA [ 'profileID' ] && $uidA [ 'profileID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $uidA [ 'profileID' ]);
}
2014-06-20 14:05:03 +02:00
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
if ( isset ( $_messageList [ 'activeFilters' ]) && $_messageList [ 'activeFilters' ])
{
$query = $_messageList [ 'activeFilters' ];
2016-04-12 17:17:57 +02:00
if ( ! empty ( $query [ 'search' ]) || ! empty ( $query [ 'filter' ]) || ( $query [ 'cat_id' ] == 'bydate' && ( ! empty ( $query [ 'startdate' ]) ||! empty ( $query [ 'enddate' ]))))
2014-06-20 14:05:03 +02:00
{
//([filterName] => Schnellsuche[type] => quick[string] => ebay[status] => any
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $supportsORinQuery ) || ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ]))
2014-06-20 14:05:03 +02:00
{
2016-05-03 21:17:44 +02:00
Mail :: $supportsORinQuery = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'supportsORinQuery' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), 60 * 60 * 10 );
2016-03-28 20:51:38 +02:00
if ( ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])) Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] = true ;
2014-06-20 14:05:03 +02:00
}
2014-07-17 11:59:14 +02:00
$filtered = true ;
2016-04-12 17:17:57 +02:00
$cutoffdate = $cutoffdate2 = null ;
2016-05-03 21:17:44 +02:00
if ( $query [ 'startdate' ]) $cutoffdate = Api\DateTime :: to ( $query [ 'startdate' ], 'ts' ); //SINCE, enddate
if ( $query [ 'enddate' ]) $cutoffdate2 = Api\DateTime :: to ( $query [ 'enddate' ], 'ts' ); //BEFORE, startdate
2016-04-12 17:17:57 +02:00
//error_log(__METHOD__.__LINE__.' Startdate:'.$cutoffdate2.' Enddate'.$cutoffdate);
$filter = array (
2021-03-30 20:34:34 +02:00
'filterName' => lang ( 'subject' ),
'type' => ( $query [ 'cat_id' ] ? $query [ 'cat_id' ] : 'subject' ),
2016-04-12 17:17:57 +02:00
'string' => $query [ 'search' ],
'status' => ( ! empty ( $query [ 'filter' ]) ? $query [ 'filter' ] : 'any' ),
//'range'=>"BETWEEN",'since'=> date("d-M-Y", $cutoffdate),'before'=> date("d-M-Y", $cutoffdate2)
);
if ( $query [ 'enddate' ] || $query [ 'startdate' ]) {
$filter [ 'range' ] = " BETWEEN " ;
if ( $cutoffdate ) {
$filter [( empty ( $cutoffdate2 ) ? 'date' : 'since' )] = date ( " d-M-Y " , $cutoffdate );
if ( empty ( $cutoffdate2 )) $filter [ 'range' ] = " SINCE " ;
}
if ( $cutoffdate2 ) {
$filter [( empty ( $cutoffdate ) ? 'date' : 'before' )] = date ( " d-M-Y " , $cutoffdate2 );
if ( empty ( $cutoffdate )) $filter [ 'range' ] = " BEFORE " ;
}
}
2014-06-20 14:05:03 +02:00
}
else
{
$filter = array ();
}
2014-07-08 10:50:43 +02:00
//error_log(__METHOD__.__LINE__."->".print_r($filter,true).' folder:'.$folder.' Method:'.$_forceDeleteMethod);
2014-07-16 18:34:15 +02:00
$reverse = 1 ;
$rByUid = true ;
2014-06-20 14:05:03 +02:00
$_sR = $this -> mail_bo -> getSortedList (
$folder ,
$sort = 0 ,
2014-07-16 18:34:15 +02:00
$reverse ,
2014-06-20 14:05:03 +02:00
$filter ,
2014-07-16 18:34:15 +02:00
$rByUid ,
2014-06-20 14:05:03 +02:00
false
);
$messageList = $_sR [ 'match' ] -> ids ;
}
else
{
$messageList = 'all' ;
}
try
{
//error_log(__METHOD__.__LINE__."->".print_r($messageList,true).' folder:'.$folder.' Method:'.$_forceDeleteMethod);
$this -> mail_bo -> deleteMessages (( $messageList == 'all' ? 'all' : $messageList ), $folder ,( empty ( $_forceDeleteMethod ) ? 'no' : $_forceDeleteMethod ));
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2014-06-20 14:05:03 +02:00
{
$error = str_replace ( '"' , " ' " , $e -> getMessage ());
}
2013-02-28 10:28:08 +01:00
}
else
{
2013-03-05 15:09:35 +01:00
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
2021-10-26 11:09:59 +02:00
if ( $uidA [ 'profileID' ] && $uidA [ 'profileID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $uidA [ 'profileID' ]);
}
2013-02-28 10:28:08 +01:00
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
2014-06-20 14:05:03 +02:00
foreach ( $_messageList [ 'msg' ] as $rowID )
{
$hA = self :: splitRowID ( $rowID );
$messageList [] = $hA [ 'msgUID' ];
}
try
{
//error_log(__METHOD__.__LINE__."->".print_r($messageList,true).' folder:'.$folder.' Method:'.$_forceDeleteMethod);
$this -> mail_bo -> deleteMessages ( $messageList , $folder ,( empty ( $_forceDeleteMethod ) ? 'no' : $_forceDeleteMethod ));
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2014-06-20 14:05:03 +02:00
{
$error = str_replace ( '"' , " ' " , $e -> getMessage ());
}
2013-05-27 15:48:55 +02:00
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2013-05-27 15:48:55 +02:00
if ( empty ( $error ))
{
2024-09-27 14:53:31 +02:00
self :: ajax_setFolderStatus ([ $uidA [ 'profileID' ] . " :: " . $folder ], true );
2019-05-14 21:10:45 +02:00
$response -> call ( 'app.mail.mail_deleteMessagesShowResult' , array ( 'egw_message' => '' , 'msg' => $_messageList [ 'msg' ]));
2013-05-27 15:48:55 +02:00
}
else
{
$error = str_replace ( '\n' , " \n " , lang ( 'mailserver reported:\n%1 \ndo you want to proceed by deleting the selected messages immediately (click ok)?\nif not, please try to empty your trashfolder before continuing. (click cancel)' , $error ));
2014-01-13 14:06:29 +01:00
$response -> call ( 'app.mail.mail_retryForcedDelete' , array ( 'response' => $error , 'messageList' => $_messageList ));
2013-05-27 15:48:55 +02:00
}
2013-02-28 10:28:08 +01:00
}
else
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> No messages selected. " );
2013-02-28 10:28:08 +01:00
}
}
2013-04-09 18:00:12 +02:00
/**
* copy messages
*
* @ param array _folderName target folder
* @ param array _messageList list of UID ' s
2013-12-18 11:27:27 +01:00
* @ param string _copyOrMove method to use copy or move allowed
2016-04-29 15:19:32 +02:00
* @ param string _move2ArchiveMarker marker to indicate if a move 2 archive was triggered
2017-06-12 15:25:21 +02:00
* @ param boolean _return if true the function will return the result instead of
* responding to client
2013-04-09 18:00:12 +02:00
*
* @ return xajax response
*/
2017-06-12 15:25:21 +02:00
function ajax_copyMessages ( $_folderName , $_messageList , $_copyOrMove = 'copy' , $_move2ArchiveMarker = '_' , $_return = false )
2013-04-09 18:00:12 +02:00
{
2016-04-29 15:19:32 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> " . $_folderName . ':' . print_r ( $_messageList , true ) . ' Method:' . $_copyOrMove . ' ArchiveMarker:' . $_move2ArchiveMarker );
2016-05-03 21:17:44 +02:00
Api\Translation :: add_app ( 'mail' );
$folderName = $this -> mail_bo -> decodeEntityFolderName ( $_folderName );
2013-12-18 11:27:27 +01:00
// only copy or move are supported as method
if ( ! ( $_copyOrMove == 'copy' || $_copyOrMove == 'move' )) $_copyOrMove = 'copy' ;
2016-05-03 21:17:44 +02:00
list ( $targetProfileID , $targetFolder ) = explode ( self :: $delimiter , $folderName , 2 );
2016-04-29 15:19:32 +02:00
// check if move2archive was called with the correct archiveFolder
$archiveFolder = $this -> mail_bo -> getArchiveFolder ();
if ( $_move2ArchiveMarker == '2' && $targetFolder != $archiveFolder )
{
error_log ( __METHOD__ . __LINE__ . " #Move to Archive called with: " . " $targetProfileID , $targetFolder " );
$targetProfileID = $this -> mail_bo -> profileID ;
$targetFolder = $archiveFolder ;
error_log ( __METHOD__ . __LINE__ . " #Fixed ArchiveFolder: " . " $targetProfileID , $targetFolder " );
}
2016-05-03 21:17:44 +02:00
$lastFoldersUsedForMoveCont = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'lastFolderUsedForMove' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), $expiration = 60 * 60 * 1 );
2014-05-20 12:02:21 +02:00
$changeFolderActions = false ;
2016-04-29 13:23:05 +02:00
//error_log(__METHOD__.__LINE__."#"."$targetProfileID,$targetFolder");
//error_log(__METHOD__.__LINE__.array2string($lastFoldersUsedForMoveCont));
2014-05-20 12:02:21 +02:00
if ( ! isset ( $lastFoldersUsedForMoveCont [ $targetProfileID ][ $targetFolder ]))
{
2016-04-29 13:23:05 +02:00
//error_log(__METHOD__.__LINE__.array2string($lastFoldersUsedForMoveCont[$targetProfileID][$targetFolder]));
2014-05-20 12:02:21 +02:00
if ( $lastFoldersUsedForMoveCont [ $targetProfileID ] && count ( $lastFoldersUsedForMoveCont [ $targetProfileID ]) > 3 )
{
$keys = array_keys ( $lastFoldersUsedForMoveCont [ $targetProfileID ]);
2014-07-16 18:34:15 +02:00
foreach ( $keys as & $f )
2014-05-20 12:02:21 +02:00
{
2015-08-25 10:11:27 +02:00
if ( count ( $lastFoldersUsedForMoveCont [ $targetProfileID ]) > 9 ) unset ( $lastFoldersUsedForMoveCont [ $targetProfileID ][ $f ]);
2014-05-20 12:02:21 +02:00
else break ;
}
//error_log(__METHOD__.__LINE__.array2string($lastFoldersUsedForMoveCont[$targetProfileID]));
}
2016-04-29 13:23:05 +02:00
//error_log(__METHOD__.__LINE__."#"."$targetProfileID,$targetFolder = $_folderName");
2016-05-03 21:17:44 +02:00
$lastFoldersUsedForMoveCont [ $targetProfileID ][ $targetFolder ] = $folderName ;
2014-05-20 12:02:21 +02:00
$changeFolderActions = true ;
}
2014-07-17 11:59:14 +02:00
$filtered = false ;
2013-04-29 16:56:33 +02:00
if ( $_messageList == 'all' || ! empty ( $_messageList [ 'msg' ]))
{
2014-06-20 15:37:20 +02:00
$error = false ;
if ( isset ( $_messageList [ 'all' ]) && $_messageList [ 'all' ])
2013-04-29 16:56:33 +02:00
{
2014-06-20 15:37:20 +02:00
// we have both messageIds AND allFlag folder information
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
$sourceProfileID = $uidA [ 'profileID' ];
if ( isset ( $_messageList [ 'activeFilters' ]) && $_messageList [ 'activeFilters' ])
{
$query = $_messageList [ 'activeFilters' ];
2016-04-12 17:17:57 +02:00
if ( ! empty ( $query [ 'search' ]) || ! empty ( $query [ 'filter' ]) || ( $query [ 'cat_id' ] == 'bydate' && ( ! empty ( $query [ 'startdate' ]) ||! empty ( $query [ 'enddate' ]))))
2014-06-20 15:37:20 +02:00
{
//([filterName] => Schnellsuche[type] => quick[string] => ebay[status] => any
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $supportsORinQuery ) || ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ]))
2014-06-20 15:37:20 +02:00
{
2016-05-03 21:17:44 +02:00
Mail :: $supportsORinQuery = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'supportsORinQuery' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), null , array (), 60 * 60 * 10 );
2016-03-28 20:51:38 +02:00
if ( ! isset ( Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ])) Mail :: $supportsORinQuery [ $this -> mail_bo -> profileID ] = true ;
2014-06-20 15:37:20 +02:00
}
2014-07-17 11:59:14 +02:00
$filtered = true ;
2016-04-12 17:17:57 +02:00
$cutoffdate = $cutoffdate2 = null ;
2016-05-03 21:17:44 +02:00
if ( $query [ 'startdate' ]) $cutoffdate = Api\DateTime :: to ( $query [ 'startdate' ], 'ts' ); //SINCE, enddate
if ( $query [ 'enddate' ]) $cutoffdate2 = Api\DateTime :: to ( $query [ 'enddate' ], 'ts' ); //BEFORE, startdate
2016-04-12 17:17:57 +02:00
//error_log(__METHOD__.__LINE__.' Startdate:'.$cutoffdate2.' Enddate'.$cutoffdate);
$filter = array (
2021-03-30 20:34:34 +02:00
'filterName' => lang ( 'subject' ),
'type' => ( $query [ 'cat_id' ] ? $query [ 'cat_id' ] : 'subject' ),
2016-04-12 17:17:57 +02:00
'string' => $query [ 'search' ],
'status' => ( ! empty ( $query [ 'filter' ]) ? $query [ 'filter' ] : 'any' ),
//'range'=>"BETWEEN",'since'=> date("d-M-Y", $cutoffdate),'before'=> date("d-M-Y", $cutoffdate2)
);
if ( $query [ 'enddate' ] || $query [ 'startdate' ]) {
$filter [ 'range' ] = " BETWEEN " ;
if ( $cutoffdate ) {
$filter [( empty ( $cutoffdate2 ) ? 'date' : 'since' )] = date ( " d-M-Y " , $cutoffdate );
if ( empty ( $cutoffdate2 )) $filter [ 'range' ] = " SINCE " ;
}
if ( $cutoffdate2 ) {
$filter [( empty ( $cutoffdate ) ? 'date' : 'before' )] = date ( " d-M-Y " , $cutoffdate2 );
if ( empty ( $cutoffdate )) $filter [ 'range' ] = " BEFORE " ;
}
}
2014-06-20 15:37:20 +02:00
}
else
{
$filter = array ();
}
2014-07-16 18:34:15 +02:00
$reverse = 1 ;
$rByUid = true ;
2014-06-20 15:37:20 +02:00
$_sR = $this -> mail_bo -> getSortedList (
$folder ,
$sort = 0 ,
2014-07-16 18:34:15 +02:00
$reverse ,
2014-06-20 15:37:20 +02:00
$filter ,
2021-03-30 20:34:34 +02:00
$rByUid ,
2014-06-20 15:37:20 +02:00
false
);
$messageList = $_sR [ 'match' ] -> ids ;
foreach ( $messageList as $uID )
{
//error_log(__METHOD__.__LINE__.$uID);
if ( $_copyOrMove == 'move' )
{
2016-05-03 21:17:44 +02:00
$messageListForRefresh [] = self :: generateRowID ( $sourceProfileID , $folderName , $uID , $_prependApp = false );
2014-06-20 15:37:20 +02:00
}
}
}
else
{
$messageList = 'all' ;
}
try
{
2014-10-14 10:51:01 +02:00
//error_log(__METHOD__.__LINE__."->".print_r($messageList,true).' folder:'.$folder.' Method:'.$_forceDeleteMethod.' '.$targetProfileID.'/'.$sourceProfileID);
$this -> mail_bo -> moveMessages ( $targetFolder , $messageList ,( $_copyOrMove == 'copy' ? false : true ), $folder , false , $sourceProfileID ,( $targetProfileID != $sourceProfileID ? $targetProfileID : null ));
2014-06-20 15:37:20 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2014-06-20 15:37:20 +02:00
{
$error = str_replace ( '"' , " ' " , $e -> getMessage ());
}
2013-04-29 16:56:33 +02:00
}
else
{
2014-11-19 20:12:50 +01:00
$messageList = array ();
while ( count ( $_messageList [ 'msg' ]) > 0 )
2014-06-20 15:37:20 +02:00
{
2014-11-19 20:12:50 +01:00
$uidA = self :: splitRowID ( $_messageList [ 'msg' ][ 0 ]);
$folder = $uidA [ 'folder' ]; // all messages in one set are supposed to be within the same folder
$sourceProfileID = $uidA [ 'profileID' ];
$moveList = array ();
foreach ( $_messageList [ 'msg' ] as $rowID )
2014-06-20 15:37:20 +02:00
{
2014-11-19 20:12:50 +01:00
$hA = self :: splitRowID ( $rowID );
// If folder changes, stop and move what we've got
if ( $hA [ 'folder' ] != $folder ) break ;
array_shift ( $_messageList [ 'msg' ]);
$messageList [] = $hA [ 'msgUID' ];
$moveList [] = $hA [ 'msgUID' ];
if ( $_copyOrMove == 'move' )
{
$helpvar = explode ( self :: $delimiter , $rowID );
array_shift ( $helpvar );
$messageListForRefresh [] = implode ( self :: $delimiter , $helpvar );
}
}
try
{
//error_log(__METHOD__.__LINE__."->".print_r($moveList,true).' folder:'.$folder.' Method:'.$_forceDeleteMethod.' '.$targetProfileID.'/'.$sourceProfileID);
$this -> mail_bo -> moveMessages ( $targetFolder , $moveList ,( $_copyOrMove == 'copy' ? false : true ), $folder , false , $sourceProfileID ,( $targetProfileID != $sourceProfileID ? $targetProfileID : null ));
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2014-11-19 20:12:50 +01:00
{
$error = str_replace ( '"' , " ' " , $e -> getMessage ());
2014-06-20 15:37:20 +02:00
}
}
2013-04-29 16:56:33 +02:00
}
2014-06-20 15:37:20 +02:00
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-06-20 15:37:20 +02:00
if ( $error )
2013-04-29 16:56:33 +02:00
{
2014-06-20 15:37:20 +02:00
if ( $changeFolderActions == false )
2014-03-10 15:36:03 +01:00
{
2014-06-20 15:37:20 +02:00
unset ( $lastFoldersUsedForMoveCont [ $targetProfileID ][ $targetFolder ]);
$changeFolderActions = true ;
2014-03-10 15:36:03 +01:00
}
2017-06-12 15:25:21 +02:00
if ( $_return ) return $error ;
2014-06-20 15:37:20 +02:00
$response -> call ( 'egw.message' , $error , " error " );
2013-04-29 16:56:33 +02:00
}
2014-06-20 15:37:20 +02:00
else
2014-02-17 11:19:31 +01:00
{
2014-03-10 15:36:03 +01:00
if ( $_copyOrMove == 'copy' )
{
2019-03-29 16:31:58 +01:00
$msg = lang ( 'copied %1 message(s) from %2 to %3' ,( $messageList == 'all' || $_messageList [ 'all' ] ? ( $filtered ? lang ( 'all filtered' ) : lang ( 'all' )) : count ( $messageList )), lang ( $folder ), lang ( $targetFolder ));
2017-06-12 15:25:21 +02:00
if ( $_return ) return $msg ;
$response -> call ( 'egw.message' , $msg );
2014-03-10 15:36:03 +01:00
}
else
{
2019-03-29 16:31:58 +01:00
$msg = lang ( 'moved %1 message(s) from %2 to %3' ,( $messageList == 'all' || $_messageList [ 'all' ] ? ( $filtered ? lang ( 'all filtered' ) : lang ( 'all' )) : count ( $messageList )), lang ( $folder ), lang ( $targetFolder ));
2017-06-12 15:25:21 +02:00
if ( $_return ) return $msg ;
2020-08-24 20:35:06 +02:00
foreach ( $messageListForRefresh as $mail_id )
{
$response -> call ( 'egw.refresh' , '' , 'mail' , $mail_id , 'delete' );
}
$response -> message ( $msg , 'success' );
2014-03-10 15:36:03 +01:00
}
2014-02-17 11:19:31 +01:00
}
2014-05-20 12:02:21 +02:00
if ( $changeFolderActions == true )
{
2016-04-29 13:23:05 +02:00
//error_log(__METHOD__.__LINE__.array2string($lastFoldersUsedForMoveCont));
2016-05-03 21:17:44 +02:00
Api\Cache :: setCache ( Api\Cache :: INSTANCE , 'email' , 'lastFolderUsedForMove' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), $lastFoldersUsedForMoveCont , $expiration = 60 * 60 * 1 );
$actionsnew = Etemplate\Widget\Nextmatch :: egw_actions ( self :: get_actions ());
2014-05-20 12:02:21 +02:00
$response -> call ( 'app.mail.mail_rebuildActionsOnList' , $actionsnew );
2014-02-17 11:19:31 +01:00
}
2013-04-29 16:56:33 +02:00
}
else
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " -> No messages selected. " );
2013-04-29 16:56:33 +02:00
}
2013-04-09 18:00:12 +02:00
}
2015-08-21 10:01:42 +02:00
2015-08-10 17:45:22 +02:00
/**
* Autoloading function to load branches of tree node
* of management folder tree
*
* @ param type $_id
*/
function ajax_folderMgmtTree_autoloading ( $_id = null )
{
$mail_ui = new mail_ui ();
2016-05-03 21:17:44 +02:00
$id = $_id ? $_id : $_GET [ 'id' ];
Etemplate\Widget\Tree :: send_quote_json ( $mail_ui -> mail_tree -> getTree ( $id , '' , 1 , true , false , false , false ));
2015-08-10 17:45:22 +02:00
}
2015-08-21 10:01:42 +02:00
2015-08-10 17:45:22 +02:00
/**
* Main function to handle folder management dialog
*
* @ param array $content content of dialog
*/
function folderManagement ( array $content = null )
{
2016-05-03 21:17:44 +02:00
$dtmpl = new Etemplate ( 'mail.folder_management' );
2015-08-10 17:45:22 +02:00
$profileID = $_GET [ 'acc_id' ] ? $_GET [ 'acc_id' ] : $content [ 'acc_id' ];
$sel_options [ 'tree' ] = $this -> mail_tree -> getTree ( null , $profileID , 1 , true , false , false );
2015-08-21 10:01:42 +02:00
2015-08-10 17:45:22 +02:00
if ( ! is_array ( $content ))
{
$content = array ( 'acc_id' => $profileID );
}
2015-08-21 10:01:42 +02:00
2015-08-10 17:45:22 +02:00
$readonlys = array ();
// Preserv
$preserv = array (
'acc_id' => $content [ 'acc_id' ] // preserve acc id to be used in client-side
);
$dtmpl -> exec ( 'mail.mail_ui.folderManagement' , $content , $sel_options , $readonlys , $preserv , 2 );
}
2015-08-21 10:01:42 +02:00
2015-08-11 18:28:59 +02:00
/**
* Function to delete folder for management longTask dialog
* it sends successfully deleted folder as response to be
* used in long task response handler .
*
* @ param type $_folderName
*/
function ajax_folderMgmt_delete ( $_folderName )
{
if ( $_folderName )
{
$success = $this -> ajax_deleteFolder ( $_folderName , true );
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2015-08-13 12:29:51 +02:00
list (, $folderName ) = explode ( self :: $delimiter , $_folderName );
2015-08-11 18:28:59 +02:00
if ( $success )
{
2015-08-13 12:29:51 +02:00
$res = $folderName ;
2015-08-11 18:28:59 +02:00
}
else
{
2015-08-13 12:29:51 +02:00
$res = lang ( " Failed to delete %1 " , $folderName );
2015-08-11 18:28:59 +02:00
}
$response -> data ( $res );
}
}
2022-05-23 15:44:42 +02:00
}