2013-07-20 09:23:55 +02:00
< ? php
/**
* EGroupware - Mail - interface class for compose mails in popup
*
* @ 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-07-20 09:23:55 +02:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id $
*/
2016-03-28 20:51:38 +02:00
use EGroupware\Api ;
2016-05-03 21:17:44 +02:00
use EGroupware\Api\Acl ;
2020-03-25 03:34:04 +01:00
use EGroupware\Api\Egw ;
2016-05-03 21:17:44 +02:00
use EGroupware\Api\Etemplate ;
2020-03-25 03:34:04 +01:00
use EGroupware\Api\Framework ;
use EGroupware\Api\Link ;
2016-03-28 20:51:38 +02:00
use EGroupware\Api\Mail ;
2020-03-25 03:34:04 +01:00
use EGroupware\Api\Vfs ;
2016-03-21 11:30:48 +01:00
2013-07-20 09:23:55 +02:00
/**
* Mail interface class for compose mails in popup
*/
class mail_compose
{
var $public_functions = array
(
'compose' => True ,
2014-01-30 10:35:56 +01:00
'getAttachment' => True ,
2013-07-20 09:23:55 +02:00
);
2013-10-07 14:17:33 +02:00
/**
* class vars for destination , priorities , mimeTypes
*/
static $destinations = array (
2013-11-27 15:36:15 +01:00
'to' => 'to' , // lang('to')
'cc' => 'cc' , // lang('cc')
'bcc' => 'bcc' , // lang('bcc')
'replyto' => 'replyto' , // lang('replyto')
'folder' => 'folder' // lang('folder')
2013-07-20 09:23:55 +02:00
);
2013-10-07 14:17:33 +02:00
static $priorities = array (
2013-11-27 15:36:15 +01:00
1 => " high " , // lang('high')
3 => " normal " , // lang('normal')
5 => " low " // lang('low')
2013-10-07 14:17:33 +02:00
);
static $mimeTypes = array (
" plain " => " plain " ,
" html " => " html "
);
2013-07-20 09:23:55 +02:00
/**
2016-03-28 20:51:38 +02:00
* Instance of Mail
2013-07-20 09:23:55 +02:00
*
2016-03-28 20:51:38 +02:00
* @ var Mail
2013-07-20 09:23:55 +02:00
*/
var $mail_bo ;
/**
* Active preferences , reference to $this -> mail_bo -> mailPreferences
*
* @ var array
*/
var $mailPreferences ;
var $attachments ; // Array of attachments
var $displayCharset ;
2013-10-07 14:17:33 +02:00
var $composeID ;
2013-07-20 09:23:55 +02:00
var $sessionData ;
2023-06-29 12:49:50 +02:00
function __construct ( int $_acc_id = null )
2013-07-20 09:23:55 +02:00
{
2016-05-03 21:17:44 +02:00
$this -> displayCharset = Api\Translation :: charset ();
2014-11-20 18:53:52 +01:00
2023-06-29 12:49:50 +02:00
$profileID = $_acc_id ? : ( int ) $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ];
2016-03-28 20:51:38 +02:00
$this -> mail_bo = Mail :: getInstance ( true , $profileID );
2014-11-20 18:53:52 +01:00
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'ActiveProfileID' ] = $this -> mail_bo -> profileID ;
2013-07-20 15:10:17 +02:00
2014-05-13 15:10:53 +02:00
$this -> mailPreferences =& $this -> mail_bo -> mailPreferences ;
2013-07-20 09:23:55 +02:00
//force the default for the forwarding -> asmail
2014-11-20 18:53:52 +01:00
if ( ! is_array ( $this -> mailPreferences ) || empty ( $this -> mailPreferences [ 'message_forwarding' ]))
{
2014-05-13 15:10:53 +02:00
$this -> mailPreferences [ 'message_forwarding' ] = 'asmail' ;
2013-07-20 09:23:55 +02:00
}
2016-03-28 20:51:38 +02:00
if ( is_null ( Mail :: $mailConfig )) Mail :: $mailConfig = Api\Config :: read ( 'mail' );
2013-07-20 09:23:55 +02:00
$this -> mailPreferences =& $this -> mail_bo -> mailPreferences ;
}
2013-10-08 16:23:46 +02:00
/**
* changeProfile
*
2014-10-23 13:28:36 +02:00
* @ param int $_icServerID
2013-10-08 16:23:46 +02:00
*/
function changeProfile ( $_icServerID )
{
if ( $this -> mail_bo -> profileID != $_icServerID )
{
2016-03-28 20:51:38 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . '->' . $this -> mail_bo -> profileID . '<->' . $_icServerID );
$this -> mail_bo = Mail :: getInstance ( false , $_icServerID );
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' Fetched IC Server:' . $this -> mail_bo -> profileID . ':' . function_backtrace ());
2013-10-08 16:23:46 +02:00
// no icServer Object: something failed big time
if ( ! isset ( $this -> mail_bo -> icServer )) exit ; // ToDo: Exception or the dialog for setting up a server config
2013-11-22 14:55:09 +01:00
$this -> mail_bo -> openConnection ( $this -> mail_bo -> profileID );
2013-10-08 16:23:46 +02:00
$this -> mailPreferences =& $this -> mail_bo -> mailPreferences ;
}
}
2015-01-26 16:04:15 +01:00
2015-01-07 12:57:34 +01:00
/**
* Provide toolbar actions used for compose toolbar
2015-01-13 13:14:41 +01:00
* @ param array $content content of compose temp
2015-01-07 12:57:34 +01:00
*
* @ return array an array of actions
*/
2018-06-22 16:04:50 +02:00
static function getToolbarActions ( $content )
2015-01-07 12:57:34 +01:00
{
2015-01-26 16:04:15 +01:00
$group = 0 ;
2015-01-07 12:57:34 +01:00
$actions = array (
'send' => array (
'caption' => 'Send' ,
'icon' => 'mail_send' ,
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.compose_submitAction' ,
2015-01-07 18:08:21 +01:00
'hint' => 'Send' ,
2017-09-26 00:12:17 +02:00
'shortcut' => array ( 'ctrl' => true , 'keyCode' => 83 , 'caption' => 'Ctrl + S' ),
2015-01-07 18:08:21 +01:00
'toolbarDefault' => true
2015-01-07 12:57:34 +01:00
),
'button[saveAsDraft]' => array (
'caption' => 'Save' ,
2019-09-20 10:44:19 +02:00
'icon' => 'apply' ,
2015-01-07 12:57:34 +01:00
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.saveAsDraft' ,
2015-01-08 16:56:45 +01:00
'hint' => 'Save as Draft' ,
'toolbarDefault' => true
2015-01-07 12:57:34 +01:00
),
'button[saveAsDraftAndPrint]' => array (
'caption' => 'Print' ,
'icon' => 'print' ,
2018-02-15 15:13:47 +01:00
'group' => $group ,
2015-01-07 12:57:34 +01:00
'onExecute' => 'javaScript:app.mail.saveAsDraft' ,
'hint' => 'Save as Draft and Print'
),
2018-02-15 15:13:47 +01:00
'save2vfs' => array (
'caption' => 'Save to filemanager' ,
'icon' => 'filesave' ,
'group' => $group ,
'onExecute' => 'javaScript:app.mail.compose_saveDraft2fm' ,
'hint' => 'Save the drafted message as eml file into VFS'
),
2015-01-07 12:57:34 +01:00
'selectFromVFSForCompose' => array (
'caption' => 'VFS' ,
2019-09-09 23:39:56 +02:00
'icon' => 'filemanager/navbar' ,
2015-01-07 12:57:34 +01:00
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.compose_triggerWidget' ,
2015-01-07 18:08:21 +01:00
'hint' => 'Select file(s) from VFS' ,
'toolbarDefault' => true
2015-01-07 12:57:34 +01:00
),
'uploadForCompose' => array (
'caption' => 'Upload files...' ,
'icon' => 'attach' ,
2018-02-15 15:13:47 +01:00
'group' => $group ,
2015-01-07 12:57:34 +01:00
'onExecute' => 'javaScript:app.mail.compose_triggerWidget' ,
2015-01-07 18:08:21 +01:00
'hint' => 'Select files to upload' ,
'toolbarDefault' => true
2015-01-07 12:57:34 +01:00
),
'to_infolog' => array (
'caption' => 'Infolog' ,
2019-08-05 10:59:26 +02:00
'icon' => 'infolog/navbar' ,
2015-01-07 12:57:34 +01:00
'group' => ++ $group ,
'checkbox' => true ,
2015-01-08 16:56:45 +01:00
'hint' => 'check to save as infolog on send' ,
2015-01-13 16:52:00 +01:00
'toolbarDefault' => true ,
'onExecute' => 'javaScript:app.mail.compose_setToggle'
2015-01-07 12:57:34 +01:00
),
'to_tracker' => array (
'caption' => 'Tracker' ,
2019-08-05 10:59:26 +02:00
'icon' => 'tracker/navbar' ,
2015-01-07 12:57:34 +01:00
'group' => $group ,
'checkbox' => true ,
2017-05-24 17:41:02 +02:00
'hint' => 'check to save as tracker entry on send' ,
2016-08-18 17:30:44 +02:00
'onExecute' => 'javaScript:app.mail.compose_setToggle' ,
'mail_import' => Api\Hooks :: single ( array ( 'location' => 'mail_import' ), 'tracker' ),
2015-01-07 12:57:34 +01:00
),
2015-04-15 17:55:18 +02:00
'to_calendar' => array (
'caption' => 'Calendar' ,
2019-08-05 10:59:26 +02:00
'icon' => 'calendar/navbar' ,
2015-04-15 17:55:18 +02:00
'group' => $group ,
'checkbox' => true ,
'hint' => 'check to save as calendar event on send' ,
'onExecute' => 'javaScript:app.mail.compose_setToggle'
),
2015-01-07 12:57:34 +01:00
'disposition' => array (
'caption' => 'Notification' ,
2021-12-10 14:48:40 +01:00
'icon' => 'notification' ,
2015-01-07 12:57:34 +01:00
'group' => ++ $group ,
'checkbox' => true ,
2017-05-24 17:41:02 +02:00
'hint' => 'check to receive a notification when the message is read (note: not all clients support this and/or the receiver may not authorize the notification)' ,
2015-01-13 16:52:00 +01:00
'onExecute' => 'javaScript:app.mail.compose_setToggle'
2015-01-07 12:57:34 +01:00
),
'prty' => array (
'caption' => 'Priority' ,
2018-02-15 15:13:47 +01:00
'group' => $group ,
2015-01-09 15:49:56 +01:00
'icon' => 'priority' ,
2015-01-07 12:57:34 +01:00
'children' => array (),
2015-01-13 13:14:41 +01:00
'hint' => 'Select the message priority tag' ,
2015-01-08 18:06:56 +01:00
),
2018-02-15 15:13:47 +01:00
'pgp' => array (
'caption' => 'Encrypt' ,
'icon' => 'lock' ,
2015-01-08 18:06:56 +01:00
'group' => ++ $group ,
2018-02-15 15:13:47 +01:00
'onExecute' => 'javaScript:app.mail.togglePgpEncrypt' ,
'hint' => 'Send message PGP encrypted: requires keys from all recipients!' ,
'checkbox' => true ,
'toolbarDefault' => true
2017-02-03 12:33:49 +01:00
),
2017-07-21 12:34:22 +02:00
2015-01-07 12:57:34 +01:00
);
2018-06-22 16:04:50 +02:00
$acc_smime = Mail\Smime :: get_acc_smime ( $content [ 'mailaccount' ]);
2021-10-07 10:14:08 +02:00
if ( $acc_smime && ! empty ( $acc_smime [ 'acc_smime_password' ]))
2017-07-21 12:34:22 +02:00
{
$actions = array_merge ( $actions , array (
'smime_sign' => array (
'caption' => 'SMIME Sign' ,
2017-09-01 16:20:57 +02:00
'icon' => 'smime_sign' ,
2017-07-21 12:34:22 +02:00
'group' => ++ $group ,
'onExecute' => 'javaScript:app.mail.compose_setToggle' ,
'checkbox' => true ,
'hint' => 'Sign your message with smime certificate'
),
'smime_encrypt' => array (
'caption' => 'SMIME Encryption' ,
2017-09-01 16:20:57 +02:00
'icon' => 'smime_encrypt' ,
2018-02-15 15:13:47 +01:00
'group' => $group ,
2017-07-21 12:34:22 +02:00
'onExecute' => 'javaScript:app.mail.compose_setToggle' ,
'checkbox' => true ,
'hint' => 'Encrypt your message with smime certificate'
)));
}
2015-01-09 13:58:06 +01:00
foreach ( self :: $priorities as $key => $priority )
2015-01-07 12:57:34 +01:00
{
2015-01-09 13:58:06 +01:00
$actions [ 'prty' ][ 'children' ][ $key ] = array (
2015-01-07 12:57:34 +01:00
'caption' => $priority ,
2015-01-13 13:14:41 +01:00
'icon' => 'prio_high' ,
'default' => false ,
'onExecute' => 'javaScript:app.mail.compose_priorityChange'
2015-01-07 12:57:34 +01:00
);
2015-01-09 15:49:56 +01:00
switch ( $priority )
{
case 'high' :
$actions [ 'prty' ][ 'children' ][ $key ][ 'icon' ] = 'prio_high' ;
break ;
case 'normal' :
2019-09-19 16:28:49 +02:00
$actions [ 'prty' ][ 'children' ][ $key ][ 'icon' ] = 'priority' ;
2015-01-09 15:49:56 +01:00
break ;
case 'low' :
$actions [ 'prty' ][ 'children' ][ $key ][ 'icon' ] = 'prio_low' ;
}
2015-01-07 12:57:34 +01:00
}
2015-01-13 13:14:41 +01:00
// Set the priority action its current state
if ( $content [ 'priority' ])
{
$actions [ 'prty' ][ 'children' ][ $content [ 'priority' ]][ 'default' ] = true ;
}
2016-05-03 21:17:44 +02:00
if ( Api\Header\UserAgent :: mobile ())
2016-01-26 12:51:56 +01:00
{
2016-03-13 12:22:44 +01:00
foreach ( array_keys ( $actions ) as $key )
2016-01-26 12:51:56 +01:00
{
2016-01-26 17:25:18 +01:00
if ( ! in_array ( $key , array ( 'send' , 'button[saveAsDraft]' , 'uploadForCompose' ))) {
2016-01-26 12:51:56 +01:00
$actions [ $key ][ 'toolbarDefault' ] = false ;
}
}
unset ( $actions [ 'pgp' ]);
}
2021-10-07 10:14:08 +02:00
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'disable_pgp_encryption' ])) unset ( $actions [ 'pgp' ]);
2017-04-21 16:21:49 +02:00
// remove vfs actions if the user has no run access to filemanager
2021-10-07 10:14:08 +02:00
if ( empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'filemanager' ]))
2017-04-21 16:21:49 +02:00
{
unset ( $actions [ 'save2vfs' ]);
unset ( $actions [ 'selectFromVFSForCompose' ]);
}
2021-04-26 14:18:57 +02:00
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'infolog' ]))
{
unset ( $actions [ 'to_infolog' ]);
}
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'tracker' ]))
{
unset ( $actions [ 'to_tracker' ]);
}
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'calendar' ]))
{
unset ( $actions [ 'to_calendar' ]);
}
2015-01-07 12:57:34 +01:00
return $actions ;
}
2013-10-08 16:23:46 +02:00
2013-07-20 09:23:55 +02:00
/**
2014-12-01 21:14:18 +01:00
* Compose dialog
2013-07-20 09:23:55 +02:00
*
2020-06-05 22:33:26 +02:00
* @ var array $_content = null etemplate content array
2014-12-01 21:14:18 +01:00
* @ var string $msg = null a possible message to be passed and displayed to the userinterface
* @ var string $_focusElement = 'to' subject , to , body supported
* @ var boolean $suppressSigOnTop = false
* @ var boolean $isReply = false
2013-07-20 09:23:55 +02:00
*/
2013-09-02 17:15:35 +02:00
function compose ( array $_content = null , $msg = null , $_focusElement = 'to' , $suppressSigOnTop = false , $isReply = false )
2013-07-20 09:23:55 +02:00
{
2016-05-03 21:17:44 +02:00
if ( $msg ) Framework :: message ( $msg );
2014-11-20 18:53:52 +01:00
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'LastSignatureIDUsed' ]))
2014-05-02 12:33:54 +02:00
{
$sigPref = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'LastSignatureIDUsed' ];
}
else
{
$sigPref = array ();
}
2014-11-25 00:38:37 +01:00
// split mailaccount (acc_id) and identity (ident_id)
2014-11-20 18:53:52 +01:00
if ( $_content && isset ( $_content [ 'mailaccount' ]))
{
2014-11-25 00:38:37 +01:00
list ( $_content [ 'mailaccount' ], $_content [ 'mailidentity' ]) = explode ( ':' , $_content [ 'mailaccount' ]);
2014-11-20 18:53:52 +01:00
}
2014-05-02 12:33:54 +02:00
//error_log(__METHOD__.__LINE__.array2string($sigPref));
2013-11-27 15:36:15 +01:00
//lang('compose'),lang('from') // needed to be found by translationtools
2014-03-21 11:37:09 +01:00
//error_log(__METHOD__.__LINE__.array2string($_REQUEST).function_backtrace());
2013-10-10 13:44:01 +02:00
//error_log(__METHOD__.__LINE__.array2string($_content).function_backtrace());
2015-11-05 13:03:03 +01:00
$_contentHasSigID = $_content ? array_key_exists ( 'mailidentity' ,( array ) $_content ) : false ;
$_contentHasMimeType = $_content ? array_key_exists ( 'mimeType' ,( array ) $_content ) : false ;
2018-07-11 14:39:28 +02:00
// fetch appendix data which is an assistance input value consisiting of json data
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_content [ 'appendix_data' ]))
2018-07-11 14:39:28 +02:00
{
$appendix_data = json_decode ( $_content [ 'appendix_data' ], true );
2018-07-12 15:42:07 +02:00
$_content [ 'appendix_data' ] = '' ;
2018-07-11 14:39:28 +02:00
}
2022-04-26 18:46:23 +02:00
if ( ! empty ( $appendix_data [ 'emails' ]))
2018-07-11 14:39:28 +02:00
{
try {
2019-02-26 11:58:20 +01:00
if ( $appendix_data [ 'emails' ][ 'processedmail_id' ]) $_content [ 'processedmail_id' ] .= ',' . $appendix_data [ 'emails' ][ 'processedmail_id' ];
2018-07-11 14:39:28 +02:00
$attched_uids = $this -> _get_uids_as_attachments ( $appendix_data [ 'emails' ][ 'ids' ], $_content [ 'serverID' ]);
if ( is_array ( $attched_uids ))
{
$_content [ 'attachments' ] = array_merge_recursive (( array ) $_content [ 'attachments' ], $attched_uids );
}
} catch ( Exception $ex ) {
Framework :: message ( $ex -> getMessage (), 'error' );
}
$suppressSigOnTop = true ;
unset ( $appendix_data );
}
2013-07-20 09:23:55 +02:00
if ( isset ( $_GET [ 'reply_id' ])) $replyID = $_GET [ 'reply_id' ];
2022-04-26 18:46:23 +02:00
if ( empty ( $replyID ) && isset ( $_GET [ 'id' ])) $replyID = $_GET [ 'id' ];
2014-01-16 16:58:27 +01:00
2013-10-04 19:45:33 +02:00
// Process different places we can use as a start for composing an email
2014-03-04 16:19:48 +01:00
$actionToProcess = 'compose' ;
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_GET [ 'from' ]) && $replyID )
2013-10-04 19:45:33 +02:00
{
$_content = array_merge (( array ) $_content , $this -> getComposeFrom (
// Parameters needed for fetching appropriate data
2022-04-29 12:49:41 +02:00
$replyID , $_GET [ 'part_id' ] ? ? null , $_GET [ 'from' ] ? ? null ,
// additionally these can be changed
2013-10-04 19:45:33 +02:00
$_focusElement , $suppressSigOnTop , $isReply
));
2017-09-08 14:24:55 +02:00
if ( Mail\Smime :: get_acc_smime ( $this -> mail_bo -> profileID ))
{
if ( isset ( $_GET [ 'smime_type' ])) $smime_type = $_GET [ 'smime_type' ];
// pre set smime_sign and smime_encrypt actions if the original
// message is smime.
$_content [ 'smime_sign' ] = $smime_type == ( Mail\Smime :: TYPE_SIGN ||
2017-09-01 16:20:57 +02:00
$smime_type == Mail\Smime :: TYPE_SIGN_ENCRYPT ) ? 'on' : 'off' ;
2017-09-08 14:24:55 +02:00
$_content [ 'smime_encrypt' ] = ( $smime_type == Mail\Smime :: TYPE_ENCRYPT ) ? 'on' : 'off' ;
}
2017-09-01 16:20:57 +02:00
2014-03-04 16:19:48 +01:00
$actionToProcess = $_GET [ 'from' ];
2013-10-08 16:23:46 +02:00
unset ( $_GET [ 'from' ]);
unset ( $_GET [ 'reply_id' ]);
unset ( $_GET [ 'part_id' ]);
unset ( $_GET [ 'id' ]);
unset ( $_GET [ 'mode' ]);
2013-10-10 16:56:30 +02:00
//error_log(__METHOD__.__LINE__.array2string($_content));
2013-10-04 19:45:33 +02:00
}
2014-04-01 13:41:34 +02:00
2013-10-10 13:44:01 +02:00
$composeCache = array ();
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_content [ 'composeID' ]))
2013-10-07 14:17:33 +02:00
{
2014-03-04 10:23:43 +01:00
$isFirstLoad = false ;
2016-03-28 20:51:38 +02:00
$composeCache = Api\Cache :: getCache ( Api\Cache :: SESSION , 'mail' , 'composeCache' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]) . '_' . $_content [ 'composeID' ], $callback = null , $callback_params = array (), $expiration = 60 * 60 * 2 );
2013-10-10 13:44:01 +02:00
$this -> composeID = $_content [ 'composeID' ];
//error_log(__METHOD__.__LINE__.array2string($composeCache));
2013-10-07 14:17:33 +02:00
}
else
{
2014-03-04 16:19:48 +01:00
// as we use isFirstLoad to trigger the initalStyle on ckEditor, we
// respect that composeasnew may not want that, as we assume there
// is some style already set and our initalStyle always adds a span with
// and we want to avoid that
$isFirstLoad = ! ( $actionToProcess == 'composeasnew' ); //true;
2014-11-21 10:33:34 +01:00
$this -> composeID = $_content [ 'composeID' ] = $this -> generateComposeID ();
2023-06-29 12:49:50 +02:00
$_content = $this -> setDefaults ( $_content + [ 'mailidentity' => $_REQUEST [ 'preset' ][ 'identity' ] ? ? null ]);
2013-10-07 14:17:33 +02:00
}
2013-10-02 16:50:24 +02:00
// VFS Selector was used
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_content [ 'selectFromVFSForCompose' ]))
2013-10-02 16:50:24 +02:00
{
2013-10-03 18:09:25 +02:00
$suppressSigOnTop = true ;
2013-10-02 16:50:24 +02:00
foreach ( $_content [ 'selectFromVFSForCompose' ] as $i => $path )
{
$_content [ 'uploadForCompose' ][] = array (
2016-03-21 11:30:48 +01:00
'name' => Vfs :: basename ( $path ),
'type' => Vfs :: mime_content_type ( $path ),
'file' => Vfs :: PREFIX . $path ,
'size' => filesize ( Vfs :: PREFIX . $path ),
2013-10-02 16:50:24 +02:00
);
}
unset ( $_content [ 'selectFromVFSForCompose' ]);
}
// check everything that was uploaded
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_content [ 'uploadForCompose' ]))
2013-10-01 13:29:54 +02:00
{
2013-10-03 18:09:25 +02:00
$suppressSigOnTop = true ;
2013-10-01 13:29:54 +02:00
foreach ( $_content [ 'uploadForCompose' ] as $i => & $upload )
{
if ( ! isset ( $upload [ 'file' ])) $upload [ 'file' ] = $upload [ 'tmp_name' ];
2013-10-02 16:50:24 +02:00
try
{
2016-03-28 20:51:38 +02:00
$upload [ 'file' ] = $upload [ 'tmp_name' ] = Mail :: checkFileBasics ( $upload , $this -> composeID , false );
2013-10-02 16:50:24 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-10-02 16:50:24 +02:00
{
2016-05-03 21:17:44 +02:00
Framework :: message ( $e -> getMessage (), 'error' );
2014-12-03 17:25:10 +01:00
unset ( $_content [ 'uploadForCompose' ][ $i ]);
continue ;
}
2016-03-21 11:30:48 +01:00
if ( is_dir ( $upload [ 'file' ]) && ( ! $_content [ 'filemode' ] || $_content [ 'filemode' ] == Vfs\Sharing :: ATTACH ))
2014-12-03 17:25:10 +01:00
{
2016-03-21 11:30:48 +01:00
$_content [ 'filemode' ] = Vfs\Sharing :: READONLY ;
2016-05-03 21:17:44 +02:00
Framework :: message ( lang ( 'Directories have to be shared.' ), 'info' );
2013-10-02 16:50:24 +02:00
}
}
}
// check if someone did hit delete on the attachments list
if ( ! empty ( $_content [ 'attachments' ][ 'delete' ]))
{
2014-01-31 11:21:58 +01:00
//error_log(__METHOD__.__LINE__.':'.array2string($_content['attachments']));
//error_log(__METHOD__.__LINE__.':'.array2string($_content['attachments']['delete']));
2013-10-03 18:09:25 +02:00
$suppressSigOnTop = true ;
2013-10-02 16:50:24 +02:00
$toDelete = $_content [ 'attachments' ][ 'delete' ];
unset ( $_content [ 'attachments' ][ 'delete' ]);
$attachments = $_content [ 'attachments' ];
unset ( $_content [ 'attachments' ]);
foreach ( $attachments as $i => $att )
{
$remove = false ;
2014-11-20 18:53:52 +01:00
foreach ( array_keys ( $toDelete ) as $k )
2013-10-02 16:50:24 +02:00
{
if ( $att [ 'tmp_name' ] == $k ) $remove = true ;
}
if ( ! $remove ) $_content [ 'attachments' ][] = $att ;
2013-10-01 13:29:54 +02:00
}
}
2013-10-03 12:05:05 +02:00
// someone clicked something like send, or saveAsDraft
2013-10-08 16:23:46 +02:00
// make sure, we are connected to the correct server for sending and storing the send message
$activeProfile = $composeProfile = $this -> mail_bo -> profileID ; // active profile may not be the profile uised in/for compose
2016-03-28 20:51:38 +02:00
$activeFolderCache = Api\Cache :: getCache ( Api\Cache :: INSTANCE , 'email' , 'activeMailbox' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]), $callback = null , $callback_params = array (), $expiration = 60 * 60 * 10 );
2014-04-01 13:41:34 +02:00
if ( ! empty ( $activeFolderCache [ $this -> mail_bo -> profileID ]))
{
//error_log(__METHOD__.__LINE__.' CurrentFolder:'.$activeFolderCache[$this->mail_bo->profileID]);
$activeFolder = $activeFolderCache [ $this -> mail_bo -> profileID ];
}
2014-05-23 14:21:17 +02:00
//error_log(__METHOD__.__LINE__.array2string($_content));
2013-10-08 16:23:46 +02:00
if ( ! empty ( $_content [ 'serverID' ]) && $_content [ 'serverID' ] != $this -> mail_bo -> profileID &&
2015-01-07 18:37:56 +01:00
( $_content [ 'composeToolbar' ] === 'send' || $_content [ 'button' ][ 'saveAsDraft' ] || $_content [ 'button' ][ 'saveAsDraftAndPrint' ])
2013-10-08 16:23:46 +02:00
)
{
$this -> changeProfile ( $_content [ 'serverID' ]);
$composeProfile = $this -> mail_bo -> profileID ;
}
2022-05-10 13:58:57 +02:00
// make sure $acc is set/initialized properly with the current composeProfile, as $acc is used down there
// at several locations and not necessary initialized before
2016-03-28 20:51:38 +02:00
$acc = Mail\Account :: read ( $composeProfile );
2013-10-03 18:09:25 +02:00
$buttonClicked = false ;
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_content [ 'composeToolbar' ]) && $_content [ 'composeToolbar' ] === 'send' )
2013-10-03 12:05:05 +02:00
{
2013-10-03 18:09:25 +02:00
$buttonClicked = $suppressSigOnTop = true ;
2013-10-03 12:05:05 +02:00
$sendOK = true ;
2022-04-29 12:49:41 +02:00
$_content [ 'body' ] = $_content [ 'body' ] ? ? $_content [ 'mail_' . ( $_content [ 'mimeType' ] == 'html' ? 'html' : 'plain' ) . 'text' ] ? ? null ;
2013-12-09 10:57:03 +01:00
/*
perform some simple checks , before trying to send on :
$_content [ 'to' ]; $_content [ 'cc' ]; $_content [ 'bcc' ];
trim ( $_content [ 'subject' ]);
trim ( strip_tags ( str_replace ( ' ' , '' , $_content [ 'body' ])));
*/
if ( strlen ( trim ( strip_tags ( str_replace ( ' ' , '' , $_content [ 'body' ])))) == 0 && count ( $_content [ 'attachments' ]) == 0 )
2013-10-03 12:05:05 +02:00
{
2013-12-09 10:57:03 +01:00
$sendOK = false ;
$_content [ 'msg' ] = $message = lang ( " no message body supplied " );
2013-10-03 12:05:05 +02:00
}
2013-12-09 10:57:03 +01:00
if ( $sendOK && strlen ( trim ( $_content [ 'subject' ])) == 0 )
2013-10-03 12:05:05 +02:00
{
$sendOK = false ;
2013-12-09 10:57:03 +01:00
$_content [ 'msg' ] = $message = lang ( " no subject supplied " );
}
if ( $sendOK && empty ( $_content [ 'to' ]) && empty ( $_content [ 'cc' ]) && empty ( $_content [ 'bcc' ]))
{
$sendOK = false ;
$_content [ 'msg' ] = $message = lang ( " no adress, to send this mail to, supplied " );
}
if ( $sendOK )
{
try
{
$success = $this -> send ( $_content );
2020-07-22 08:57:51 +02:00
//hook mail_compose_after_save
Api\Hooks :: process ( array (
'location' => 'mail_compose_after_save' ,
'content' => $_content ,
));
2022-04-29 12:49:41 +02:00
if ( ! $success )
2013-12-09 10:57:03 +01:00
{
$sendOK = false ;
$message = $this -> errorInfo ;
}
2014-11-25 00:38:37 +01:00
if ( ! empty ( $_content [ 'mailidentity' ]) && $_content [ 'mailidentity' ] != $sigPref [ $this -> mail_bo -> profileID ])
2014-05-02 12:33:54 +02:00
{
2014-11-25 00:38:37 +01:00
$sigPref [ $this -> mail_bo -> profileID ] = $_content [ 'mailidentity' ];
2014-05-02 12:33:54 +02:00
$GLOBALS [ 'egw' ] -> preferences -> add ( 'mail' , 'LastSignatureIDUsed' , $sigPref , 'user' );
// save prefs
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( true );
}
2013-12-09 10:57:03 +01:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-12-09 10:57:03 +01:00
{
$sendOK = false ;
$message = $e -> getMessage ();
}
2013-10-03 12:05:05 +02:00
}
2013-10-08 16:23:46 +02:00
if ( $activeProfile != $composeProfile )
{
$this -> changeProfile ( $activeProfile );
$activeProfile = $this -> mail_bo -> profileID ;
}
2013-10-03 12:05:05 +02:00
if ( $sendOK )
{
2021-10-06 09:11:59 +02:00
$workingFolder = $activeFolder [ 'mailbox' ];
2014-04-01 13:41:34 +02:00
$mode = 'compose' ;
2014-04-03 11:07:55 +02:00
$idsForRefresh = array ();
2014-04-01 13:41:34 +02:00
if ( isset ( $_content [ 'mode' ]) && ! empty ( $_content [ 'mode' ]))
{
$mode = $_content [ 'mode' ];
if ( $_content [ 'mode' ] == 'forward' && ! empty ( $_content [ 'processedmail_id' ]))
{
$_content [ 'processedmail_id' ] = explode ( ',' , $_content [ 'processedmail_id' ]);
foreach ( $_content [ 'processedmail_id' ] as $k => $rowid )
{
$fhA = mail_ui :: splitRowID ( $rowid );
//$this->sessionData['uid'][] = $fhA['msgUID'];
//$this->sessionData['forwardedUID'][] = $fhA['msgUID'];
2014-04-03 11:07:55 +02:00
$idsForRefresh [] = mail_ui :: generateRowID ( $fhA [ 'profileID' ], $fhA [ 'folder' ], $fhA [ 'msgUID' ], $_prependApp = false );
2014-04-01 13:41:34 +02:00
if ( ! empty ( $fhA [ 'folder' ])) $workingFolder = $fhA [ 'folder' ];
}
}
if ( $_content [ 'mode' ] == 'reply' && ! empty ( $_content [ 'processedmail_id' ]))
{
$rhA = mail_ui :: splitRowID ( $_content [ 'processedmail_id' ]);
//$this->sessionData['uid'] = $rhA['msgUID'];
2014-04-03 11:07:55 +02:00
$idsForRefresh [] = mail_ui :: generateRowID ( $rhA [ 'profileID' ], $rhA [ 'folder' ], $rhA [ 'msgUID' ], $_prependApp = false );
2014-04-01 13:41:34 +02:00
$workingFolder = $rhA [ 'folder' ];
}
}
2014-04-03 11:07:55 +02:00
//the line/condition below should not be needed
if ( empty ( $idsForRefresh ) && ! empty ( $_content [ 'processedmail_id' ]))
{
$rhA = mail_ui :: splitRowID ( $_content [ 'processedmail_id' ]);
$idsForRefresh [] = mail_ui :: generateRowID ( $rhA [ 'profileID' ], $rhA [ 'folder' ], $rhA [ 'msgUID' ], $_prependApp = false );
2020-07-29 13:58:02 +02:00
$workingFolder = $rhA [ 'folder' ]; // need folder to refresh eg. drafts folder
2014-04-03 11:07:55 +02:00
}
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-04-01 13:41:34 +02:00
if ( $activeProfile != $composeProfile )
{
// we need a message only, when account ids (composeProfile vs. activeProfile) differ
$response -> call ( 'opener.egw_message' , lang ( 'Message send successfully.' ));
}
2020-07-29 13:58:02 +02:00
elseif ( $activeProfile == $composeProfile && ( $workingFolder == $activeFolder [ 'mailbox' ] && $mode != 'compose' ) ||
( $this -> mail_bo -> isSentFolder ( $workingFolder ) || $this -> mail_bo -> isDraftFolder ( $workingFolder )))
2014-04-01 13:41:34 +02:00
{
if ( $this -> mail_bo -> isSentFolder ( $workingFolder ) || $this -> mail_bo -> isDraftFolder ( $workingFolder ))
{
// we may need a refresh when on sent folder or in drafts, as drafted messages will/should be deleted after succeeded send action
$response -> call ( 'opener.egw_refresh' , lang ( 'Message send successfully.' ), 'mail' );
}
2020-07-29 13:58:02 +02:00
// we only need to update the icon of the replied or forwarded mails --> 'update-in-place'
2014-04-01 13:41:34 +02:00
else
{
2014-04-03 11:07:55 +02:00
//error_log(__METHOD__.__LINE__.array2string($idsForRefresh));
2020-07-29 13:58:02 +02:00
$response -> call ( 'opener.egw_refresh' , lang ( 'Message send successfully.' ), 'mail' , $idsForRefresh , 'update-in-place' );
2014-04-01 13:41:34 +02:00
}
}
else
{
$response -> call ( 'opener.egw_message' , lang ( 'Message send successfully.' ));
}
//egw_framework::refresh_opener(lang('Message send successfully.'),'mail');
2016-05-03 21:17:44 +02:00
Framework :: window_close ();
2013-10-03 12:05:05 +02:00
}
2013-10-05 11:47:34 +02:00
if ( $sendOK == false )
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
Framework :: message ( lang ( 'Message send failed: %1' , $message ), 'error' ); // maybe error is more appropriate
2014-12-16 11:26:44 +01:00
$response -> call ( 'app.mail.clearIntevals' );
2013-10-05 11:47:34 +02:00
}
2013-10-03 12:05:05 +02:00
}
2014-09-12 13:52:38 +02:00
2013-10-08 16:23:46 +02:00
if ( $activeProfile != $composeProfile ) $this -> changeProfile ( $activeProfile );
2013-07-20 09:23:55 +02:00
$insertSigOnTop = false ;
2022-04-29 12:49:41 +02:00
$content = $_content ? ? [];
2014-01-18 15:52:21 +01:00
if ( $_contentHasMimeType )
{
2014-02-04 12:31:13 +01:00
// mimeType is now a checkbox; convert it here to match expectations
// ToDo: match Code to meet checkbox value
2022-04-29 12:49:41 +02:00
$_content [ 'mimetype' ] = $content [ 'mimeType' ] = ! empty ( $content [ 'mimeType' ]) ? 'html' : 'plain' ;
2014-01-18 15:52:21 +01:00
}
2013-10-04 11:33:44 +02:00
// user might have switched desired mimetype, so we should convert
2022-04-26 18:46:23 +02:00
if ( ! empty ( $content [ 'is_html' ]) && $content [ 'mimeType' ] === 'plain' )
2013-10-04 11:33:44 +02:00
{
2013-10-04 13:02:12 +02:00
//error_log(__METHOD__.__LINE__.$content['mail_htmltext']);
2013-10-04 11:33:44 +02:00
$suppressSigOnTop = true ;
2013-10-04 13:02:12 +02:00
if ( stripos ( $content [ 'mail_htmltext' ], '<pre>' ) !== false )
{
2016-05-03 21:17:44 +02:00
$contentArr = Api\Mail\Html :: splithtmlByPRE ( $content [ 'mail_htmltext' ]);
2014-09-09 16:04:40 +02:00
if ( is_array ( $contentArr ))
2013-10-04 13:02:12 +02:00
{
2014-09-09 16:04:40 +02:00
foreach ( $contentArr as $k =>& $elem )
{
if ( stripos ( $elem , '<pre>' ) !== false ) $elem = str_replace ( array ( " \r \n " , " \n " , " \r " ), array ( " <br> " , " <br> " , " <br> " ), $elem );
}
$content [ 'mail_htmltext' ] = implode ( '' , $contentArr );
2013-10-04 13:02:12 +02:00
}
}
2015-10-23 12:02:18 +02:00
$content [ 'mail_htmltext' ] = $this -> _getCleanHTML ( $content [ 'mail_htmltext' ]);
2016-05-03 21:17:44 +02:00
$content [ 'mail_htmltext' ] = Api\Mail\Html :: convertHTMLToText ( $content [ 'mail_htmltext' ], $charset = false , false , true );
2013-10-04 13:02:12 +02:00
2013-10-04 11:33:44 +02:00
$content [ 'body' ] = $content [ 'mail_htmltext' ];
2013-10-04 13:02:12 +02:00
unset ( $content [ 'mail_htmltext' ]);
2013-10-04 11:33:44 +02:00
$content [ 'is_html' ] = false ;
$content [ 'is_plain' ] = true ;
}
2022-04-26 18:46:23 +02:00
if ( ! empty ( $content [ 'is_plain' ]) && $content [ 'mimeType' ] === 'html' )
2013-10-04 11:33:44 +02:00
{
2014-03-04 10:23:43 +01:00
// the possible font span should only be applied on first load or on switch plain->html
2014-03-07 15:54:44 +01:00
$isFirstLoad = " switchedplaintohtml " ;
2013-10-04 13:02:12 +02:00
//error_log(__METHOD__.__LINE__.$content['mail_plaintext']);
2013-10-04 11:33:44 +02:00
$suppressSigOnTop = true ;
2022-12-02 15:24:32 +01:00
$content [ 'mail_plaintext' ] = str_replace ([ '<' , " \r \n " , " \n " , " \r " ], [ '<' , " <br> " , " <br> " , " <br> " ], $content [ 'mail_plaintext' ]);
2013-10-04 13:02:12 +02:00
//$this->replaceEmailAdresses($content['mail_plaintext']);
2013-10-04 11:33:44 +02:00
$content [ 'body' ] = $content [ 'mail_plaintext' ];
2013-10-04 13:02:12 +02:00
unset ( $content [ 'mail_plaintext' ]);
2013-10-04 11:33:44 +02:00
$content [ 'is_html' ] = true ;
$content [ 'is_plain' ] = false ;
}
2013-10-10 13:44:01 +02:00
2022-05-10 13:58:57 +02:00
$content [ 'body' ] = $content [ 'body' ] ? ? $content [ 'mail_' . ( $content [ 'mimeType' ] === 'html' ? 'html' : 'plain' ) . 'text' ] ? ? '' ;
2022-04-29 12:49:41 +02:00
unset ( $_content [ 'body' ], $_content [ 'mail_htmltext' ], $_content [ 'mail_plaintext' ]);
2022-05-02 17:19:37 +02:00
$_currentMode = $_content [ 'mimeType' ] && $_content [ 'mimeType' ] !== 'plain' ? 'html' : 'plain' ;
2013-10-10 13:44:01 +02:00
2017-02-10 13:13:24 +01:00
// we have to keep comments to be able to changing signatures
// signature is wraped in "<!-- HTMLSIGBEGIN -->$signature<!-- HTMLSIGEND -->"
Mail :: $htmLawed_config [ 'comment' ] = 2 ;
2013-10-07 17:02:35 +02:00
// form was submitted either by clicking a button or by changing one of the triggering selectboxes
2013-11-22 14:55:09 +01:00
// identity and signatureid; this might trigger that the signature in mail body may have to be altered
2013-10-07 17:02:35 +02:00
if ( ! empty ( $content [ 'body' ]) &&
2014-01-13 16:40:34 +01:00
( ! empty ( $composeCache [ 'mailaccount' ]) && ! empty ( $_content [ 'mailaccount' ]) && $_content [ 'mailaccount' ] != $composeCache [ 'mailaccount' ]) ||
2014-11-25 00:38:37 +01:00
( ! empty ( $composeCache [ 'mailidentity' ]) && ! empty ( $_content [ 'mailidentity' ]) && $_content [ 'mailidentity' ] != $composeCache [ 'mailidentity' ])
2013-10-07 17:02:35 +02:00
)
{
$buttonClicked = true ;
$suppressSigOnTop = true ;
2014-01-13 16:40:34 +01:00
if ( ! empty ( $composeCache [ 'mailaccount' ]) && ! empty ( $_content [ 'mailaccount' ]) && $_content [ 'mailaccount' ] != $composeCache [ 'mailaccount' ])
2013-10-10 13:44:01 +02:00
{
2016-03-28 20:51:38 +02:00
$acc = Mail\Account :: read ( $_content [ 'mailaccount' ]);
2014-01-13 16:40:34 +01:00
//error_log(__METHOD__.__LINE__.array2string($acc));
2016-03-28 20:51:38 +02:00
$Identities = Mail\Account :: read_identity ( $acc [ 'ident_id' ], true );
2013-11-22 14:55:09 +01:00
//error_log(__METHOD__.__LINE__.array2string($Identities));
if ( $Identities [ 'ident_id' ])
2013-10-10 13:44:01 +02:00
{
2013-11-22 14:55:09 +01:00
$newSig = $Identities [ 'ident_id' ];
2013-10-10 13:44:01 +02:00
}
else
{
2013-12-17 10:55:47 +01:00
$newSig = $this -> mail_bo -> getDefaultIdentity ();
2013-11-22 14:55:09 +01:00
if ( $newSig === false ) $newSig = - 2 ;
2013-10-10 13:44:01 +02:00
}
}
2014-11-25 00:38:37 +01:00
$_oldSig = $composeCache [ 'mailidentity' ];
$_signatureid = ( $newSig ? $newSig : $_content [ 'mailidentity' ]);
2016-10-05 16:31:58 +02:00
2013-11-22 14:55:09 +01:00
if ( $_oldSig != $_signatureid )
2013-10-10 13:44:01 +02:00
{
2022-05-02 17:19:37 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . __LINE__ . ' old,new ->' . $_oldSig . ',' . $_signatureid . '#' . $content [ 'body' ]);
2013-10-10 13:44:01 +02:00
// prepare signatures, the selected sig may be used on top of the body
2013-11-22 14:55:09 +01:00
try
{
2016-03-28 20:51:38 +02:00
$oldSignature = Mail\Account :: read_identity ( $_oldSig , true );
2013-11-22 14:55:09 +01:00
//error_log(__METHOD__.__LINE__.'Old:'.array2string($oldSignature).'#');
$oldSigText = $oldSignature [ 'ident_signature' ];
}
catch ( Exception $e )
{
$oldSignature = array ();
$oldSigText = null ;
}
try
{
2016-03-28 20:51:38 +02:00
$signature = Mail\Account :: read_identity ( $_signatureid , true );
2013-11-22 14:55:09 +01:00
//error_log(__METHOD__.__LINE__.'New:'.array2string($signature).'#');
$sigText = $signature [ 'ident_signature' ];
}
catch ( Exception $e )
{
$signature = array ();
$sigText = null ;
}
//error_log(__METHOD__.'Old:'.$oldSigText.'#');
//error_log(__METHOD__.'New:'.$sigText.'#');
2013-10-10 13:44:01 +02:00
if ( $_currentMode == 'plain' )
{
$oldSigText = $this -> convertHTMLToText ( $oldSigText , true , true );
$sigText = $this -> convertHTMLToText ( $sigText , true , true );
2022-05-02 17:19:37 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " Old signature: " . $oldSigText );
2013-10-10 13:44:01 +02:00
}
2016-03-28 20:51:38 +02:00
//$oldSigText = Mail::merge($oldSigText,array($GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'],'person_id')));
2013-10-10 13:44:01 +02:00
//error_log(__METHOD__.'Old+:'.$oldSigText.'#');
2016-03-28 20:51:38 +02:00
//$sigText = Mail::merge($sigText,array($GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'],'person_id')));
2013-10-10 13:44:01 +02:00
//error_log(__METHOD__.'new+:'.$sigText.'#');
2016-03-28 20:51:38 +02:00
$_htmlConfig = Mail :: $htmLawed_config ;
Mail :: $htmLawed_config [ 'transform_anchor' ] = false ;
2016-06-06 15:08:57 +02:00
$oldSigTextCleaned = str_replace ( array ( " \r " , " \t " , " <br /> \n " , " : " ), array ( " " , " " , " <br /> " , " : " ),
$_currentMode == 'html' ? Api\Html :: purify ( $oldSigText , null , array (), true ) : $oldSigText );
2014-11-20 18:53:52 +01:00
//error_log(__METHOD__.'Old(clean):'.$oldSigTextCleaned.'#');
2013-10-10 13:44:01 +02:00
if ( $_currentMode == 'html' )
{
$content [ 'body' ] = str_replace ( " \n " , '\n' , $content [ 'body' ]); // dont know why, but \n screws up preg_replace
2016-03-28 20:51:38 +02:00
$styles = Mail :: getStyles ( array ( array ( 'body' => $content [ 'body' ])));
2016-05-03 21:17:44 +02:00
if ( stripos ( $content [ 'body' ], 'style' ) !== false ) Api\Mail\Html :: replaceTagsCompletley ( $content [ 'body' ], 'style' , $endtag = '' , true ); // clean out empty or pagewide style definitions / left over tags
2013-10-10 13:44:01 +02:00
}
2016-06-06 15:08:57 +02:00
$content [ 'body' ] = str_replace ( array ( " \r " , " \t " , " <br /> \n " , " : " ), array ( " " , " " , " <br /> " , " : " ),
$_currentMode == 'html' ? Api\Html :: purify ( $content [ 'body' ], Mail :: $htmLawed_config , array (), true ) : $content [ 'body' ]);
2016-03-28 20:51:38 +02:00
Mail :: $htmLawed_config = $_htmlConfig ;
2013-10-10 13:44:01 +02:00
if ( $_currentMode == 'html' )
{
2014-11-20 18:53:52 +01:00
$replaced = null ;
2013-10-10 13:44:01 +02:00
$content [ 'body' ] = preg_replace ( $reg = '|' . preg_quote ( '<!-- HTMLSIGBEGIN -->' , '|' ) . '.*' . preg_quote ( '<!-- HTMLSIGEND -->' , '|' ) . '|u' ,
$rep = '<!-- HTMLSIGBEGIN -->' . $sigText . '<!-- HTMLSIGEND -->' , $in = $content [ 'body' ], - 1 , $replaced );
$content [ 'body' ] = str_replace ( array ( '\n' , " \xe2 \x80 \x93 " , " \xe2 \x80 \x94 " , " \xe2 \x82 \xac " ), array ( " \n " , '–' , '—' , '€' ), $content [ 'body' ]);
//error_log(__METHOD__."() preg_replace('$reg', '$rep', '$in', -1)='".$content['body']."', replaced=$replaced");
2014-11-20 18:53:52 +01:00
unset ( $rep , $in );
2013-10-10 13:44:01 +02:00
if ( $replaced )
{
2014-11-25 00:38:37 +01:00
$content [ 'mailidentity' ] = $_content [ 'mailidentity' ] = $presetSig = $_signatureid ;
2013-10-10 13:44:01 +02:00
$found = false ; // this way we skip further replacement efforts
}
else
{
// try the old way
2014-11-20 18:53:52 +01:00
$found = ( strlen ( trim ( $oldSigTextCleaned )) > 0 ? strpos ( $content [ 'body' ], trim ( $oldSigTextCleaned )) : false );
2013-10-10 13:44:01 +02:00
}
}
else
{
2014-11-20 18:53:52 +01:00
$found = ( strlen ( trim ( $oldSigTextCleaned )) > 0 ? strpos ( $content [ 'body' ], trim ( $oldSigTextCleaned )) : false );
2013-10-10 13:44:01 +02:00
}
2014-11-20 18:53:52 +01:00
if ( $found !== false && $_oldSig != - 2 && ! ( empty ( $oldSigTextCleaned ) || trim ( $this -> convertHTMLToText ( $oldSigTextCleaned , true , true )) == '' ))
2013-10-10 13:44:01 +02:00
{
//error_log(__METHOD__.'Old Content:'.$content['body'].'#');
2014-11-20 18:53:52 +01:00
$_oldSigText = preg_quote ( $oldSigTextCleaned , '~' );
2013-10-10 13:44:01 +02:00
//error_log(__METHOD__.'Old(masked):'.$_oldSigText.'#');
$content [ 'body' ] = preg_replace ( '~' . $_oldSigText . '~mi' , $sigText , $content [ 'body' ], 1 );
//error_log(__METHOD__.'new Content:'.$content['body'].'#');
}
2014-11-20 18:53:52 +01:00
if ( $_oldSig == - 2 && ( empty ( $oldSigTextCleaned ) || trim ( $this -> convertHTMLToText ( $oldSigTextCleaned , true , true )) == '' ))
2013-10-10 13:44:01 +02:00
{
// if there is no sig selected, there is no way to replace a signature
}
if ( $found === false )
{
2022-05-02 17:19:37 +02:00
if ( Mail :: $debug ) error_log ( __METHOD__ . " Old Signature failed to match: " . $oldSigTextCleaned );
if ( Mail :: $debug ) error_log ( __METHOD__ . " Compare content: " . $content [ 'body' ]);
2013-10-10 13:44:01 +02:00
}
else
{
2014-11-25 00:38:37 +01:00
$content [ 'mailidentity' ] = $_content [ 'mailidentity' ] = $presetSig = $_signatureid ;
2013-10-10 13:44:01 +02:00
}
if ( $styles )
{
//error_log($styles);
$content [ 'body' ] = $styles . $content [ 'body' ];
}
}
2013-10-07 17:02:35 +02:00
}
2016-10-05 16:31:58 +02:00
/*run the purify on compose body unconditional*/
2017-11-28 17:04:46 +01:00
$content [ 'body' ] = str_replace ( array ( " \r " , " \t " , " <br /> \n " ), array ( " " , " " , " <br /> " ),
2016-10-05 16:31:58 +02:00
$_currentMode == 'html' ? Api\Html :: purify ( $content [ 'body' ], Mail :: $htmLawed_config , array (), true ) : $content [ 'body' ]);
2013-10-07 17:02:35 +02:00
2013-10-10 13:44:01 +02:00
// do not double insert a signature on a server roundtrip
if ( $buttonClicked ) $suppressSigOnTop = true ;
2018-02-28 17:30:29 +01:00
2018-07-11 14:39:28 +02:00
// On submit reads external_vcard widget's value and addes them as attachments.
2018-02-28 17:30:29 +01:00
// this happens when we send vcards from addressbook to an opened compose
// dialog.
2022-04-26 18:46:23 +02:00
if ( ! empty ( $appendix_data [ 'files' ]))
2018-02-28 17:30:29 +01:00
{
2018-07-11 14:39:28 +02:00
$_REQUEST [ 'preset' ][ 'file' ] = $appendix_data [ 'files' ][ 'file' ];
$_REQUEST [ 'preset' ][ 'type' ] = $appendix_data [ 'files' ][ 'type' ];
2018-07-12 15:42:07 +02:00
$_content [ 'filemode' ] = ! empty ( $appendix_data [ 'files' ][ 'filemode' ]) &&
isset ( Vfs\Sharing :: $modes [ $appendix_data [ 'files' ][ 'filemode' ]]) ?
$appendix_data [ 'files' ][ 'filemode' ] : Vfs\Sharing :: ATTACH ;
2018-02-28 17:30:29 +01:00
$suppressSigOnTop = true ;
unset ( $_content [ 'attachments' ]);
$this -> addPresetFiles ( $content , $insertSigOnTop , true );
}
2014-04-29 11:53:47 +02:00
if ( $isFirstLoad )
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
$alwaysAttachVCardAtCompose = false ; // we use this to eliminate double attachments, if users VCard is already present/attached
2014-05-13 15:10:53 +02:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'apps' ][ 'stylite' ]) && ( isset ( $this -> mailPreferences [ 'attachVCardAtCompose' ]) &&
$this -> mailPreferences [ 'attachVCardAtCompose' ]))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
$alwaysAttachVCardAtCompose = true ;
if ( ! is_array ( $_REQUEST [ 'preset' ][ 'file' ]) && ! empty ( $_REQUEST [ 'preset' ][ 'file' ]))
{
$f = $_REQUEST [ 'preset' ][ 'file' ];
$_REQUEST [ 'preset' ][ 'file' ] = array ( $f );
}
$_REQUEST [ 'preset' ][ 'file' ][] = " vfs://default/apps/addressbook/ " . $GLOBALS [ 'egw' ] -> accounts -> id2name ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ], 'person_id' ) . " /.entry " ;
2013-07-20 09:23:55 +02:00
}
2014-04-29 11:53:47 +02:00
// an app passed the request for fetching and mailing an entry
if ( isset ( $_REQUEST [ 'app' ]) && isset ( $_REQUEST [ 'method' ]) && isset ( $_REQUEST [ 'id' ]))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
$app = $_REQUEST [ 'app' ];
$mt = $_REQUEST [ 'method' ];
$id = $_REQUEST [ 'id' ];
// passed method MUST be registered
2016-05-03 21:17:44 +02:00
$method = Link :: get_registry ( $app , $mt );
2014-04-29 11:53:47 +02:00
//error_log(__METHOD__.__LINE__.array2string($method));
if ( $method )
{
$res = ExecMethod ( $method , array ( $id , 'html' ));
2015-11-05 13:03:03 +01:00
//error_log(__METHOD__.__LINE__.array2string($res));
2014-04-29 11:53:47 +02:00
if ( ! empty ( $res ))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
$insertSigOnTop = 'below' ;
if ( isset ( $res [ 'attachments' ]) && is_array ( $res [ 'attachments' ]))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
foreach ( $res [ 'attachments' ] as $f )
{
$_REQUEST [ 'preset' ][ 'file' ][] = $f ;
}
2013-07-20 09:23:55 +02:00
}
2014-04-29 11:53:47 +02:00
$content [ 'subject' ] = lang ( $app ) . ' #' . $res [ 'id' ] . ': ' ;
foreach ( array ( 'subject' , 'body' , 'mimetype' ) as $name ) {
$sName = $name ;
2015-11-05 13:03:03 +01:00
if ( $name == 'mimetype' && $res [ $name ])
2014-04-29 11:53:47 +02:00
{
$sName = 'mimeType' ;
$content [ $sName ] = $res [ $name ];
}
else
{
if ( $res [ $name ]) $content [ $sName ] .= ( strlen ( $content [ $sName ]) > 0 ? ' ' : '' ) . $res [ $name ];
}
2013-07-20 09:23:55 +02:00
}
}
}
}
2014-04-29 11:53:47 +02:00
// handle preset info/values
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_REQUEST [ 'preset' ]))
2014-04-29 11:53:47 +02:00
{
2015-11-05 13:03:03 +01:00
$alreadyProcessed = array ();
2014-04-29 11:53:47 +02:00
//_debug_array($_REQUEST);
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_REQUEST [ 'preset' ][ 'mailto' ])) {
2014-04-29 11:53:47 +02:00
// handle mailto strings such as
// mailto:larry,dan?cc=mike&bcc=sue&subject=test&body=type+your&body=message+here
// the above string may be htmlentyty encoded, then multiple body tags are supported
// first, strip the mailto: string out of the mailto URL
$tmp_send_to = ( stripos ( $_REQUEST [ 'preset' ][ 'mailto' ], 'mailto' ) === false ? $_REQUEST [ 'preset' ][ 'mailto' ] : trim ( substr ( html_entity_decode ( $_REQUEST [ 'preset' ][ 'mailto' ]), 7 )));
// check if there is more than the to address
$mailtoArray = explode ( '?' , $tmp_send_to , 2 );
if ( $mailtoArray [ 1 ]) {
// check if there are more than one requests
$addRequests = explode ( '&' , $mailtoArray [ 1 ]);
foreach ( $addRequests as $key => $reqval ) {
// the additional requests should have a =, to separate key from value.
2018-07-05 11:28:12 +02:00
$reqval = preg_replace ( '/__AMPERSAND__/i' , " & " , $reqval );
2014-04-29 11:53:47 +02:00
$keyValuePair = explode ( '=' , $reqval , 2 );
$content [ $keyValuePair [ 0 ]] .= ( strlen ( $content [ $keyValuePair [ 0 ]]) > 0 ? ' ' : '' ) . $keyValuePair [ 1 ];
}
}
2018-07-05 11:28:12 +02:00
$content [ 'to' ] = preg_replace ( '/__AMPERSAND__/i' , " & " , $mailtoArray [ 0 ]);
2015-11-05 13:03:03 +01:00
$alreadyProcessed [ 'to' ] = 'to' ;
2014-04-29 11:53:47 +02:00
// if the mailto string is not htmlentity decoded the arguments are passed as simple requests
foreach ( array ( 'cc' , 'bcc' , 'subject' , 'body' ) as $name ) {
2015-11-05 13:03:03 +01:00
$alreadyProcessed [ $name ] = $name ;
2014-04-29 11:53:47 +02:00
if ( $_REQUEST [ $name ]) $content [ $name ] .= ( strlen ( $content [ $name ]) > 0 ? ( $name == 'cc' || $name == 'bcc' ? ',' : ' ' ) : '' ) . $_REQUEST [ $name ];
2013-07-20 09:23:55 +02:00
}
}
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_REQUEST [ 'preset' ][ 'mailtocontactbyid' ])) {
2014-04-29 11:53:47 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'addressbook' ]) {
2016-03-29 12:13:32 +02:00
$contacts_obj = new Api\Contacts ();
2014-04-29 11:53:47 +02:00
$addressbookprefs =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'addressbook' ];
2016-03-29 10:46:09 +02:00
if ( method_exists ( $contacts_obj , 'search' )) {
2013-07-20 09:23:55 +02:00
2014-04-29 11:53:47 +02:00
$addressArray = explode ( ',' , $_REQUEST [ 'preset' ][ 'mailtocontactbyid' ]);
foreach (( array ) $addressArray as $id => $addressID )
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
$addressID = ( int ) $addressID ;
if ( ! ( $addressID > 0 ))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
unset ( $addressArray [ $id ]);
2013-07-20 09:23:55 +02:00
}
2014-04-29 11:53:47 +02:00
}
if ( count ( $addressArray ))
{
$_searchCond = array ( 'contact_id' => $addressArray );
//error_log(__METHOD__.__LINE__.$_searchString);
2017-12-01 14:58:44 +01:00
$showAccounts = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'addressbook' ][ 'hide_accounts' ] !== '1' ;
2014-04-29 11:53:47 +02:00
$filter = ( $showAccounts ? array () : array ( 'account_id' => null ));
$filter [ 'cols_to_search' ] = array ( 'n_fn' , 'email' , 'email_home' );
2016-03-29 10:46:09 +02:00
$contacts = $contacts_obj -> search ( $_searchCond , array ( 'n_fn' , 'email' , 'email_home' ), 'n_fn' , '' , '%' , false , 'OR' , array ( 0 , 100 ), $filter );
2014-04-29 11:53:47 +02:00
// additionally search the accounts, if the contact storage is not the account storage
if ( $showAccounts &&
$GLOBALS [ 'egw_info' ][ 'server' ][ 'account_repository' ] == 'ldap' &&
$GLOBALS [ 'egw_info' ][ 'server' ][ 'contact_repository' ] == 'sql' )
2013-07-20 09:23:55 +02:00
{
2016-03-29 10:46:09 +02:00
$accounts = $contacts_obj -> search ( $_searchCond , array ( 'n_fn' , 'email' , 'email_home' ), 'n_fn' , '' , '%' , false , 'OR' , array ( 0 , 100 ), array ( 'owner' => 0 ));
2014-04-29 11:53:47 +02:00
if ( $contacts && $accounts )
{
$contacts = array_merge ( $contacts , $accounts );
2016-07-10 11:09:21 +02:00
usort ( $contacts , function ( $a , $b )
{
return strcasecmp ( $a [ 'n_fn' ], $b [ 'n_fn' ]);
});
2014-04-29 11:53:47 +02:00
}
elseif ( $accounts )
{
$contacts =& $accounts ;
}
unset ( $accounts );
2013-07-20 09:23:55 +02:00
}
}
2014-04-29 11:53:47 +02:00
if ( is_array ( $contacts )) {
$mailtoArray = array ();
$primary = $addressbookprefs [ 'distributionListPreferredMail' ];
if ( $primary != 'email' && $primary != 'email_home' ) $primary = 'email' ;
$secondary = ( $primary == 'email' ? 'email_home' : 'email' );
//error_log(__METHOD__.__LINE__.array2string($contacts));
foreach ( $contacts as $contact ) {
$innerCounter = 0 ;
foreach ( array ( $contact [ $primary ], $contact [ $secondary ]) as $email ) {
// use pref distributionListPreferredMail for the primary address
// avoid wrong addresses, if an rfc822 encoded address is in addressbook
$email = preg_replace ( " /(^.*<)([a-zA-Z0-9_ \ -]+@[a-zA-Z0-9_ \ - \ .]+)(.*)/ " , '$2' , $email );
$contact [ 'n_fn' ] = str_replace ( array ( ',' , '@' ), ' ' , $contact [ 'n_fn' ]);
$completeMailString = addslashes ( trim ( $contact [ 'n_fn' ] ? $contact [ 'n_fn' ] : $contact [ 'fn' ]) . ' <' . trim ( $email ) . '>' );
if ( $innerCounter == 0 && ! empty ( $email ) && in_array ( $completeMailString , $mailtoArray ) === false ) {
$i ++ ;
$innerCounter ++ ;
$mailtoArray [ $i ] = $completeMailString ;
}
2013-07-20 09:23:55 +02:00
}
}
}
2014-04-29 11:53:47 +02:00
//error_log(__METHOD__.__LINE__.array2string($mailtoArray));
2015-11-05 13:03:03 +01:00
$alreadyProcessed [ 'to' ] = 'to' ;
2014-04-29 11:53:47 +02:00
$content [ 'to' ] = $mailtoArray ;
2013-07-20 09:23:55 +02:00
}
}
}
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_REQUEST [ 'preset' ][ 'file' ]))
2013-07-20 09:23:55 +02:00
{
2014-12-03 17:25:10 +01:00
$content [ 'filemode' ] = ! empty ( $_REQUEST [ 'preset' ][ 'filemode' ]) &&
2020-03-26 20:20:20 +01:00
( isset ( Vfs\Sharing :: $modes [ $_REQUEST [ 'preset' ][ 'filemode' ]]) || isset ( Vfs\HiddenUploadSharing :: $modes [ $_REQUEST [ 'preset' ][ 'filemode' ]])) ?
2016-03-21 11:30:48 +01:00
$_REQUEST [ 'preset' ][ 'filemode' ] : Vfs\Sharing :: ATTACH ;
2014-12-03 17:25:10 +01:00
2018-02-28 17:30:29 +01:00
$this -> addPresetFiles ( $content , $insertSigOnTop , $alwaysAttachVCardAtCompose );
2014-04-29 11:53:47 +02:00
$remember = array ();
if ( isset ( $_REQUEST [ 'preset' ][ 'mailto' ]) || ( isset ( $_REQUEST [ 'app' ]) && isset ( $_REQUEST [ 'method' ]) && isset ( $_REQUEST [ 'id' ])))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
foreach ( array_keys ( $content ) as $k )
{
2015-11-05 13:03:03 +01:00
if ( in_array ( $k , array ( 'to' , 'cc' , 'bcc' , 'subject' , 'body' , 'mimeType' )) && isset ( $this -> sessionData [ $k ]))
{
$alreadyProcessed [ $k ] = $k ;
$remember [ $k ] = $this -> sessionData [ $k ];
}
2014-04-29 11:53:47 +02:00
}
2013-07-20 09:23:55 +02:00
}
2014-04-29 11:53:47 +02:00
if ( ! empty ( $remember )) $content = array_merge ( $content , $remember );
2013-07-20 09:23:55 +02:00
}
2023-06-30 16:33:28 +02:00
foreach ( array ( 'to' , 'cc' , 'bcc' , 'subject' , 'body' , 'mimeType' , 'replyto' , 'priority' ) as $name )
2013-07-20 09:23:55 +02:00
{
2015-11-05 13:03:03 +01:00
//always handle mimeType
2022-04-26 18:46:23 +02:00
if ( $name == 'mimeType' && ! empty ( $_REQUEST [ 'preset' ][ $name ]))
2015-11-05 13:03:03 +01:00
{
$_content [ $name ] = $content [ $name ] = $_REQUEST [ 'preset' ][ $name ];
}
//skip if already processed by "preset Routines"
if ( $alreadyProcessed [ $name ]) continue ;
//error_log(__METHOD__.__LINE__.':'.$name.'->'. $_REQUEST['preset'][$name]);
2022-04-26 18:46:23 +02:00
if ( ! empty ( $_REQUEST [ 'preset' ][ $name ])) $content [ $name ] = $_REQUEST [ 'preset' ][ $name ];
2013-07-20 09:23:55 +02:00
}
2023-10-27 09:21:00 +02:00
// if we preset the body, we always want the signature below (independent of user preference for replay or forward!)
if ( ! empty ( $_REQUEST [ 'preset' ][ 'body' ]))
{
$insertSigOnTop = 'below' ;
}
2013-07-20 09:23:55 +02:00
}
2014-04-29 11:53:47 +02:00
// is the to address set already?
if ( ! empty ( $_REQUEST [ 'send_to' ]))
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
$content [ 'to' ] = base64_decode ( $_REQUEST [ 'send_to' ]);
// first check if there is a questionmark or ampersand
if ( strpos ( $content [ 'to' ], '?' ) !== false ) list ( $content [ 'to' ], $rest ) = explode ( '?' , $content [ 'to' ], 2 );
$content [ 'to' ] = html_entity_decode ( $content [ 'to' ]);
if (( $at_pos = strpos ( $content [ 'to' ], '@' )) !== false )
{
if (( $amp_pos = strpos ( substr ( $content [ 'to' ], $at_pos ), '&' )) !== false )
{
//list($email,$addoptions) = explode('&',$value,2);
$email = substr ( $content [ 'to' ], 0 , $amp_pos + $at_pos );
$rest = substr ( $content [ 'to' ], $amp_pos + $at_pos + 1 );
//error_log(__METHOD__.__LINE__.$email.' '.$rest);
$content [ 'to' ] = $email ;
}
}
2016-05-03 21:17:44 +02:00
if ( strpos ( $content [ 'to' ], '%40' ) !== false ) $content [ 'to' ] = Api\Html :: purify ( str_replace ( '%40' , '@' , $content [ 'to' ]));
$rarr = array ( Api\Html :: purify ( $rest ));
2014-04-29 11:53:47 +02:00
if ( isset ( $rest ) &&! empty ( $rest ) && strpos ( $rest , '&' ) !== false ) $rarr = explode ( '&' , $rest );
//error_log(__METHOD__.__LINE__.$content['to'].'->'.array2string($rarr));
$karr = array ();
2014-10-23 13:28:36 +02:00
foreach ( $rarr as & $rval )
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
//must contain =
if ( strpos ( $rval , '=' ) !== false )
{
list ( $k , $v ) = explode ( '=' , $rval , 2 );
2014-11-20 18:53:52 +01:00
$karr [ $k ] = ( string ) $v ;
unset ( $k , $v );
2014-04-29 11:53:47 +02:00
}
2013-07-20 09:23:55 +02:00
}
2014-04-29 11:53:47 +02:00
//error_log(__METHOD__.__LINE__.$content['to'].'->'.array2string($karr));
foreach ( array ( 'cc' , 'bcc' , 'subject' , 'body' ) as $name )
2013-07-20 09:23:55 +02:00
{
2014-04-29 11:53:47 +02:00
if ( $karr [ $name ]) $content [ $name ] = $karr [ $name ];
2013-07-20 09:23:55 +02:00
}
2016-05-03 21:17:44 +02:00
if ( ! empty ( $_REQUEST [ 'subject' ])) $content [ 'subject' ] = Api\Html :: purify ( trim ( html_entity_decode ( $_REQUEST [ 'subject' ])));
2013-07-20 09:23:55 +02:00
}
}
2015-11-05 13:03:03 +01:00
//error_log(__METHOD__.__LINE__.array2string($content));
2013-07-20 09:23:55 +02:00
//is the MimeType set/requested
2014-04-29 11:53:47 +02:00
if ( $isFirstLoad && ! empty ( $_REQUEST [ 'mimeType' ]))
2013-07-20 09:23:55 +02:00
{
2015-11-05 13:03:03 +01:00
$_content [ 'mimeType' ] = $content [ 'mimeType' ];
2014-02-04 12:31:13 +01:00
if (( $_REQUEST [ 'mimeType' ] == " text " || $_REQUEST [ 'mimeType' ] == " plain " ) && $content [ 'mimeType' ] == 'html' )
{
$_content [ 'mimeType' ] = $content [ 'mimeType' ] = 'plain' ;
2021-03-30 20:34:34 +02:00
$html = str_replace ( array ( " \n \r " , " \n " ), ' ' , $content [ 'body' ]);
$content [ 'body' ] = $this -> convertHTMLToText ( $html );
2014-02-04 12:31:13 +01:00
}
if ( $_REQUEST [ 'mimeType' ] == " html " && $content [ 'mimeType' ] != 'html' )
{
$_content [ 'mimeType' ] = $content [ 'mimeType' ] = 'html' ;
$content [ 'body' ] = " <pre> " . $content [ 'body' ] . " </pre> " ;
// take care this assumption is made on the creation of the reply header in bocompose::getReplyData
if ( strpos ( $content [ 'body' ], " <pre> \r \n \r \n --- " ) === 0 ) $content [ 'body' ] = substr_replace ( $content [ 'body' ], " <br> \r \n <pre>--- " , 0 , strlen ( " <pre> \r \n \r \n --- " ) - 1 );
}
2013-07-20 09:23:55 +02:00
}
else
{
// try to enforce a mimeType on reply ( if type is not of the wanted type )
if ( $isReply )
{
2014-05-13 15:10:53 +02:00
if ( ! empty ( $this -> mailPreferences [ 'replyOptions' ]) && $this -> mailPreferences [ 'replyOptions' ] == " text " &&
2013-10-02 16:50:24 +02:00
$content [ 'mimeType' ] == 'html' )
2013-07-20 09:23:55 +02:00
{
2014-02-04 12:31:13 +01:00
$_content [ 'mimeType' ] = $content [ 'mimeType' ] = 'plain' ;
2021-03-30 20:34:34 +02:00
$html = str_replace ( array ( " \n \r " , " \n " ), ' ' , $content [ 'body' ]);
$content [ 'body' ] = $this -> convertHTMLToText ( $html );
2013-07-20 09:23:55 +02:00
}
2014-05-13 15:10:53 +02:00
if ( ! empty ( $this -> mailPreferences [ 'replyOptions' ]) && $this -> mailPreferences [ 'replyOptions' ] == " html " &&
2013-10-02 16:50:24 +02:00
$content [ 'mimeType' ] != 'html' )
2013-07-20 09:23:55 +02:00
{
2014-02-04 12:31:13 +01:00
$_content [ 'mimeType' ] = $content [ 'mimeType' ] = 'html' ;
2013-10-02 16:50:24 +02:00
$content [ 'body' ] = " <pre> " . $content [ 'body' ] . " </pre> " ;
2013-07-20 09:23:55 +02:00
// take care this assumption is made on the creation of the reply header in bocompose::getReplyData
2013-10-02 16:50:24 +02:00
if ( strpos ( $content [ 'body' ], " <pre> \r \n \r \n --- " ) === 0 ) $content [ 'body' ] = substr_replace ( $content [ 'body' ], " <br> \r \n <pre>--- " , 0 , strlen ( " <pre> \r \n \r \n --- " ) - 1 );
2013-07-20 09:23:55 +02:00
}
}
}
2013-10-10 13:44:01 +02:00
2013-07-20 09:23:55 +02:00
// is a certain signature requested?
// only the following values are supported (and make sense)
// no => means -2
// system => means -1
// default => fetches the default, which is standard behavior
if ( ! empty ( $_REQUEST [ 'signature' ]) && ( strtolower ( $_REQUEST [ 'signature' ]) == 'no' || strtolower ( $_REQUEST [ 'signature' ]) == 'system' ))
{
2015-03-18 17:31:30 +01:00
$content [ 'mailidentity' ] = $presetSig = ( strtolower ( $_REQUEST [ 'signature' ]) == 'no' ? - 2 : - 1 );
2013-07-20 09:23:55 +02:00
}
$disableRuler = false ;
2014-11-25 00:38:37 +01:00
//_debug_array(($presetSig ? $presetSig : $content['mailidentity']));
2013-11-22 14:55:09 +01:00
try
{
2016-03-28 20:51:38 +02:00
$signature = Mail\Account :: read_identity ( $content [ 'mailidentity' ] ? $content [ 'mailidentity' ] : $presetSig , true );
2013-11-22 14:55:09 +01:00
}
catch ( Exception $e )
{
//PROBABLY NOT FOUND
$signature = array ();
}
2022-04-30 12:10:47 +02:00
if ( ! empty ( $this -> mailPreferences [ 'disableRulerForSignatureSeparation' ]) ||
empty ( $signature [ 'ident_signature' ]))
2013-07-20 09:23:55 +02:00
{
$disableRuler = true ;
}
2022-02-02 13:51:20 +01:00
2013-07-20 09:23:55 +02:00
//remove possible html header stuff
2013-10-02 16:50:24 +02:00
if ( stripos ( $content [ 'body' ], '<html><head></head><body>' ) !== false ) $content [ 'body' ] = str_ireplace ( array ( '<html><head></head><body>' , '</body></html>' ), array ( '' , '' ), $content [ 'body' ]);
2014-05-13 15:10:53 +02:00
//error_log(__METHOD__.__LINE__.array2string($this->mailPreferences));
2013-07-20 09:23:55 +02:00
$blockElements = array ( 'address' , 'blockquote' , 'center' , 'del' , 'dir' , 'div' , 'dl' , 'fieldset' , 'form' , 'h1' , 'h2' , 'h3' , 'h4' , 'h5' , 'h6' , 'hr' , 'ins' , 'isindex' , 'menu' , 'noframes' , 'noscript' , 'ol' , 'p' , 'pre' , 'table' , 'ul' );
2014-12-04 14:48:43 +01:00
if ( $this -> mailPreferences [ 'insertSignatureAtTopOfMessage' ] != 'no_belowaftersend' &&
2013-07-20 09:23:55 +02:00
! ( isset ( $_POST [ 'mySigID' ]) && ! empty ( $_POST [ 'mySigID' ]) ) && ! $suppressSigOnTop
)
{
2014-12-04 14:48:43 +01:00
// ON tOP OR BELOW? pREF CAN TELL
/*
Signature behavior preference changed . New default , if not set -> 0
2015-02-03 13:29:02 +01:00
'0' => 'after reply, visible during compose' ,
'1' => 'before reply, visible during compose' ,
'no_belowaftersend' => 'appended after reply before sending' ,
2014-12-04 14:48:43 +01:00
*/
$insertSigOnTop = ( $insertSigOnTop ? $insertSigOnTop : ( $this -> mailPreferences [ 'insertSignatureAtTopOfMessage' ] ? $this -> mailPreferences [ 'insertSignatureAtTopOfMessage' ] : 'below' ));
2016-03-28 20:51:38 +02:00
$sigText = Mail :: merge ( $signature [ 'ident_signature' ], array ( $GLOBALS [ 'egw' ] -> accounts -> id2name ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ], 'person_id' )));
2013-10-02 16:50:24 +02:00
if ( $content [ 'mimeType' ] == 'html' )
2013-07-20 09:23:55 +02:00
{
2022-04-30 12:10:47 +02:00
$sigTextStartsWithBlockElement = ! $disableRuler ;
2013-07-20 09:23:55 +02:00
foreach ( $blockElements as $e )
{
if ( $sigTextStartsWithBlockElement ) break ;
if ( stripos ( trim ( $sigText ), '<' . $e ) === 0 ) $sigTextStartsWithBlockElement = true ;
}
}
2022-05-10 13:58:57 +02:00
if ( $content [ 'mimeType' ] === 'html' )
{
$start = " <br/> \n " ;
2022-05-11 18:05:54 +02:00
$before = $disableRuler ? '' : '<hr class="ruler" style="border:1px dotted silver; width:100%;">' ;
2015-03-31 19:01:25 +02:00
$inbetween = '' ;
2013-07-20 09:23:55 +02:00
}
2022-05-10 13:58:57 +02:00
else
{
$before = $disableRuler ? " \r \n " : " \r \n -- \r \n " ;
$start = $inbetween = " \r \n " ;
}
2023-10-27 09:21:00 +02:00
// if we already have a body in compose (not reply or forward!), do NOT add an empty line above it
if ( ! empty ( $content [ 'body' ]) && ! $isReply )
{
$start = '' ;
}
2022-05-10 13:58:57 +02:00
if ( $content [ 'mimeType' ] === 'html' )
2013-07-20 09:23:55 +02:00
{
$sigText = ( $sigTextStartsWithBlockElement ? '' : " <div> " ) . " <!-- HTMLSIGBEGIN --> " . $sigText . " <!-- HTMLSIGEND --> " . ( $sigTextStartsWithBlockElement ? '' : " </div> " );
}
if ( $insertSigOnTop === 'below' )
{
2022-05-10 13:58:57 +02:00
$content [ 'body' ] = $start . $content [ 'body' ] . $before . ( $content [ 'mimeType' ] == 'html' ? $sigText : $this -> convertHTMLToText ( $sigText , true , true ));
2013-07-20 09:23:55 +02:00
}
else
{
2022-05-10 13:58:57 +02:00
$content [ 'body' ] = $start . $before . ( $content [ 'mimeType' ] == 'html' ? $sigText : $this -> convertHTMLToText ( $sigText , true , true )) . $inbetween . $content [ 'body' ];
2013-07-20 09:23:55 +02:00
}
}
2019-07-26 19:48:39 +02:00
// Skip this part if we're merging, it would add an extra line at the top
2019-07-29 21:22:25 +02:00
else if ( ! $content [ 'body' ])
2013-07-20 09:23:55 +02:00
{
2022-04-26 18:46:23 +02:00
$content [ 'body' ] = ( $isFirstLoad === " switchedplaintohtml " ? " </span> " : " " );
2013-07-20 09:23:55 +02:00
}
2013-10-02 16:50:24 +02:00
//error_log(__METHOD__.__LINE__.$content['body']);
2013-08-21 12:47:20 +02:00
2013-07-20 09:23:55 +02:00
// prepare body
// in a way, this tests if we are having real utf-8 (the displayCharset) by now; we should if charsets reported (or detected) are correct
2016-05-03 21:17:44 +02:00
$content [ 'body' ] = Api\Translation :: convert_jsonsafe ( $content [ 'body' ], 'utf-8' );
2014-02-14 14:38:08 +01:00
//error_log(__METHOD__.__LINE__.array2string($content));
2014-11-20 18:53:52 +01:00
// get identities of all accounts as "$acc_id:$ident_id" => $identity
$sel_options [ 'mailaccount' ] = $identities = array ();
2016-03-28 20:51:38 +02:00
foreach ( Mail\Account :: search ( true , false ) as $acc_id => $account )
2014-11-20 18:53:52 +01:00
{
2017-06-12 13:33:56 +02:00
// do NOT add SMTP only accounts as identities
if ( ! $account -> is_imap ( false )) continue ;
2016-01-07 15:35:41 +01:00
foreach ( $account -> identities ( $acc_id ) as $ident_id => $identity )
2014-11-20 18:53:52 +01:00
{
$sel_options [ 'mailaccount' ][ $acc_id . ':' . $ident_id ] = $identity ;
$identities [ $ident_id ] = $identity ;
}
unset ( $account );
}
2016-10-08 14:32:58 +02:00
//$content['bcc'] = array('kl@egroupware.org','kl@leithoff.net');
2013-08-21 12:47:20 +02:00
// address stuff like from, to, cc, replyto
$destinationRows = 0 ;
2013-10-07 14:17:33 +02:00
foreach ( self :: $destinations as $destination ) {
2021-10-07 10:14:08 +02:00
if ( ! empty ( $content [ $destination ]) && ! is_array ( $content [ $destination ]))
2013-10-07 18:33:56 +02:00
{
2021-10-07 10:14:08 +02:00
$content [ $destination ] = ( array ) $content [ $destination ];
2013-10-07 18:33:56 +02:00
}
2021-10-07 10:14:08 +02:00
$addr_content = $content [ strtolower ( $destination )] ? ? [];
2014-04-01 16:56:13 +02:00
// we clear the given address array and rebuild it
unset ( $content [ strtolower ( $destination )]);
2021-10-07 10:14:08 +02:00
foreach ( $addr_content as $value ) {
if ( $value === " NIL@NIL " ) continue ;
if ( $destination === 'replyto' && str_replace ( '"' , '' , $value ) ===
2016-03-13 12:22:44 +01:00
str_replace ( '"' , '' , $identities [ $this -> mail_bo -> getDefaultIdentity ()]))
2014-04-01 16:56:13 +02:00
{
// preserve/restore the value to content.
2022-04-29 12:49:41 +02:00
/** @noinspection UnsupportedStringOffsetOperationsInspection */
2014-04-01 16:56:13 +02:00
$content [ strtolower ( $destination )][] = $value ;
continue ;
}
2013-10-10 16:56:30 +02:00
//error_log(__METHOD__.__LINE__.array2string(array('key'=>$key,'value'=>$value)));
2014-11-20 18:53:52 +01:00
$value = str_replace ( " \" \" " , '"' , htmlspecialchars_decode ( $value , ENT_COMPAT ));
2016-03-28 20:51:38 +02:00
foreach ( Mail :: parseAddressList ( $value ) as $addressObject ) {
2021-10-07 10:14:08 +02:00
if ( $addressObject -> host === '.SYNTAX-ERROR.' ) continue ;
2013-08-21 12:47:20 +02:00
$address = imap_rfc822_write_address ( $addressObject -> mailbox , $addressObject -> host , $addressObject -> personal );
2016-03-28 20:51:38 +02:00
//$address = Mail::htmlentities($address, $this->displayCharset);
2022-04-29 12:49:41 +02:00
/** @noinspection UnsupportedStringOffsetOperationsInspection */
2013-10-05 11:47:34 +02:00
$content [ strtolower ( $destination )][] = $address ;
2013-08-21 12:47:20 +02:00
$destinationRows ++ ;
}
}
}
2013-09-02 17:15:35 +02:00
if ( $_content )
2013-08-21 12:47:20 +02:00
{
2013-11-22 14:55:09 +01:00
//input array of _content had no signature information but was seeded later, and content has a valid setting
2014-11-25 00:38:37 +01:00
if ( ! $_contentHasSigID && $content [ 'mailidentity' ] && array_key_exists ( 'mailidentity' , $_content )) unset ( $_content [ 'mailidentity' ]);
2013-09-02 17:15:35 +02:00
$content = array_merge ( $content , $_content );
2013-10-05 11:47:34 +02:00
if ( ! empty ( $content [ 'folder' ])) $sel_options [ 'folder' ] = $this -> ajax_searchFolder ( 0 , true );
2014-11-20 18:53:52 +01:00
if ( empty ( $content [ 'mailaccount' ])) $content [ 'mailaccount' ] = $this -> mail_bo -> profileID ;
2013-08-21 12:47:20 +02:00
}
else
{
2014-01-13 16:40:34 +01:00
//error_log(__METHOD__.__LINE__.array2string(array($sel_options['mailaccount'],$selectedSender)));
2014-11-20 18:53:52 +01:00
$content [ 'mailaccount' ] = $this -> mail_bo -> profileID ;
2013-10-02 16:50:24 +02:00
//error_log(__METHOD__.__LINE__.$content['body']);
2013-08-21 12:47:20 +02:00
}
2013-10-03 18:09:25 +02:00
$content [ 'is_html' ] = ( $content [ 'mimeType' ] == 'html' ? true : '' );
$content [ 'is_plain' ] = ( $content [ 'mimeType' ] == 'html' ? '' : true );
$content [ 'mail_' . ( $content [ 'mimeType' ] == 'html' ? 'html' : 'plain' ) . 'text' ] = $content [ 'body' ];
2013-09-11 15:46:00 +02:00
$content [ 'showtempname' ] = 0 ;
2013-10-08 16:23:46 +02:00
//if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.'before merging content with uploadforCompose:'.array2string($content['attachments']));
2021-10-07 10:14:08 +02:00
$content [ 'attachments' ] = array_merge ( $content [ 'attachments' ] ? ? [], $content [ 'uploadForCompose' ] ? ? []);
2013-09-11 15:46:00 +02:00
//if (is_array($content['attachments'])) foreach($content['attachments'] as $k => &$file) $file['delete['.$file['tmp_name'].']']=0;
$content [ 'no_griddata' ] = empty ( $content [ 'attachments' ]);
$preserv [ 'attachments' ] = $content [ 'attachments' ];
2020-06-05 22:33:26 +02:00
$content [ 'expiration_blur' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'stylite' ] ? lang ( 'Select a date' ) : lang ( 'EPL only' );
2013-10-02 16:50:24 +02:00
2013-10-08 16:23:46 +02:00
//if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.' Attachments:'.array2string($content['attachments']));
2013-10-07 17:02:35 +02:00
// if no filemanager -> no vfsFileSelector
2021-10-07 10:14:08 +02:00
if ( empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'filemanager' ]))
2013-10-07 17:02:35 +02:00
{
2013-10-11 11:28:33 +02:00
$content [ 'vfsNotAvailable' ] = " mail_DisplayNone " ;
2013-10-07 17:02:35 +02:00
}
// if no infolog -> no save as infolog
2021-10-07 10:14:08 +02:00
if ( empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'infolog' ]))
2013-10-07 17:02:35 +02:00
{
2013-10-11 11:28:33 +02:00
$content [ 'noInfologAvailable' ] = " mail_DisplayNone " ;
2013-10-07 17:02:35 +02:00
}
// if no tracker -> no save as tracker
2021-10-07 10:14:08 +02:00
if ( empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'tracker' ]))
2013-10-07 17:02:35 +02:00
{
2013-10-11 11:28:33 +02:00
$content [ 'noTrackerAvailable' ] = " mail_DisplayNone " ;
2013-10-07 17:02:35 +02:00
}
2021-10-07 10:14:08 +02:00
if ( empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'infolog' ]) && empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'tracker' ]))
2013-10-07 17:02:35 +02:00
{
2013-10-11 11:28:33 +02:00
$content [ 'noSaveAsAvailable' ] = " mail_DisplayNone " ;
2013-10-07 17:02:35 +02:00
}
// composeID to detect if we have changes to certain content
2013-10-07 14:17:33 +02:00
$preserv [ 'composeID' ] = $content [ 'composeID' ] = $this -> composeID ;
//error_log(__METHOD__.__LINE__.' ComposeID:'.$preserv['composeID']);
2013-09-02 17:15:35 +02:00
$preserv [ 'is_html' ] = $content [ 'is_html' ];
$preserv [ 'is_plain' ] = $content [ 'is_plain' ];
2013-10-03 18:09:25 +02:00
if ( isset ( $content [ 'mimeType' ])) $preserv [ 'mimeType' ] = $content [ 'mimeType' ];
2013-10-07 14:17:33 +02:00
$sel_options [ 'mimeType' ] = self :: $mimeTypes ;
$sel_options [ 'priority' ] = self :: $priorities ;
2016-03-21 11:30:48 +01:00
$sel_options [ 'filemode' ] = Vfs\Sharing :: $modes ;
2021-10-07 10:14:08 +02:00
if ( empty ( $content [ 'priority' ])) $content [ 'priority' ] = 3 ;
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.compose' );
2015-01-26 16:04:15 +01:00
2018-06-22 16:04:50 +02:00
$etpl -> setElementAttribute ( 'composeToolbar' , 'actions' , self :: getToolbarActions ( $content ));
2021-10-08 13:05:06 +02:00
if ( $content [ 'mimeType' ] == 'html' )
2013-10-10 13:44:01 +02:00
{
//mode="$cont[rtfEditorFeatures]" validation_rules="$cont[validation_rules]" base_href="$cont[upload_dir]"
2016-03-28 20:51:38 +02:00
$_htmlConfig = Mail :: $htmLawed_config ;
Mail :: $htmLawed_config [ 'comment' ] = 2 ;
Mail :: $htmLawed_config [ 'transform_anchor' ] = false ;
$content [ 'validation_rules' ] = json_encode ( Mail :: $htmLawed_config );
2013-10-10 13:44:01 +02:00
$etpl -> setElementAttribute ( 'mail_htmltext' , 'validation_rules' , $content [ 'validation_rules' ]);
2016-03-28 20:51:38 +02:00
Mail :: $htmLawed_config = $_htmlConfig ;
2013-10-10 13:44:01 +02:00
}
2021-10-07 10:14:08 +02:00
if ( ! empty ( $content [ 'composeID' ]))
2013-10-07 14:17:33 +02:00
{
$composeCache = $content ;
2013-10-10 13:44:01 +02:00
unset ( $composeCache [ 'body' ]);
unset ( $composeCache [ 'mail_htmltext' ]);
unset ( $composeCache [ 'mail_plaintext' ]);
2016-03-28 20:51:38 +02:00
Api\Cache :: setCache ( Api\Cache :: SESSION , 'mail' , 'composeCache' . trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]) . '_' . $this -> composeID , $composeCache , $expiration = 60 * 60 * 2 );
2013-10-07 14:17:33 +02:00
}
2021-10-07 10:14:08 +02:00
if ( empty ( $_content [ 'serverID' ]))
2013-10-08 16:23:46 +02:00
{
$content [ 'serverID' ] = $this -> mail_bo -> profileID ;
}
$preserv [ 'serverID' ] = $content [ 'serverID' ];
2021-10-07 10:14:08 +02:00
$preserv [ 'lastDrafted' ] = $content [ 'lastDrafted' ] ? ? null ;
$preserv [ 'processedmail_id' ] = $content [ 'processedmail_id' ] ? ? null ;
$preserv [ 'references' ] = $content [ 'references' ] ? ? null ;
$preserv [ 'in-reply-to' ] = $content [ 'in-reply-to' ] ? ? null ;
2015-03-06 10:23:13 +01:00
// thread-topic is a proprietary microsoft header and deprecated with the current version
// horde does not support the encoding of thread-topic, and probably will not no so in the future
//$preserv['thread-topic'] = $content['thread-topic'];
2021-10-07 10:14:08 +02:00
$preserv [ 'thread-index' ] = $content [ 'thread-index' ] ? ? null ;
$preserv [ 'list-id' ] = $content [ 'list-id' ] ? ? null ;
$preserv [ 'mode' ] = $content [ 'mode' ] ? ? null ;
2014-01-18 15:52:21 +01:00
// convert it back to checkbox expectations
2021-10-08 13:05:06 +02:00
if ( $content [ 'mimeType' ] == 'html' ) {
2014-01-18 15:52:21 +01:00
$content [ 'mimeType' ] = 1 ;
} else {
$content [ 'mimeType' ] = 0 ;
}
2015-01-09 14:56:14 +01:00
// set the current selected mailaccount as param for folderselection
$etpl -> setElementAttribute ( 'folder' , 'autocomplete_params' , array ( 'mailaccount' => $content [ 'mailaccount' ]));
2014-11-25 00:38:37 +01:00
// join again mailaccount and identity
$content [ 'mailaccount' ] .= ':' . $content [ 'mailidentity' ];
2017-07-05 17:41:31 +02:00
//Try to set the initial selected account to the first identity match found
// which fixes the issue of prefered identity never get selected.
if ( ! in_array ( $content [ 'mailaccount' ], array_keys ( $sel_options [ 'mailaccount' ])))
{
foreach ( $sel_options [ 'mailaccount' ] as $ident => $value )
{
$idnt_acc_parts = explode ( ':' , $ident );
2015-03-31 19:01:25 +02:00
2017-07-05 17:41:31 +02:00
if ( $content [ 'mailidentity' ] == $idnt_acc_parts [ 1 ])
{
$content [ 'mailaccount' ] = $ident ;
break ;
}
}
}
2015-03-19 14:04:37 +01:00
// Resolve distribution list before send content to client
foreach ( array ( 'to' , 'cc' , 'bcc' , 'replyto' ) as $f )
{
2021-10-07 10:14:08 +02:00
if ( isset ( $content [ $f ]) && is_array ( $content [ $f ])) $content [ $f ] = self :: resolveEmailAddressList ( $content [ $f ]);
2015-03-19 14:04:37 +01:00
}
2015-03-31 19:01:25 +02:00
2018-07-12 15:42:07 +02:00
// set filemode icons for all attachments
2021-10-07 10:14:08 +02:00
if ( ! empty ( $content [ 'attachments' ]))
2018-07-12 15:42:07 +02:00
{
2018-12-18 19:19:13 +01:00
foreach ( $content [ 'attachments' ] as & $attach )
{
2022-04-26 18:46:23 +02:00
$attach [ 'is_dir' ] = ! empty ( $attach [ 'file' ]) && is_dir ( $attach [ 'file' ]);
$attach [ 'filemode_icon' ] = ! empty ( $attach [ 'file' ]) && ! is_dir ( $attach [ 'file' ]) && ! empty ( $content [ 'filemode' ]) &&
2018-12-18 19:19:13 +01:00
( $content [ 'filemode' ] == Vfs\Sharing :: READONLY || $content [ 'filemode' ] == Vfs\Sharing :: WRITABLE )
2022-04-26 18:46:23 +02:00
? Vfs\Sharing :: LINK : $content [ 'filemode' ] ? ? '' ;
$attach [ 'filemode_title' ] = lang ( Vfs\Sharing :: $modes [ $attach [ 'filemode_icon' ]][ 'label' ] ? ? '' );
2018-12-18 19:19:13 +01:00
}
2022-08-31 15:09:41 +02:00
$content [ 'attachmentsBlockTitle' ] = count ( $content [ 'attachments' ]) . ' ' . Lang ( 'Attachments' );
2018-07-12 15:42:07 +02:00
}
2022-08-31 12:26:39 +02:00
else
{
unset ( $content [ 'attachments' ]);
}
2018-07-12 15:42:07 +02:00
2021-10-07 10:14:08 +02:00
if ( isset ( $content [ 'to' ])) $content [ 'to' ] = self :: resolveEmailAddressList ( $content [ 'to' ]);
2020-09-25 14:17:29 +02:00
$content [ 'html_toolbar' ] = empty ( Mail :: $mailConfig [ 'html_toolbar' ]) ?
2021-10-07 10:14:08 +02:00
implode ( ',' , Etemplate\Widget\HtmlArea :: $toolbar_default_list ) : implode ( ',' , Mail :: $mailConfig [ 'html_toolbar' ]);
2014-01-30 12:28:20 +01:00
//error_log(__METHOD__.__LINE__.array2string($content));
2014-09-12 13:52:38 +02:00
$etpl -> exec ( 'mail.mail_compose.compose' , $content , $sel_options , array (), $preserv , 2 );
2013-07-20 09:23:55 +02:00
}
2014-01-16 16:58:27 +01:00
2018-02-28 17:30:29 +01:00
/**
* Add preset files like vcard as attachments into content array
*
2018-05-05 11:48:10 +02:00
* Preset attachments are read from $_REQUEST [ 'preset' ][ 'file' ] with
* optional [ 'type' ] and [ 'name' ] .
*
* Attachments must either be in EGroupware Vfs or configured temp . directory !
*
2018-02-28 17:30:29 +01:00
* @ param array $_content content
* @ param string $_insertSigOnTop
* @ param boolean $_eliminateDoubleAttachments
*/
function addPresetFiles ( & $_content , & $_insertSigOnTop , $_eliminateDoubleAttachments )
{
2018-05-05 11:48:10 +02:00
// check if JSON was used
if ( ! is_array ( $_REQUEST [ 'preset' ][ 'file' ]) &&
( $_REQUEST [ 'preset' ][ 'file' ][ 0 ] === '[' && substr ( $_REQUEST [ 'preset' ][ 'file' ], - 1 ) === ']' ||
$_REQUEST [ 'preset' ][ 'file' ][ 0 ] === '{' && substr ( $_REQUEST [ 'preset' ][ 'file' ], - 1 ) === '}' ) &&
( $files = json_decode ( $_REQUEST [ 'preset' ][ 'file' ], true )))
{
$types = ! empty ( $_REQUEST [ 'preset' ][ 'type' ]) ?
json_decode ( $_REQUEST [ 'preset' ][ 'type' ], true ) : array ();
$names = ! empty ( $_REQUEST [ 'preset' ][ 'name' ]) ?
json_decode ( $_REQUEST [ 'preset' ][ 'name' ], true ) : array ();
}
else
{
$files = ( array ) $_REQUEST [ 'preset' ][ 'file' ];
$types = ! empty ( $_REQUEST [ 'preset' ][ 'type' ]) ?
( array ) $_REQUEST [ 'preset' ][ 'type' ] : array ();
$names = ! empty ( $_REQUEST [ 'preset' ][ 'name' ]) ?
( array ) $_REQUEST [ 'preset' ][ 'name' ] : array ();
}
2018-02-28 17:30:29 +01:00
foreach ( $files as $k => $path )
{
if ( ! empty ( $types [ $k ]) && stripos ( $types [ $k ], 'text/calendar' ) !== false )
{
$_insertSigOnTop = 'below' ;
}
//error_log(__METHOD__.__LINE__.$path.'->'.array2string(parse_url($path,PHP_URL_SCHEME == 'vfs')));
2018-05-05 11:48:10 +02:00
if (( $scheme = parse_url ( $path , PHP_URL_SCHEME )) === 'vfs' )
2018-02-28 17:30:29 +01:00
{
$type = Vfs :: mime_content_type ( $path );
// special handling for attaching vCard of iCal --> use their link-title as name
if ( substr ( $path , - 7 ) != '/.entry' ||
! ( list ( $app , $id ) = array_slice ( explode ( '/' , $path ), - 3 )) ||
! ( $name = Link :: title ( $app , $id )))
{
$name = Vfs :: decodePath ( Vfs :: basename ( $path ));
}
else
{
$name .= '.' . Api\MimeMagic :: mime2ext ( $type );
}
// use type specified by caller, if Vfs reports only default, or contains specified type (eg. "text/vcard; charset=utf-8")
if ( ! empty ( $types [ $k ]) && ( $type == 'application/octet-stream' || stripos ( $types [ $k ], $type ) === 0 ))
{
$type = $types [ $k ];
}
$path = str_replace ( '+' , '%2B' , $path );
$formData = array (
'name' => $name ,
'type' => $type ,
'file' => Vfs :: decodePath ( $path ),
'size' => filesize ( Vfs :: decodePath ( $path )),
);
if ( $formData [ 'type' ] == Vfs :: DIR_MIME_TYPE && $_content [ 'filemode' ] == Vfs\Sharing :: ATTACH )
{
$_content [ 'filemode' ] = Vfs\Sharing :: READONLY ;
Framework :: message ( lang ( 'Directories have to be shared.' ), 'info' );
}
}
2018-05-05 11:48:10 +02:00
// do not allow to attache something from server filesystem outside configured temp_dir
elseif ( strpos ( realpath ( parse_url ( $path , PHP_URL_PATH )), realpath ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ]) . '/' ) !== 0 )
{
error_log ( __METHOD__ . " () Attaching ' $path ' outside configured temp. directory ' { $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] } ' denied! " );
}
2018-02-28 17:30:29 +01:00
elseif ( is_readable ( $path ))
{
$formData = array (
'name' => isset ( $names [ $k ]) ? $names [ $k ] : basename ( $path ),
'type' => isset ( $types [ $k ]) ? $types [ $k ] : ( function_exists ( 'mime_content_type' ) ? mime_content_type ( $path ) : Api\MimeMagic :: filename2mime ( $path )),
'file' => $path ,
'size' => filesize ( $path ),
);
}
else
{
continue ;
}
$this -> addAttachment ( $formData , $_content , $_eliminateDoubleAttachments );
}
}
2013-10-04 19:45:33 +02:00
/**
* Get pre - fill a new compose based on an existing email
*
* @ param type $mail_id If composing based on an existing mail , this is the ID of the mail
* @ param type $part_id For multi - part mails , indicates which part
* @ param type $from Indicates what the mail is based on , and how to extract data .
2014-01-15 17:29:30 +01:00
* One of 'compose' , 'composeasnew' , 'reply' , 'reply_all' , 'forward' or 'merge'
2013-10-04 19:45:33 +02:00
* @ param boolean $_focusElement varchar subject , to , body supported
* @ param boolean $suppressSigOnTop
* @ param boolean $isReply
*
* @ return mixed [] Content array pre - filled according to source mail
*/
private function getComposeFrom ( $mail_id , $part_id , $from , & $_focusElement , & $suppressSigOnTop , & $isReply )
{
$content = array ();
2013-10-08 16:23:46 +02:00
//error_log(__METHOD__.__LINE__.array2string($mail_id).", $part_id, $from, $_focusElement, $suppressSigOnTop, $isReply");
// on forward we may have to support multiple ids
if ( $from == 'forward' )
{
$replyIds = explode ( ',' , $mail_id );
$mail_id = $replyIds [ 0 ];
}
2013-10-04 19:45:33 +02:00
$hA = mail_ui :: splitRowID ( $mail_id );
$msgUID = $hA [ 'msgUID' ];
2013-10-03 12:05:05 +02:00
$folder = $hA [ 'folder' ];
2013-10-08 16:23:46 +02:00
$icServerID = $hA [ 'profileID' ];
if ( $icServerID != $this -> mail_bo -> profileID )
{
2014-01-21 09:26:59 +01:00
$this -> changeProfile ( $icServerID );
2013-10-08 16:23:46 +02:00
}
$icServer = $this -> mail_bo -> icServer ;
2013-10-04 19:45:33 +02:00
if ( ! empty ( $folder ) && ! empty ( $msgUID ) )
2013-07-20 09:23:55 +02:00
{
// this fill the session data with the values from the original email
2013-10-04 19:45:33 +02:00
switch ( $from )
{
case 'composefromdraft' :
2015-03-06 10:23:13 +01:00
case 'composeasnew' :
2013-10-04 19:45:33 +02:00
$content = $this -> getDraftData ( $icServer , $folder , $msgUID , $part_id );
2015-09-11 15:45:45 +02:00
if ( $from == 'composefromdraft' ) $content [ 'mode' ] = 'composefromdraft' ;
2014-01-30 10:35:56 +01:00
$content [ 'processedmail_id' ] = $mail_id ;
2014-01-16 16:58:27 +01:00
2013-10-04 19:45:33 +02:00
$_focusElement = 'body' ;
$suppressSigOnTop = true ;
break ;
case 'reply' :
2013-10-05 11:03:51 +02:00
case 'reply_all' :
2013-10-04 19:45:33 +02:00
$content = $this -> getReplyData ( $from == 'reply' ? 'single' : 'all' , $icServer , $folder , $msgUID , $part_id );
2023-06-23 15:07:57 +02:00
if ( $content [ 'mimeType' ] === 'plain' && $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'replyOptions' ] === 'html' )
{
$content [ 'body' ] = htmlspecialchars ( $content [ 'body' ]);
}
2014-01-23 12:56:34 +01:00
$content [ 'processedmail_id' ] = $mail_id ;
$content [ 'mode' ] = 'reply' ;
2013-10-04 19:45:33 +02:00
$_focusElement = 'body' ;
2013-10-10 16:56:30 +02:00
$suppressSigOnTop = false ;
2013-10-04 19:45:33 +02:00
$isReply = true ;
break ;
case 'forward' :
2013-10-08 16:23:46 +02:00
$mode = ( $_GET [ 'mode' ] == 'forwardinline' ? 'inline' : 'asmail' );
// this fill the session data with the values from the original email
2021-03-30 20:34:34 +02:00
foreach ( $replyIds as & $m_id )
2013-10-08 16:23:46 +02:00
{
2021-03-30 20:34:34 +02:00
//error_log(__METHOD__.__LINE__.' ID:'.$m_id.' Mode:'.$mode);
$hA = mail_ui :: splitRowID ( $m_id );
2013-10-08 16:23:46 +02:00
$msgUID = $hA [ 'msgUID' ];
$folder = $hA [ 'folder' ];
$content = $this -> getForwardData ( $icServer , $folder , $msgUID , $part_id , $mode );
}
2014-01-23 12:56:34 +01:00
$content [ 'processedmail_id' ] = implode ( ',' , $replyIds );
$content [ 'mode' ] = 'forward' ;
2014-05-13 15:10:53 +02:00
$isReply = ( $mode ? $mode == 'inline' : $this -> mailPreferences [ 'message_forwarding' ] == 'inline' );
2013-10-10 16:56:30 +02:00
$suppressSigOnTop = false ; // ($mode && $mode=='inline'?true:false);// may be a better solution
2013-10-04 19:45:33 +02:00
$_focusElement = 'to' ;
break ;
default :
error_log ( 'Unhandled compose source: ' . $from );
}
2013-07-20 09:23:55 +02:00
}
2014-01-15 17:29:30 +01:00
else if ( $from == 'merge' && $_REQUEST [ 'document' ])
{
/*
2014-01-16 15:05:07 +01:00
* Special merge from everywhere else because all other apps merge gives
* a document to be downloaded , this opens a compose dialog .
* Use ajax_merge to merge & send multiple
2014-01-15 17:29:30 +01:00
*/
// Merge selected ID (in mailtocontactbyid or $mail_id) into given document
2016-05-03 21:17:44 +02:00
$merge_class = preg_match ( '/^([a-z_-]+_merge)$/' , $_REQUEST [ 'merge' ]) ? $_REQUEST [ 'merge' ] : 'EGroupware\\Api\\Contacts\\Merge' ;
2014-08-12 18:58:07 +02:00
$document_merge = new $merge_class ();
2014-01-15 17:29:30 +01:00
$this -> mail_bo -> openConnection ();
$merge_ids = $_REQUEST [ 'preset' ][ 'mailtocontactbyid' ] ? $_REQUEST [ 'preset' ][ 'mailtocontactbyid' ] : $mail_id ;
2014-11-20 18:53:52 +01:00
if ( ! is_array ( $merge_ids )) $merge_ids = explode ( ',' , $merge_ids );
2014-01-15 17:29:30 +01:00
try
{
$merged_mail_id = '' ;
2019-08-16 18:46:35 +02:00
$folder = $this -> mail_bo -> getDraftFolder ();
2014-11-20 18:53:52 +01:00
if (( $error = $document_merge -> check_document ( $_REQUEST [ 'document' ], '' )))
2014-01-15 17:29:30 +01:00
{
$content [ 'msg' ] = $error ;
return $content ;
}
// Merge does not work correctly (missing to) if current app is not addressbook
2014-01-17 11:47:35 +01:00
//$GLOBALS['egw_info']['flags']['currentapp'] = 'addressbook';
2014-01-15 17:29:30 +01:00
// Actually do the merge
if ( count ( $merge_ids ) <= 1 )
{
2014-01-16 15:05:07 +01:00
$results = $this -> mail_bo -> importMessageToMergeAndSend (
2016-03-21 11:30:48 +01:00
$document_merge , Vfs :: PREFIX . $_REQUEST [ 'document' ], $merge_ids , $folder , $merged_mail_id
2014-01-16 15:05:07 +01:00
);
// Open compose
2014-01-15 17:29:30 +01:00
$merged_mail_id = trim ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]) . mail_ui :: $delimiter .
$this -> mail_bo -> profileID . mail_ui :: $delimiter .
base64_encode ( $folder ) . mail_ui :: $delimiter . $merged_mail_id ;
$content = $this -> getComposeFrom ( $merged_mail_id , $part_id , 'composefromdraft' , $_focusElement , $suppressSigOnTop , $isReply );
}
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2014-01-15 17:29:30 +01:00
{
// if this returns with an exeption, something failed big time
$content [ 'msg' ] = $e -> getMessage ();
}
}
2013-10-04 19:45:33 +02:00
return $content ;
2013-07-20 09:23:55 +02:00
}
/**
* previous bocompose stuff
*/
/**
* replace emailaddresses eclosed in <> ( eg .: < me @ you . de > ) with the emailaddress only ( e . g : me @ you . de )
* always returns 1
*/
static function replaceEmailAdresses ( & $text )
{
// replace emailaddresses eclosed in <> (eg.: <me@you.de>) with the emailaddress only (e.g: me@you.de)
2016-05-03 21:17:44 +02:00
Api\Mail\Html :: replaceEmailAdresses ( $text );
2013-07-20 09:23:55 +02:00
return 1 ;
}
2018-12-20 17:10:41 +01:00
function convertHTMLToText ( & $_html , $sourceishtml = true , $stripcrl = false , $noRepEmailAddr = false )
2013-07-20 09:23:55 +02:00
{
$stripalltags = true ;
// third param is stripalltags, we may not need that, if the source is already in ascii
if ( ! $sourceishtml ) $stripalltags = false ;
2018-12-20 17:10:41 +01:00
return Api\Mail\Html :: convertHTMLToText ( $_html , $this -> displayCharset , $stripcrl , $stripalltags , $noRepEmailAddr );
2013-07-20 09:23:55 +02:00
}
function generateRFC822Address ( $_addressObject )
{
2014-10-20 08:49:23 +02:00
if ( $_addressObject -> personal && $_addressObject -> mailbox && $_addressObject -> host ) {
2013-07-20 09:23:55 +02:00
return sprintf ( '"%s" <%s@%s>' , $this -> mail_bo -> decode_header ( $_addressObject -> personal ), $_addressObject -> mailbox , $this -> mail_bo -> decode_header ( $_addressObject -> host , 'FORCE' ));
2014-10-20 08:49:23 +02:00
} elseif ( $_addressObject -> mailbox && $_addressObject -> host ) {
2013-07-20 09:23:55 +02:00
return sprintf ( " %s@%s " , $_addressObject -> mailbox , $this -> mail_bo -> decode_header ( $_addressObject -> host , 'FORCE' ));
} else {
return $this -> mail_bo -> decode_header ( $_addressObject -> mailbox , true );
}
}
2014-11-21 10:33:34 +01:00
/**
* create a unique id , to keep track of different compose windows
*/
function generateComposeID ()
2013-07-20 09:23:55 +02:00
{
2016-03-28 20:51:38 +02:00
return Mail :: getRandomString ();
2013-07-20 09:23:55 +02:00
}
// $_mode can be:
// single: for a reply to one address
// all: for a reply to all
function getDraftData ( $_icServer , $_folder , $_uid , $_partID = NULL )
{
2014-11-20 18:53:52 +01:00
unset ( $_icServer ); // not used
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'to' ] = array ();
$mail_bo = $this -> mail_bo ;
$mail_bo -> openConnection ();
$mail_bo -> reopen ( $_folder );
// get message headers for specified message
#$headers = $mail_bo->getMessageHeader($_folder, $_uid);
$headers = $mail_bo -> getMessageEnvelope ( $_uid , $_partID );
$addHeadInfo = $mail_bo -> getMessageHeader ( $_uid , $_partID );
2015-03-06 10:23:13 +01:00
// thread-topic is a proprietary microsoft header and deprecated with the current version
// horde does not support the encoding of thread-topic, and probably will not no so in the future
//if ($addHeadInfo['THREAD-TOPIC']) $this->sessionData['thread-topic'] = $addHeadInfo['THREAD-TOPIC'];
2013-07-20 09:23:55 +02:00
//error_log(__METHOD__.__LINE__.array2string($headers));
if ( ! empty ( $addHeadInfo [ 'X-MAILFOLDER' ])) {
foreach ( explode ( '|' , $addHeadInfo [ 'X-MAILFOLDER' ]) as $val ) {
2015-01-09 14:56:14 +01:00
$fval = $val ;
$icServerID = $mail_bo -> icServer -> ImapServerId ;
if ( stripos ( $val , '::' ) !== false ) list ( $icServerID , $fval ) = explode ( '::' , $val , 2 );
if ( $icServerID != $mail_bo -> icServer -> ImapServerId ) continue ;
if ( $mail_bo -> folderExists ( $fval )) $this -> sessionData [ 'folder' ][] = $val ;
2013-07-20 09:23:55 +02:00
}
}
2014-11-25 00:38:37 +01:00
if ( ! empty ( $addHeadInfo [ 'X-MAILIDENTITY' ])) {
2014-01-24 11:30:45 +01:00
// with the new system it would be the identity
try
{
2016-03-28 20:51:38 +02:00
Mail\Account :: read_identity ( $addHeadInfo [ 'X-MAILIDENTITY' ]);
2014-11-25 00:38:37 +01:00
$this -> sessionData [ 'mailidentity' ] = $addHeadInfo [ 'X-MAILIDENTITY' ];
2014-01-24 11:30:45 +01:00
}
catch ( Exception $e )
{
}
2013-07-20 09:23:55 +02:00
}
2013-11-22 14:55:09 +01:00
/*
2013-07-20 09:23:55 +02:00
if ( ! empty ( $addHeadInfo [ 'X-STATIONERY' ])) {
$this -> sessionData [ 'stationeryID' ] = $addHeadInfo [ 'X-STATIONERY' ];
}
2013-11-22 14:55:09 +01:00
*/
2014-11-25 00:38:37 +01:00
if ( ! empty ( $addHeadInfo [ 'X-MAILACCOUNT' ])) {
2014-01-24 11:30:45 +01:00
// with the new system it would the identity is the account id
try
{
2016-03-28 20:51:38 +02:00
Mail\Account :: read ( $addHeadInfo [ 'X-MAILACCOUNT' ]);
2014-11-25 00:38:37 +01:00
$this -> sessionData [ 'mailaccount' ] = $addHeadInfo [ 'X-MAILACCOUNT' ];
2014-01-24 11:30:45 +01:00
}
catch ( Exception $e )
{
2016-03-13 12:22:44 +01:00
unset ( $e );
2014-01-24 11:30:45 +01:00
// fail silently
$this -> sessionData [ 'mailaccount' ] = $mail_bo -> profileID ;
}
2013-07-20 09:23:55 +02:00
}
// if the message is located within the draft folder, add it as last drafted version (for possible cleanup on abort))
2015-01-26 16:04:15 +01:00
if ( $mail_bo -> isDraftFolder ( $_folder )) $this -> sessionData [ 'lastDrafted' ] = mail_ui :: generateRowID ( $this -> mail_bo -> profileID , $_folder , $_uid ); //array('uid'=>$_uid,'folder'=>$_folder);
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'uid' ] = $_uid ;
$this -> sessionData [ 'messageFolder' ] = $_folder ;
$this -> sessionData [ 'isDraft' ] = true ;
2014-11-20 18:53:52 +01:00
$foundAddresses = array ();
2013-07-20 09:23:55 +02:00
foreach (( array ) $headers [ 'CC' ] as $val ) {
2016-03-28 20:51:38 +02:00
$rfcAddr = Mail :: parseAddressList ( $val );
2014-01-24 11:30:45 +01:00
$_rfcAddr = $rfcAddr [ 0 ];
2014-10-18 18:30:39 +02:00
if ( ! $_rfcAddr -> valid ) continue ;
2014-10-20 08:49:23 +02:00
if ( $_rfcAddr -> mailbox == 'undisclosed-recipients' || ( ! $_rfcAddr -> mailbox && ! $_rfcAddr -> host ) ) {
2013-07-20 09:23:55 +02:00
continue ;
}
2014-01-24 11:30:45 +01:00
$keyemail = $_rfcAddr -> mailbox . '@' . $_rfcAddr -> host ;
if ( ! $foundAddresses [ $keyemail ]) {
2014-11-20 18:53:52 +01:00
$address = $this -> mail_bo -> decode_header ( $val , true );
2014-01-24 11:30:45 +01:00
$this -> sessionData [ 'cc' ][] = $val ;
$foundAddresses [ $keyemail ] = true ;
2013-07-20 09:23:55 +02:00
}
}
foreach (( array ) $headers [ 'TO' ] as $val ) {
2014-01-15 17:29:30 +01:00
if ( ! is_array ( $val ))
{
$this -> sessionData [ 'to' ][] = $val ;
continue ;
}
2016-03-28 20:51:38 +02:00
$rfcAddr = Mail :: parseAddressList ( $val );
2014-01-24 11:30:45 +01:00
$_rfcAddr = $rfcAddr [ 0 ];
2014-10-18 18:30:39 +02:00
if ( ! $_rfcAddr -> valid ) continue ;
2014-10-20 08:49:23 +02:00
if ( $_rfcAddr -> mailbox == 'undisclosed-recipients' || ( ! $_rfcAddr -> mailbox && ! $_rfcAddr -> host ) ) {
2013-07-20 09:23:55 +02:00
continue ;
}
2014-01-24 11:30:45 +01:00
$keyemail = $_rfcAddr -> mailbox . '@' . $_rfcAddr -> host ;
if ( ! $foundAddresses [ $keyemail ]) {
2014-11-20 18:53:52 +01:00
$address = $this -> mail_bo -> decode_header ( $val , true );
2014-01-24 11:30:45 +01:00
$this -> sessionData [ 'to' ][] = $val ;
$foundAddresses [ $keyemail ] = true ;
2013-07-20 09:23:55 +02:00
}
}
2018-11-20 15:13:40 +01:00
$fromAddr = Mail :: parseAddressList ( $addHeadInfo [ 'FROM' ])[ 0 ];
2014-04-15 12:42:30 +02:00
foreach (( array ) $headers [ 'REPLY-TO' ] as $val ) {
2016-03-28 20:51:38 +02:00
$rfcAddr = Mail :: parseAddressList ( $val );
2014-01-24 11:30:45 +01:00
$_rfcAddr = $rfcAddr [ 0 ];
2018-11-20 15:13:40 +01:00
if ( ! $_rfcAddr -> valid || ( $_rfcAddr -> mailbox == $fromAddr -> mailbox && $_rfcAddr -> host == $fromAddr -> host )) continue ;
2014-01-24 11:30:45 +01:00
if ( $_rfcAddr -> mailbox == 'undisclosed-recipients' || ( empty ( $_rfcAddr -> mailbox ) && empty ( $_rfcAddr -> host )) ) {
2013-07-20 09:23:55 +02:00
continue ;
}
2014-01-24 11:30:45 +01:00
$keyemail = $_rfcAddr -> mailbox . '@' . $_rfcAddr -> host ;
2022-04-26 18:46:23 +02:00
if ( empty ( $foundAddresses [ $keyemail ])) {
2014-11-20 18:53:52 +01:00
$address = $this -> mail_bo -> decode_header ( $val , true );
2014-01-24 11:30:45 +01:00
$this -> sessionData [ 'replyto' ][] = $val ;
$foundAddresses [ $keyemail ] = true ;
2013-07-20 09:23:55 +02:00
}
}
foreach (( array ) $headers [ 'BCC' ] as $val ) {
2016-03-28 20:51:38 +02:00
$rfcAddr = Mail :: parseAddressList ( $val );
2014-01-24 11:30:45 +01:00
$_rfcAddr = $rfcAddr [ 0 ];
2014-10-18 18:30:39 +02:00
if ( ! $_rfcAddr -> valid ) continue ;
2014-01-24 11:30:45 +01:00
if ( $_rfcAddr -> mailbox == 'undisclosed-recipients' || ( empty ( $_rfcAddr -> mailbox ) && empty ( $_rfcAddr -> host )) ) {
2013-07-20 09:23:55 +02:00
continue ;
}
2014-01-24 11:30:45 +01:00
$keyemail = $_rfcAddr -> mailbox . '@' . $_rfcAddr -> host ;
2022-04-26 18:46:23 +02:00
if ( empty ( $foundAddresses [ $keyemail ])) {
2014-11-20 18:53:52 +01:00
$address = $this -> mail_bo -> decode_header ( $val , true );
2014-01-24 11:30:45 +01:00
$this -> sessionData [ 'bcc' ][] = $val ;
$foundAddresses [ $keyemail ] = true ;
2013-07-20 09:23:55 +02:00
}
}
2014-02-04 12:31:13 +01:00
//_debug_array($this->sessionData);
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'subject' ] = $mail_bo -> decode_header ( $headers [ 'SUBJECT' ]);
// remove a printview tag if composing
$searchfor = '/^\[' . lang ( 'printview' ) . ':\]/' ;
$this -> sessionData [ 'subject' ] = preg_replace ( $searchfor , '' , $this -> sessionData [ 'subject' ]);
2015-05-19 16:34:35 +02:00
$bodyParts = $mail_bo -> getMessageBody ( $_uid , 'always_display' , $_partID );
2013-07-20 09:23:55 +02:00
//_debug_array($bodyParts);
#$fromAddress = ($headers['FROM'][0]['PERSONAL_NAME'] != 'NIL') ? $headers['FROM'][0]['RFC822_EMAIL'] : $headers['FROM'][0]['EMAIL'];
if ( $bodyParts [ '0' ][ 'mimeType' ] == 'text/html' ) {
$this -> sessionData [ 'mimeType' ] = 'html' ;
2022-04-26 18:46:23 +02:00
foreach ( $bodyParts as $i => & $bodyPart ) {
2013-07-20 09:23:55 +02:00
if ( $i > 0 ) {
$this -> sessionData [ 'body' ] .= '<hr>' ;
}
2022-04-26 18:46:23 +02:00
if ( $bodyPart [ 'mimeType' ] == 'text/plain' ) {
2013-07-20 09:23:55 +02:00
#$bodyParts[$i]['body'] = nl2br($bodyParts[$i]['body']);
2022-04-26 18:46:23 +02:00
$bodyPart [ 'body' ] = " <pre> " . $bodyPart [ 'body' ] . " </pre> " ;
2013-07-20 09:23:55 +02:00
}
2022-04-26 18:46:23 +02:00
if ( $bodyPart [ 'charSet' ] === false ) $bodyPart [ 'charSet' ] = Mail :: detect_encoding ( $bodyPart [ 'body' ]);
$bodyParts [ $i ][ 'body' ] = Api\Translation :: convert_jsonsafe ( $bodyPart [ 'body' ], $bodyPart [ 'charSet' ]);
#error_log( "GetDraftData (HTML) CharSet:".mb_detect_encoding($bodyPart['body'] . 'a' , strtoupper($bodyPart['charSet']).','.strtoupper($this->displayCharset).',UTF-8, ISO-8859-1'));
$this -> sessionData [ 'body' ] .= ( $i > 0 ? " <br> " : " " ) . $bodyPart [ 'body' ] ;
2013-07-20 09:23:55 +02:00
}
2015-06-01 11:27:09 +02:00
$this -> sessionData [ 'body' ] = mail_ui :: resolve_inline_images ( $this -> sessionData [ 'body' ], $_folder , $_uid , $_partID );
2013-07-20 09:23:55 +02:00
} else {
$this -> sessionData [ 'mimeType' ] = 'plain' ;
2022-04-26 18:46:23 +02:00
foreach ( $bodyParts as $i => & $bodyPart ) {
2013-07-20 09:23:55 +02:00
if ( $i > 0 ) {
$this -> sessionData [ 'body' ] .= " <hr> " ;
}
2022-04-26 18:46:23 +02:00
if ( $bodyPart [ 'charSet' ] === false ) $bodyPart [ 'charSet' ] = Mail :: detect_encoding ( $bodyPart [ 'body' ]);
$bodyPart [ 'body' ] = Api\Translation :: convert_jsonsafe ( $bodyPart [ 'body' ], $bodyPart [ 'charSet' ]);
2013-07-20 09:23:55 +02:00
#error_log( "GetDraftData (Plain) CharSet".mb_detect_encoding($bodyParts[$i]['body'] . 'a' , strtoupper($bodyParts[$i]['charSet']).','.strtoupper($this->displayCharset).',UTF-8, ISO-8859-1'));
2022-04-26 18:46:23 +02:00
$this -> sessionData [ 'body' ] .= ( $i > 0 ? " \r \n " : " " ) . $bodyPart [ 'body' ] ;
2013-07-20 09:23:55 +02:00
}
2015-06-01 11:27:09 +02:00
$this -> sessionData [ 'body' ] = mail_ui :: resolve_inline_images ( $this -> sessionData [ 'body' ], $_folder , $_uid , $_partID , 'plain' );
2013-07-20 09:23:55 +02:00
}
2015-07-07 13:44:02 +02:00
2014-10-23 13:28:36 +02:00
if (( $attachments = $mail_bo -> getMessageAttachments ( $_uid , $_partID ))) {
2013-07-20 09:23:55 +02:00
foreach ( $attachments as $attachment ) {
2016-03-10 12:15:45 +01:00
//error_log(__METHOD__.__LINE__.array2string($attachment));
2015-06-11 19:43:17 +02:00
$cid = $attachment [ 'cid' ];
2016-03-10 12:15:45 +01:00
$match = null ;
preg_match ( " /cid: { $cid } / " , $bodyParts [ '0' ][ 'body' ], $match );
//error_log(__METHOD__.__LINE__.'searching for cid:'."/cid:{$cid}/".'#'.$r.'#'.array2string($match));
2015-06-11 19:43:17 +02:00
if ( ! $match || ! $attachment [ 'cid' ])
{
$this -> addMessageAttachment ( $_uid , $attachment [ 'partID' ],
$_folder ,
$attachment [ 'name' ],
$attachment [ 'mimeType' ],
2017-01-12 12:37:20 +01:00
$attachment [ 'size' ],
$attachment [ 'is_winmail' ]);
2015-06-11 19:43:17 +02:00
}
2013-07-20 09:23:55 +02:00
}
}
$mail_bo -> closeConnection ();
2013-10-10 13:44:01 +02:00
return $this -> sessionData ;
2013-07-20 09:23:55 +02:00
}
function getErrorInfo ()
{
if ( isset ( $this -> errorInfo )) {
$errorInfo = $this -> errorInfo ;
unset ( $this -> errorInfo );
return $errorInfo ;
}
return false ;
}
function getForwardData ( $_icServer , $_folder , $_uid , $_partID , $_mode = false )
{
if ( $_mode )
{
2014-05-13 15:10:53 +02:00
$modebuff = $this -> mailPreferences [ 'message_forwarding' ];
$this -> mailPreferences [ 'message_forwarding' ] = $_mode ;
2013-07-20 09:23:55 +02:00
}
2014-05-13 15:10:53 +02:00
if ( $this -> mailPreferences [ 'message_forwarding' ] == 'inline' ) {
2013-07-20 09:23:55 +02:00
$this -> getReplyData ( 'forward' , $_icServer , $_folder , $_uid , $_partID );
}
$mail_bo = $this -> mail_bo ;
$mail_bo -> openConnection ();
$mail_bo -> reopen ( $_folder );
// get message headers for specified message
2016-03-22 09:41:58 +01:00
$headers = $mail_bo -> getMessageEnvelope ( $_uid , $_partID , false , $_folder );
2013-10-08 16:23:46 +02:00
//error_log(__METHOD__.__LINE__.array2string($headers));
2013-07-20 09:23:55 +02:00
//_debug_array($headers); exit;
// check for Re: in subject header
$this -> sessionData [ 'subject' ] = " [FWD] " . $mail_bo -> decode_header ( $headers [ 'SUBJECT' ]);
2014-04-01 13:41:34 +02:00
// the three attributes below are substituted by processedmail_id and mode
2014-01-23 12:56:34 +01:00
//$this->sessionData['sourceFolder']=$_folder;
//$this->sessionData['forwardFlag']='forwarded';
//$this->sessionData['forwardedUID']=$_uid;
2014-05-13 15:10:53 +02:00
if ( $this -> mailPreferences [ 'message_forwarding' ] == 'asmail' ) {
$this -> sessionData [ 'mimeType' ] = $this -> mailPreferences [ 'composeOptions' ];
2013-07-20 09:23:55 +02:00
if ( $headers [ 'SIZE' ])
$size = $headers [ 'SIZE' ];
else
$size = lang ( 'unknown' );
$this -> addMessageAttachment ( $_uid , $_partID , $_folder ,
2014-07-03 12:16:23 +02:00
$mail_bo -> decode_header (( $headers [ 'SUBJECT' ] ? $headers [ 'SUBJECT' ] : lang ( 'no subject' ))) . '.eml' ,
2013-07-20 09:23:55 +02:00
'MESSAGE/RFC822' , $size );
}
else
{
unset ( $this -> sessionData [ 'in-reply-to' ]);
unset ( $this -> sessionData [ 'to' ]);
unset ( $this -> sessionData [ 'cc' ]);
2018-02-07 16:56:39 +01:00
try
{
if (( $attachments = $mail_bo -> getMessageAttachments ( $_uid , $_partID , null , true , false , false ))) {
//error_log(__METHOD__.__LINE__.':'.array2string($attachments));
foreach ( $attachments as $attachment ) {
if ( ! ( $attachment [ 'cid' ] && preg_match ( " /image \ // " , $attachment [ 'mimeType' ])) || $attachment [ 'disposition' ] == 'attachment' )
{
$this -> addMessageAttachment ( $_uid , $attachment [ 'partID' ],
$_folder ,
$attachment [ 'name' ],
$attachment [ 'mimeType' ],
$attachment [ 'size' ]);
}
2015-06-12 16:52:22 +02:00
}
2013-07-20 09:23:55 +02:00
}
}
2018-02-07 16:56:39 +01:00
catch ( Mail\Smime\PassphraseMissing $e )
{
error_log ( __METHOD__ . '() Failed to forward because of smime ' . $e -> getMessage ());
Framework :: message ( lang ( 'Forwarding of this message failed' .
' because the content of this message seems to be encrypted' .
' and can not be decrypted properly. If you still wish to' .
' forward content of this encrypted message, you may try' .
' to use forward as attachment instead.' ), 'error' );
}
2013-07-20 09:23:55 +02:00
}
$mail_bo -> closeConnection ();
if ( $_mode )
{
2014-05-13 15:10:53 +02:00
$this -> mailPreferences [ 'message_forwarding' ] = $modebuff ;
2013-07-20 09:23:55 +02:00
}
2013-10-08 16:23:46 +02:00
//error_log(__METHOD__.__LINE__.array2string($this->sessionData));
return $this -> sessionData ;
}
2014-02-04 12:31:13 +01:00
/**
* adds uploaded files or files in eGW ' s temp directory as attachments
*
* passes the given $_formData representing an attachment to $_content
*
2014-04-15 12:42:30 +02:00
* @ param array $_formData fields of the compose form ( to , cc , bcc , reply - to , subject , body , priority , signature ), plus data of the file ( name , file , size , type )
2014-02-04 12:31:13 +01:00
* @ param array $_content the content passed to the function and to be modified
* @ return void
*/
function addAttachment ( $_formData , & $_content , $eliminateDoubleAttachments = false )
{
2014-03-21 11:37:09 +01:00
//error_log(__METHOD__.__LINE__.' Formdata:'.array2string($_formData).' Content:'.array2string($_content));
2014-02-04 12:31:13 +01:00
$attachfailed = false ;
// to guard against exploits the file must be either uploaded or be in the temp_dir
// check if formdata meets basic restrictions (in tmp dir, or vfs, mimetype, etc.)
try
{
2016-03-28 20:51:38 +02:00
$tmpFileName = Mail :: checkFileBasics ( $_formData , $this -> composeID , false );
2014-02-04 12:31:13 +01:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2014-02-04 12:31:13 +01:00
{
$attachfailed = true ;
$alert_msg = $e -> getMessage ();
2016-05-03 21:17:44 +02:00
Framework :: message ( $e -> getMessage (), 'error' );
2014-02-04 12:31:13 +01:00
}
2014-03-21 11:37:09 +01:00
//error_log(__METHOD__.__LINE__.array2string($tmpFileName));
2014-12-05 12:14:42 +01:00
//error_log(__METHOD__.__LINE__.array2string($_formData));
2014-02-04 12:31:13 +01:00
if ( $eliminateDoubleAttachments == true )
2014-11-20 18:53:52 +01:00
{
foreach (( array ) $_content [ 'attachments' ] as $attach )
{
2014-02-04 12:31:13 +01:00
if ( $attach [ 'name' ] && $attach [ 'name' ] == $_formData [ 'name' ] &&
strtolower ( $_formData [ 'type' ]) == strtolower ( $attach [ 'type' ]) &&
stripos ( $_formData [ 'file' ], 'vfs://' ) !== false ) return ;
2014-11-20 18:53:52 +01:00
}
}
2014-02-04 12:31:13 +01:00
if ( $attachfailed === false )
{
$buffer = array (
'name' => $_formData [ 'name' ],
'type' => $_formData [ 'type' ],
'file' => $tmpFileName ,
2014-03-21 13:56:34 +01:00
'tmp_name' => $tmpFileName ,
2014-02-04 12:31:13 +01:00
'size' => $_formData [ 'size' ]
);
if ( ! is_array ( $_content [ 'attachments' ])) $_content [ 'attachments' ] = array ();
2014-03-21 11:37:09 +01:00
$_content [ 'attachments' ][] = $buffer ;
2014-02-04 12:31:13 +01:00
unset ( $buffer );
}
else
{
error_log ( __METHOD__ . __LINE__ . array2string ( $alert_msg ));
}
}
2017-01-12 12:37:20 +01:00
function addMessageAttachment ( $_uid , $_partID , $_folder , $_name , $_type , $_size , $_is_winmail = null )
2013-10-08 16:23:46 +02:00
{
$this -> sessionData [ 'attachments' ][] = array (
'uid' => $_uid ,
'partID' => $_partID ,
'name' => $_name ,
'type' => $_type ,
'size' => $_size ,
2014-01-31 11:21:58 +01:00
'folder' => $_folder ,
2017-01-12 12:37:20 +01:00
'winmailFlag' => $_is_winmail ,
2021-10-14 09:39:01 +02:00
'tmp_name' => mail_ui :: generateRowID ( $this -> mail_bo -> profileID , $_folder , $_uid ) . '_' . ( ! empty ( $_partID ) ? $_partID : count ( $this -> sessionData [ 'attachments' ] ? ? []) + 1 ),
2013-10-08 16:23:46 +02:00
);
2013-07-20 09:23:55 +02:00
}
2014-01-30 10:35:56 +01:00
function getAttachment ()
{
2015-02-14 21:10:26 +01:00
// read attachment data from etemplate request, use tmpname only to identify it
2016-05-03 21:17:44 +02:00
if (( $request = Etemplate\Request :: read ( $_GET [ 'etemplate_exec_id' ])))
2015-02-14 21:10:26 +01:00
{
foreach ( $request -> preserv [ 'attachments' ] as $attachment )
{
if ( $_GET [ 'tmpname' ] === $attachment [ 'tmp_name' ]) break ;
}
}
if ( ! $request || $_GET [ 'tmpname' ] !== $attachment [ 'tmp_name' ])
{
header ( 'HTTP/1.1 404 Not found' );
die ( 'Attachment ' . htmlspecialchars ( $_GET [ 'tmpname' ]) . ' NOT found!' );
}
2014-01-30 10:35:56 +01:00
2014-01-31 11:21:58 +01:00
//error_log(__METHOD__.__LINE__.array2string($_GET));
2015-02-14 21:10:26 +01:00
if ( parse_url ( $attachment [ 'tmp_name' ], PHP_URL_SCHEME ) == 'vfs' )
2014-01-30 10:35:56 +01:00
{
2016-03-21 11:30:48 +01:00
Vfs :: load_wrapper ( 'vfs' );
2014-10-20 20:08:03 +02:00
}
// attachment data in temp_dir, only use basename of given name, to not allow path traversal
2015-02-14 21:10:26 +01:00
else
2014-10-20 20:08:03 +02:00
{
2016-07-11 10:08:11 +02:00
$attachment [ 'tmp_name' ] = $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] . '/' . basename ( $attachment [ 'tmp_name' ]);
2014-10-20 20:08:03 +02:00
}
2015-02-14 21:10:26 +01:00
if ( ! file_exists ( $attachment [ 'tmp_name' ]))
2014-10-20 20:08:03 +02:00
{
2015-02-14 21:10:26 +01:00
header ( 'HTTP/1.1 404 Not found' );
die ( 'Attachment ' . htmlspecialchars ( $attachment [ 'tmp_name' ]) . ' NOT found!' );
2014-01-30 10:35:56 +01:00
}
2015-02-14 21:10:26 +01:00
$attachment [ 'attachment' ] = file_get_contents ( $attachment [ 'tmp_name' ]);
2014-01-30 10:35:56 +01:00
//error_log(__METHOD__.__LINE__.' FileSize:'.filesize($attachment['tmp_name']));
if ( $_GET [ 'mode' ] != " save " )
{
if ( strtoupper ( $attachment [ 'type' ]) == 'TEXT/DIRECTORY' )
{
$sfxMimeType = $attachment [ 'type' ];
2014-10-20 20:08:03 +02:00
$buff = explode ( '.' , $attachment [ 'tmp_name' ]);
2014-01-30 10:35:56 +01:00
$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 );
2014-01-30 10:35:56 +01: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-22 11:07:25 +01:00
$eventid = $calendar_ical -> iCalSearch ( $attachment [ 'attachment' ], - 1 );
2014-01-30 10:35:56 +01:00
//error_log(__METHOD__.array2string($eventid));
if ( ! $eventid ) $eventid = - 1 ;
$event = $calendar_ical -> importVCal ( $attachment [ 'attachment' ],( is_array ( $eventid ) ? $eventid [ 0 ] : $eventid ), null , true );
//error_log(__METHOD__.$event);
if (( int ) $event > 0 )
{
$vars = array (
'menuaction' => 'calendar.calendar_uiforms.edit' ,
'cal_id' => $event ,
);
$GLOBALS [ 'egw' ] -> redirect_link ( '../index.php' , $vars );
}
//Import failed, download content anyway
}
if ( strtoupper ( $attachment [ 'type' ]) == 'TEXT/X-VCARD' || strtoupper ( $attachment [ 'type' ]) == 'TEXT/VCARD' )
{
$addressbook_vcal = new addressbook_vcal ();
// double \r\r\n seems to end a vcard prematurely, so we set them to \r\n
//error_log(__METHOD__.__LINE__.$attachment['attachment']);
$attachment [ 'attachment' ] = str_replace ( " \r \r \n " , " \r \n " , $attachment [ 'attachment' ]);
$vcard = $addressbook_vcal -> vcardtoegw ( $attachment [ 'attachment' ]);
if ( $vcard [ 'uid' ])
{
$vcard [ 'uid' ] = trim ( $vcard [ 'uid' ]);
//error_log(__METHOD__.__LINE__.print_r($vcard,true));
$contact = $addressbook_vcal -> find_contact ( $vcard , false );
}
if ( ! $contact ) $contact = null ;
// if there are not enough fields in the vcard (or the parser was unable to correctly parse the vcard (as of VERSION:3.0 created by MSO))
if ( $contact || count ( $vcard ) > 2 )
{
$contact = $addressbook_vcal -> addVCard ( $attachment [ 'attachment' ],( is_array ( $contact ) ? array_shift ( $contact ) : $contact ), true );
}
if (( int ) $contact > 0 )
{
$vars = array (
'menuaction' => 'addressbook.addressbook_ui.edit' ,
'contact_id' => $contact ,
);
$GLOBALS [ 'egw' ] -> redirect_link ( '../index.php' , $vars );
}
//Import failed, download content anyway
}
}
2014-02-12 11:56:44 +01:00
//error_log(__METHOD__.__LINE__.'->'.array2string($attachment));
2021-03-30 20:34:34 +02:00
$size = 0 ;
Api\Header\Content :: safe ( $attachment [ 'attachment' ], $attachment [ 'name' ], $attachment [ 'type' ], $size , true , $_GET [ 'mode' ] == " save " );
2014-01-30 10:35:56 +01:00
echo $attachment [ 'attachment' ];
2016-05-03 21:17:44 +02:00
exit ();
2014-01-30 10:35:56 +01:00
}
2013-07-20 09:23:55 +02:00
/**
2014-11-21 10:33:34 +01:00
* Test if string contains one of the keys of an array
2014-11-20 18:53:52 +01:00
*
2013-11-20 16:05:25 +01:00
* @ param array arrayToTestAgainst to test its keys against haystack
* @ param string haystack
* @ return boolean
*/
function testIfOneKeyInArrayDoesExistInString ( $arrayToTestAgainst , $haystack ) {
2014-11-20 18:53:52 +01:00
foreach ( array_keys ( $arrayToTestAgainst ) as $k )
2013-11-20 16:05:25 +01:00
{
//error_log(__METHOD__.__LINE__.':'.$k.'<->'.$haystack);
if ( stripos ( $haystack , $k ) !== false )
{
//error_log(__METHOD__.__LINE__.':FOUND:'.$k.'<->'.$haystack.function_backtrace());
return true ;
}
}
return false ;
}
2013-07-20 09:23:55 +02:00
/**
2014-11-20 18:53:52 +01:00
* Gather the replyData and save it with the session , to be used then
*
2013-07-20 09:23:55 +02:00
* @ param $_mode can be :
* single : for a reply to one address
* all : for a reply to all
* forward : inlineforwarding of a message with its attachments
* @ param $_icServer number ( 0 as it is the active Profile )
* @ param $_folder string
* @ param $_uid number
* @ param $_partID number
*/
function getReplyData ( $_mode , $_icServer , $_folder , $_uid , $_partID )
{
2014-11-20 18:53:52 +01:00
unset ( $_icServer ); // not used
2013-07-20 09:23:55 +02:00
$foundAddresses = array ();
2013-11-20 16:05:25 +01:00
$mail_bo = $this -> mail_bo ;
2013-07-20 09:23:55 +02:00
$mail_bo -> openConnection ();
$mail_bo -> reopen ( $_folder );
2013-12-17 10:55:47 +01:00
$userEMailAddresses = $mail_bo -> getUserEMailAddresses ();
2013-07-20 09:23:55 +02:00
// get message headers for specified message
2013-10-05 16:15:29 +02:00
//print "AAAA: $_folder, $_uid, $_partID<br>";
2014-04-15 12:42:30 +02:00
$headers = $mail_bo -> getMessageEnvelope ( $_uid , $_partID , false , $_folder , $useHeaderInsteadOfEnvelope = true );
//$headers = $mail_bo->getMessageHeader($_uid, $_partID, true, true, $_folder);
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'uid' ] = $_uid ;
$this -> sessionData [ 'messageFolder' ] = $_folder ;
2014-09-09 16:04:40 +02:00
$this -> sessionData [ 'in-reply-to' ] = ( $headers [ 'IN-REPLY-TO' ] ? $headers [ 'IN-REPLY-TO' ] : $headers [ 'MESSAGE_ID' ]);
$this -> sessionData [ 'references' ] = ( $headers [ 'REFERENCES' ] ? $headers [ 'REFERENCES' ] : $headers [ 'MESSAGE_ID' ]);
2017-02-28 15:52:50 +01:00
// break reference into multiple lines if they're greater than 998 chars
// and remove comma seperation. Fix error serer does not support binary
// data due to long references.
if ( strlen ( $this -> sessionData [ 'references' ]) > 998 )
{
$temp_refs = explode ( ',' , $this -> sessionData [ 'references' ]);
$this -> sessionData [ 'references' ] = implode ( " " , $temp_refs );
}
2015-03-06 10:23:13 +01:00
// thread-topic is a proprietary microsoft header and deprecated with the current version
// horde does not support the encoding of thread-topic, and probably will not no so in the future
//if ($headers['THREAD-TOPIC']) $this->sessionData['thread-topic'] = $headers['THREAD-TOPIC'];
2014-09-11 13:51:07 +02:00
if ( $headers [ 'THREAD-INDEX' ]) $this -> sessionData [ 'thread-index' ] = $headers [ 'THREAD-INDEX' ];
if ( $headers [ 'LIST-ID' ]) $this -> sessionData [ 'list-id' ] = $headers [ 'LIST-ID' ];
2014-01-24 11:30:45 +01:00
//error_log(__METHOD__.__LINE__.' Mode:'.$_mode.':'.array2string($headers));
2013-07-20 09:23:55 +02:00
// check for Reply-To: header and use if available
2014-04-15 12:42:30 +02:00
if ( ! empty ( $headers [ 'REPLY-TO' ]) && ( $headers [ 'REPLY-TO' ] != $headers [ 'FROM' ])) {
foreach ( $headers [ 'REPLY-TO' ] as $val ) {
2013-11-20 16:05:25 +01:00
if ( ! $foundAddresses [ $val ]) {
$oldTo [] = $val ;
$foundAddresses [ $val ] = true ;
2013-07-20 09:23:55 +02:00
}
}
2014-04-15 12:42:30 +02:00
$oldToAddress = ( is_array ( $headers [ 'REPLY-TO' ]) ? $headers [ 'REPLY-TO' ][ 0 ] : $headers [ 'REPLY-TO' ]);
2013-07-20 09:23:55 +02:00
} else {
foreach ( $headers [ 'FROM' ] as $val ) {
2013-11-20 16:05:25 +01:00
if ( ! $foundAddresses [ $val ]) {
$oldTo [] = $val ;
$foundAddresses [ $val ] = true ;
2013-07-20 09:23:55 +02:00
}
}
2014-01-24 11:30:45 +01:00
$oldToAddress = ( is_array ( $headers [ 'FROM' ]) ? $headers [ 'FROM' ][ 0 ] : $headers [ 'FROM' ]);
2013-07-20 09:23:55 +02:00
}
2013-11-20 16:05:25 +01:00
//error_log(__METHOD__.__LINE__.' OldToAddress:'.$oldToAddress.'#');
if ( $_mode != 'all' || ( $_mode == 'all' && ! empty ( $oldToAddress ) && ! $this -> testIfOneKeyInArrayDoesExistInString ( $userEMailAddresses , $oldToAddress )) ) {
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'to' ] = $oldTo ;
}
if ( $_mode == 'all' ) {
// reply to any address which is cc, but not to my self
#if($headers->cc) {
foreach ( $headers [ 'CC' ] as $val ) {
2013-11-20 16:05:25 +01:00
if ( $this -> testIfOneKeyInArrayDoesExistInString ( $userEMailAddresses , $val )) {
2013-07-20 09:23:55 +02:00
continue ;
}
2013-11-20 16:05:25 +01:00
if ( ! $foundAddresses [ $val ]) {
$this -> sessionData [ 'cc' ][] = $val ;
$foundAddresses [ $val ] = true ;
2013-07-20 09:23:55 +02:00
}
}
#}
// reply to any address which is to, but not to my self
#if($headers->to) {
foreach ( $headers [ 'TO' ] as $val ) {
2013-11-20 16:05:25 +01:00
if ( $this -> testIfOneKeyInArrayDoesExistInString ( $userEMailAddresses , $val )) {
2013-07-20 09:23:55 +02:00
continue ;
}
2013-11-20 16:05:25 +01:00
if ( ! $foundAddresses [ $val ]) {
$this -> sessionData [ 'to' ][] = $val ;
$foundAddresses [ $val ] = true ;
2013-07-20 09:23:55 +02:00
}
}
#}
#if($headers->from) {
foreach ( $headers [ 'FROM' ] as $val ) {
2013-11-20 16:05:25 +01:00
if ( $this -> testIfOneKeyInArrayDoesExistInString ( $userEMailAddresses , $val )) {
2013-07-20 09:23:55 +02:00
continue ;
}
2013-11-20 16:05:25 +01:00
//error_log(__METHOD__.__LINE__.' '.$val);
if ( ! $foundAddresses [ $val ]) {
$this -> sessionData [ 'to' ][] = $val ;
$foundAddresses [ $val ] = true ;
2013-07-20 09:23:55 +02:00
}
}
#}
}
// check for Re: in subject header
if ( strtolower ( substr ( trim ( $mail_bo -> decode_header ( $headers [ 'SUBJECT' ])), 0 , 3 )) == " re: " ) {
$this -> sessionData [ 'subject' ] = $mail_bo -> decode_header ( $headers [ 'SUBJECT' ]);
} else {
$this -> sessionData [ 'subject' ] = " Re: " . $mail_bo -> decode_header ( $headers [ 'SUBJECT' ]);
}
//_debug_array($headers);
2014-05-13 15:10:53 +02:00
//error_log(__METHOD__.__LINE__.'->'.array2string($this->mailPreferences['htmlOptions']));
2018-02-07 16:56:39 +01:00
try {
$bodyParts = $mail_bo -> getMessageBody ( $_uid , ( $this -> mailPreferences [ 'htmlOptions' ] ? $this -> mailPreferences [ 'htmlOptions' ] : '' ), $_partID );
}
catch ( Mail\Smime\PassphraseMissing $e )
{
$bodyParts = '' ;
error_log ( __METHOD__ . '() Failed to reply because of smime ' . $e -> getMessage ());
Framework :: message ( lang ( 'Replying to this message failed' .
' because the content of this message seems to be encrypted' .
' and can not be decrypted properly. If you still wish to include' .
' content of this encrypted message, you may try to use forward as' .
' attachment instead.' ), 'error' );
}
2013-07-20 09:23:55 +02:00
//_debug_array($bodyParts);
2016-03-28 20:51:38 +02:00
$styles = Mail :: getStyles ( $bodyParts );
2013-07-20 09:23:55 +02:00
2022-05-10 11:51:35 +02:00
$fromAddress = implode ( ', ' , $headers [ 'FROM' ]);
2013-07-20 09:23:55 +02:00
$toAddressA = array ();
$toAddress = '' ;
foreach ( $headers [ 'TO' ] as $mailheader ) {
2013-11-20 16:05:25 +01:00
$toAddressA [] = $mailheader ;
2013-07-20 09:23:55 +02:00
}
if ( count ( $toAddressA ) > 0 )
{
2022-05-10 11:51:35 +02:00
$toAddress = implode ( ', ' , $toAddressA );
$toAddress = htmlspecialchars ( lang ( " to " ) . " : " . $toAddress ) . ( $bodyParts [ '0' ][ 'mimeType' ] == 'text/html' ? " <br> " : " \r \n " );
2013-07-20 09:23:55 +02:00
}
$ccAddressA = array ();
$ccAddress = '' ;
foreach ( $headers [ 'CC' ] as $mailheader ) {
2013-11-20 16:05:25 +01:00
$ccAddressA [] = $mailheader ;
2013-07-20 09:23:55 +02:00
}
if ( count ( $ccAddressA ) > 0 )
{
2022-05-10 11:51:35 +02:00
$ccAddress = implode ( ', ' , $ccAddressA );
$ccAddress = htmlspecialchars ( lang ( " cc " ) . " : " . $ccAddress ) . ( $bodyParts [ '0' ][ 'mimeType' ] == 'text/html' ? " <br> " : " \r \n " );
2013-07-20 09:23:55 +02:00
}
2022-05-10 11:51:35 +02:00
// create original message header in users preferred font and -size
$this -> sessionData [ 'body' ] = self :: wrapBlockWithPreferredFont (
htmlspecialchars ( lang ( " from " ) . " : " . $fromAddress ) . " <br> " .
$toAddress . $ccAddress .
htmlspecialchars ( lang ( " date " ) . " : " . Mail :: _strtotime ( $headers [ 'DATE' ], 'r' , true ), ENT_QUOTES | ENT_IGNORE , Mail :: $displayCharset , false ),
lang ( " original message " ), 'originalMessage' );
if ( $bodyParts [ '0' ][ 'mimeType' ] == 'text/html' )
{
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'mimeType' ] = 'html' ;
if ( ! empty ( $styles )) $this -> sessionData [ 'body' ] .= $styles ;
$this -> sessionData [ 'body' ] .= '<blockquote type="cite">' ;
2022-04-29 12:49:41 +02:00
foreach ( $bodyParts as $i => & $bodyPart )
{
2013-07-20 09:23:55 +02:00
if ( $i > 0 ) {
$this -> sessionData [ 'body' ] .= '<hr>' ;
}
2022-04-29 12:49:41 +02:00
if ( $bodyPart [ 'mimeType' ] == 'text/plain' ) {
#$bodyPart['body'] = nl2br($bodyPart['body'])."<br>";
$bodyPart [ 'body' ] = " <pre> " . $bodyPart [ 'body' ] . " </pre> " ;
2013-07-20 09:23:55 +02:00
}
2022-04-29 12:49:41 +02:00
if ( $bodyPart [ 'charSet' ] === false ) $bodyPart [ 'charSet' ] = Mail :: detect_encoding ( $bodyPart [ 'body' ]);
2013-07-20 09:23:55 +02:00
2016-03-28 20:51:38 +02:00
$_htmlConfig = Mail :: $htmLawed_config ;
Mail :: $htmLawed_config [ 'comment' ] = 2 ;
Mail :: $htmLawed_config [ 'transform_anchor' ] = false ;
2022-04-29 12:49:41 +02:00
$this -> sessionData [ 'body' ] .= " <br> " . self :: _getCleanHTML ( Api\Translation :: convert_jsonsafe ( $bodyPart [ 'body' ], $bodyPart [ 'charSet' ]));
2016-03-28 20:51:38 +02:00
Mail :: $htmLawed_config = $_htmlConfig ;
2022-04-29 12:49:41 +02:00
#error_log( "GetReplyData (HTML) CharSet:".mb_detect_encoding($bodyPart['body'] . 'a' , strtoupper($bodyPart['charSet']).','.strtoupper($this->displayCharset).',UTF-8, ISO-8859-1'));
2013-07-20 09:23:55 +02:00
}
$this -> sessionData [ 'body' ] .= '</blockquote><br>' ;
2015-05-15 16:00:37 +02:00
$this -> sessionData [ 'body' ] = mail_ui :: resolve_inline_images ( $this -> sessionData [ 'body' ], $_folder , $_uid , $_partID , 'html' );
2022-05-10 11:51:35 +02:00
}
else
{
// convert original message header to plain-text
$this -> sessionData [ 'body' ] = self :: convertHTMLToText ( $this -> sessionData [ 'body' ], true , false , true );
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'mimeType' ] = 'plain' ;
2022-04-29 12:49:41 +02:00
foreach ( $bodyParts as $i => & $bodyPart )
{
2013-07-20 09:23:55 +02:00
if ( $i > 0 ) {
$this -> sessionData [ 'body' ] .= " <hr> " ;
}
// add line breaks to $bodyParts
2022-04-29 12:49:41 +02:00
$newBody2 = Api\Translation :: convert_jsonsafe ( $bodyPart [ 'body' ], $bodyPart [ 'charSet' ]);
#error_log( "GetReplyData (Plain) CharSet:".mb_detect_encoding($bodyPart['body'] . 'a' , strtoupper($bodyPart['charSet']).','.strtoupper($this->displayCharset).',UTF-8, ISO-8859-1'));
2016-03-13 12:22:44 +01:00
$newBody = mail_ui :: resolve_inline_images ( $newBody2 , $_folder , $_uid , $_partID , 'plain' );
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'body' ] .= " \r \n " ;
2017-09-06 17:24:10 +02:00
$hasSignature = false ;
2013-07-20 09:23:55 +02:00
// create body new, with good line breaks and indention
2014-11-20 18:53:52 +01:00
foreach ( explode ( " \n " , $newBody ) as $value ) {
2013-07-20 09:23:55 +02:00
// the explode is removing the character
2017-09-06 17:24:10 +02:00
//$value .= 'ee';
// Try to remove signatures from qouted parts to avoid multiple
// signatures problem in reply (rfc3676#section-4.3).
2018-08-17 14:52:32 +02:00
if ( $_mode != 'forward' && ( $hasSignature || ( $hasSignature = preg_match ( " /^-- \ s[ \r \n ] $ / " , $value ))))
2017-09-06 17:24:10 +02:00
{
continue ;
}
2013-07-20 09:23:55 +02:00
$numberOfChars = strspn ( trim ( $value ), " > " );
$appendString = str_repeat ( '>' , $numberOfChars + 1 );
$bodyAppend = $this -> mail_bo -> wordwrap ( $value , 76 - strlen ( " \r \n $appendString " ), " \r \n $appendString " , '>' );
if ( $bodyAppend [ 0 ] == '>' ) {
$bodyAppend = '>' . $bodyAppend ;
} else {
$bodyAppend = '> ' . $bodyAppend ;
}
$this -> sessionData [ 'body' ] .= $bodyAppend ;
}
}
}
$mail_bo -> closeConnection ();
2013-10-03 12:05:05 +02:00
return $this -> sessionData ;
2013-07-20 09:23:55 +02:00
}
2016-03-13 12:22:44 +01:00
2022-05-10 11:51:35 +02:00
/**
* Wrap html block in given tag with preferred font and - size set
*
* @ param string $content
* @ param string $legend
* @ param ? string $class
* @ return string
*/
static function wrapBlockWithPreferredFont ( $content , $legend , $class = null )
{
2022-05-10 18:46:12 +02:00
if ( ! empty ( $class )) $options = ' class="' . htmlspecialchars ( $class ) . '"' ;
2022-05-10 11:51:35 +02:00
2022-05-11 18:05:54 +02:00
return Api\Html :: fieldset ( $content , $legend , $options ? ? '' );
2022-05-10 11:51:35 +02:00
}
2015-11-24 16:35:43 +01:00
/**
* HTML cleanup
*
* @ param type $_body message
2022-05-10 11:51:35 +02:00
* @ param type $_useTidy = false , if true tidy extension will be loaded and tidy will try to clean body message
2015-11-24 16:35:43 +01:00
* since the tidy causes segmentation fault ATM , we set the default to false .
* @ return type
*/
static function _getCleanHTML ( $_body , $_useTidy = false )
2013-07-20 09:23:55 +02:00
{
static $nonDisplayAbleCharacters = array ( '[\016]' , '[\017]' ,
'[\020]' , '[\021]' , '[\022]' , '[\023]' , '[\024]' , '[\025]' , '[\026]' , '[\027]' ,
'[\030]' , '[\031]' , '[\032]' , '[\033]' , '[\034]' , '[\035]' , '[\036]' , '[\037]' );
2015-10-27 10:16:37 +01:00
2015-11-24 16:35:43 +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 ( $_body , 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
{
$_body = $cleaned ;
}
}
2016-03-28 20:51:38 +02:00
Mail :: getCleanHTML ( $_body );
2014-11-20 18:53:52 +01:00
return preg_replace ( $nonDisplayAbleCharacters , '' , $_body );
2013-07-20 09:23:55 +02:00
}
2014-09-11 16:10:01 +02:00
static function _getHostName ()
{
if ( isset ( $_SERVER [ 'SERVER_NAME' ])) {
$result = $_SERVER [ 'SERVER_NAME' ];
} else {
$result = 'localhost.localdomain' ;
}
return $result ;
}
2014-11-22 14:17:41 +01:00
/**
* Create a message from given data and identity
*
2016-05-03 21:17:44 +02:00
* @ param Api\Mailer $_mailObject
2014-11-22 14:17:41 +01:00
* @ param array $_formData
* @ param array $_identity
2015-02-18 11:10:10 +01:00
* @ param boolean $_autosaving = false true : autosaving , false : save - as - draft or send
2016-09-21 15:52:50 +02:00
*
* @ return array returns found inline images as attachment structure
2014-11-22 14:17:41 +01:00
*/
2016-05-03 21:17:44 +02:00
function createMessage ( Api\Mailer $_mailObject , array $_formData , array $_identity , $_autosaving = false )
2013-07-20 09:23:55 +02:00
{
2015-05-18 21:23:05 +02:00
if ( substr ( $_formData [ 'body' ], 0 , 27 ) == '-----BEGIN PGP MESSAGE-----' )
{
$_formData [ 'mimeType' ] = 'openpgp' ;
}
2013-07-20 09:23:55 +02:00
$mail_bo = $this -> mail_bo ;
2016-03-28 20:51:38 +02:00
$activeMailProfile = Mail\Account :: read ( $this -> mail_bo -> profileID );
2014-09-11 16:10:01 +02:00
2013-07-20 09:23:55 +02:00
// you need to set the sender, if you work with different identities, since most smtp servers, dont allow
// sending in the name of someone else
2013-11-21 14:22:34 +01:00
if ( $_identity [ 'ident_id' ] != $activeMailProfile [ 'ident_id' ] && ! empty ( $_identity [ 'ident_email' ]) && strtolower ( $activeMailProfile [ 'ident_email' ]) != strtolower ( $_identity [ 'ident_email' ]))
{
error_log ( __METHOD__ . __LINE__ . ' Faking From/SenderInfo for ' . $activeMailProfile [ 'ident_email' ] . ' with ID:' . $activeMailProfile [ 'ident_id' ] . '. Identitiy to use for sending:' . array2string ( $_identity ));
}
2017-04-24 12:42:20 +02:00
$email_From = $_identity [ 'ident_email' ] ? $_identity [ 'ident_email' ] : $activeMailProfile [ 'ident_email' ];
// Try to fix identity email with no domain part set
$_mailObject -> setFrom ( Mail :: fixInvalidAliasAddress ( Api\Accounts :: id2name ( $_identity [ 'account_id' ], 'account_email' ), $email_From ),
2022-01-10 14:03:14 +01:00
mail_tree :: getIdentityName ( $_identity , false ));
2014-11-22 14:17:41 +01:00
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'X-Priority' , $_formData [ 'priority' ]);
$_mailObject -> addHeader ( 'X-Mailer' , 'EGroupware-Mail' );
2014-11-22 14:17:41 +01:00
if ( ! empty ( $_formData [ 'in-reply-to' ])) {
2014-09-11 13:51:07 +02:00
if ( stripos ( $_formData [ 'in-reply-to' ], '<' ) === false ) $_formData [ 'in-reply-to' ] = '<' . trim ( $_formData [ 'in-reply-to' ]) . '>' ;
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'In-Reply-To' , $_formData [ 'in-reply-to' ]);
2013-07-20 09:23:55 +02:00
}
2014-11-22 14:17:41 +01:00
if ( ! empty ( $_formData [ 'references' ])) {
2017-02-28 15:52:50 +01:00
if ( stripos ( $_formData [ 'references' ], '<' ) === false )
{
$_formData [ 'references' ] = '<' . trim ( $_formData [ 'references' ]) . '>' ;
}
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'References' , $_formData [ 'references' ]);
2014-09-11 11:21:07 +02:00
}
2015-03-06 10:23:13 +01:00
2014-11-22 14:17:41 +01:00
if ( ! empty ( $_formData [ 'thread-index' ])) {
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'Thread-Index' , $_formData [ 'thread-index' ]);
2014-09-11 13:51:07 +02:00
}
2014-11-22 14:17:41 +01:00
if ( ! empty ( $_formData [ 'list-id' ])) {
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'List-Id' , $_formData [ 'list-id' ]);
2014-09-11 13:51:07 +02:00
}
2021-10-07 10:14:08 +02:00
if ( isset ( $_formData [ 'disposition' ]) && $_formData [ 'disposition' ] === 'on' ) {
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'Disposition-Notification-To' , $_identity [ 'ident_email' ]);
2013-07-20 09:23:55 +02:00
}
2013-11-21 23:29:57 +01:00
// Expand any mailing lists
2014-11-25 00:38:37 +01:00
foreach ( array ( 'to' , 'cc' , 'bcc' , 'replyto' ) as $field )
2013-11-21 23:29:57 +01:00
{
2014-10-18 18:30:39 +02:00
if ( $field != 'replyto' ) $_formData [ $field ] = self :: resolveEmailAddressList ( $_formData [ $field ]);
2013-07-20 09:23:55 +02:00
2014-11-25 00:38:37 +01:00
if ( $_formData [ $field ]) $_mailObject -> addAddress ( $_formData [ $field ], '' , $field );
2013-07-20 09:23:55 +02:00
}
2014-11-25 00:38:37 +01:00
$_mailObject -> addHeader ( 'Subject' , $_formData [ 'subject' ]);
2013-07-20 09:23:55 +02:00
$disableRuler = false ;
2014-11-22 14:17:41 +01:00
$signature = $_identity [ 'ident_signature' ];
2014-12-04 14:48:43 +01:00
$sigAlreadyThere = $this -> mailPreferences [ 'insertSignatureAtTopOfMessage' ] != 'no_belowaftersend' ? 1 : 0 ;
2023-06-30 16:33:28 +02:00
if ( $sigAlreadyThere && empty ( $_formData [ 'add_signature' ]))
2013-07-20 09:23:55 +02:00
{
// note: if you use stationery ' s the insert signatures at the top does not apply here anymore, as the signature
// is already part of the body, so the signature part of the template will not be applied.
$signature = null ; // note: no signature, no ruler!!!!
}
2014-05-13 15:10:53 +02:00
if (( isset ( $this -> mailPreferences [ 'disableRulerForSignatureSeparation' ]) &&
$this -> mailPreferences [ 'disableRulerForSignatureSeparation' ]) ||
2013-07-20 09:23:55 +02:00
empty ( $signature ) || trim ( $this -> convertHTMLToText ( $signature )) == '' )
{
$disableRuler = true ;
}
2016-03-21 11:30:48 +01:00
if ( $_formData [ 'attachments' ] && $_formData [ 'filemode' ] != Vfs\Sharing :: ATTACH && ! $_autosaving )
2014-12-01 21:14:18 +01:00
{
2017-02-15 12:23:27 +01:00
$attachment_links = $this -> _getAttachmentLinks ( $_formData [ 'attachments' ], $_formData [ 'filemode' ],
2021-10-08 13:05:06 +02:00
// @TODO: $content['mimeType'] could type string/boolean. At the moment we can't strictly check them :(.
// @TODO: This needs to be fixed in compose function to get the right type from the content.
$_formData [ 'mimeType' ] == 'html' ,
2014-12-03 17:25:10 +01:00
array_unique ( array_merge (( array ) $_formData [ 'to' ], ( array ) $_formData [ 'cc' ], ( array ) $_formData [ 'bcc' ])),
$_formData [ 'expiration' ], $_formData [ 'password' ]);
2014-12-01 21:14:18 +01:00
}
2017-02-15 12:23:27 +01:00
switch ( $_formData [ 'mimeType' ])
2014-11-25 00:38:37 +01:00
{
2017-02-15 12:23:27 +01:00
case 'html' :
2022-05-23 19:36:04 +02:00
$body = $_formData [ 'body' ];
2022-05-11 18:05:54 +02:00
2021-10-07 10:14:08 +02:00
if ( ! empty ( $attachment_links ))
2014-12-01 21:14:18 +01:00
{
2022-05-11 18:05:54 +02:00
// if we have a ruler, replace it with the attachment block
static $ruler = '<hr class="ruler"' ;
if ( strpos ( $body , $ruler ) !== false )
{
$body = preg_replace ( '#' . $ruler . '[^>]*>#' , $attachment_links , $body );
}
// else place it before the signature
elseif ( strpos ( $body , '<!-- HTMLSIGBEGIN -->' ) !== false )
2017-02-15 12:23:27 +01:00
{
$body = str_replace ( '<!-- HTMLSIGBEGIN -->' , $attachment_links . '<!-- HTMLSIGBEGIN -->' , $body );
}
else
{
$body .= $attachment_links ;
}
}
2022-05-11 18:05:54 +02:00
$body = str_replace ( $ruler , '<hr' , $body ); // remove id from ruler, to not replace in cited mails
2017-02-15 12:23:27 +01:00
if ( ! empty ( $signature ))
{
$_mailObject -> setBody ( $this -> convertHTMLToText ( $body , true , true ) .
( $disableRuler ? " \r \n " : " \r \n -- \r \n " ) .
$this -> convertHTMLToText ( $signature , true , true ));
$body .= ( $disableRuler ? '<br>' : '<hr style="border:1px dotted silver; width:90%;">' ) . $signature ;
2014-12-01 21:14:18 +01:00
}
else
{
2017-02-15 12:23:27 +01:00
$_mailObject -> setBody ( $this -> convertHTMLToText ( $body , true , true ));
2014-12-01 21:14:18 +01:00
}
2017-02-15 12:23:27 +01:00
// convert URL Images to inline images - if possible
if ( ! $_autosaving ) $inline_images = Mail :: processURL2InlineImages ( $_mailObject , $body , $mail_bo );
if ( strpos ( $body , " <!-- HTMLSIGBEGIN --> " ) !== false )
{
$body = str_replace ( array ( '<!-- HTMLSIGBEGIN -->' , '<!-- HTMLSIGEND -->' ), '' , $body );
}
$_mailObject -> setHtmlBody ( $body , null , false ); // false = no automatic alternative, we called setBody()
break ;
case 'openpgp' :
2022-04-29 12:49:41 +02:00
$_mailObject -> setOpenPgpBody ( $_formData [ 'body' ] . $attachment_links );
2017-02-15 12:23:27 +01:00
break ;
default :
2018-12-20 16:57:46 +01:00
$body = $this -> convertHTMLToText ( $_formData [ 'body' ], false , false , true , true );
2014-12-01 21:14:18 +01:00
2021-10-07 10:14:08 +02:00
if ( ! empty ( $attachment_links )) $body .= $attachment_links ;
2014-12-01 21:14:18 +01:00
2017-02-15 12:23:27 +01:00
#$_mailObject->Body = $_formData['body'];
if ( ! empty ( $signature )) {
$body .= ( $disableRuler ? " \r \n " : " \r \n -- \r \n " ) .
$this -> convertHTMLToText ( $signature , true , true );
}
$_mailObject -> setBody ( $body );
2013-07-20 09:23:55 +02:00
}
// add the attachments
2013-10-08 16:23:46 +02:00
if ( is_array ( $_formData ) && isset ( $_formData [ 'attachments' ]))
2013-07-20 09:23:55 +02:00
{
2014-11-25 00:38:37 +01:00
$connection_opened = false ;
2013-07-20 09:23:55 +02:00
$tnfattachments = null ;
2013-10-08 16:23:46 +02:00
foreach (( array ) $_formData [ 'attachments' ] as $attachment ) {
2013-07-20 09:23:55 +02:00
if ( is_array ( $attachment ))
{
if ( ! empty ( $attachment [ 'uid' ]) && ! empty ( $attachment [ 'folder' ])) {
2014-01-30 12:28:20 +01:00
/* Example :
Array ([ 0 ] => Array (
[ uid ] => 21178
[ partID ] => 2
[ name ] => [ Untitled ] . pdf
[ type ] => application / pdf
[ size ] => 622379
[ folder ] => INBOX ))
*/
2014-11-25 00:38:37 +01:00
if ( ! $connection_opened )
{
2015-11-03 14:06:47 +01:00
$mail_bo -> openConnection ( $mail_bo -> profileID );
2014-11-25 00:38:37 +01:00
$connection_opened = true ;
}
2013-07-20 09:23:55 +02:00
$mail_bo -> reopen ( $attachment [ 'folder' ]);
2014-12-05 12:14:42 +01:00
switch ( strtoupper ( $attachment [ 'type' ])) {
case 'MESSAGE/RFC' :
2013-07-20 09:23:55 +02:00
case 'MESSAGE/RFC822' :
2015-11-03 14:06:47 +01:00
$rawBody = '' ;
2013-07-20 09:23:55 +02:00
if ( isset ( $attachment [ 'partID' ])) {
2015-11-03 14:06:47 +01:00
$eml = $mail_bo -> getAttachment ( $attachment [ 'uid' ], $attachment [ 'partID' ], 0 , false , true , $attachment [ 'folder' ]);
$rawBody = $eml [ 'attachment' ];
} else {
$rawBody = $mail_bo -> getMessageRawBody ( $attachment [ 'uid' ], $attachment [ 'partID' ], $attachment [ 'folder' ]);
2013-07-20 09:23:55 +02:00
}
2015-11-03 14:06:47 +01:00
$_mailObject -> addStringAttachment ( $rawBody , $attachment [ 'name' ], 'message/rfc822' );
2013-07-20 09:23:55 +02:00
break ;
default :
2014-01-30 12:28:20 +01:00
$attachmentData = $mail_bo -> getAttachment ( $attachment [ 'uid' ], $attachment [ 'partID' ], 0 , false );
2013-07-20 09:23:55 +02:00
if ( $attachmentData [ 'type' ] == 'APPLICATION/MS-TNEF' )
{
if ( ! is_array ( $tnfattachments )) $tnfattachments = $mail_bo -> decode_winmail ( $attachment [ 'uid' ], $attachment [ 'partID' ]);
foreach ( $tnfattachments as $k )
{
if ( $k [ 'name' ] == $attachment [ 'name' ])
{
$tnfpart = $mail_bo -> decode_winmail ( $attachment [ 'uid' ], $attachment [ 'partID' ], $k [ 'is_winmail' ]);
$attachmentData [ 'attachment' ] = $tnfpart [ 'attachment' ];
break ;
}
}
}
2014-12-05 12:14:42 +01:00
$_mailObject -> addStringAttachment ( $attachmentData [ 'attachment' ], $attachment [ 'name' ], $attachment [ 'type' ]);
2013-07-20 09:23:55 +02:00
break ;
}
2014-10-20 20:08:03 +02:00
}
2015-02-18 11:10:10 +01:00
// attach files not for autosaving
2016-03-21 11:30:48 +01:00
elseif ( $_formData [ 'filemode' ] == Vfs\Sharing :: ATTACH && ! $_autosaving )
2014-10-20 20:08:03 +02:00
{
2013-07-20 09:23:55 +02:00
if ( isset ( $attachment [ 'file' ]) && parse_url ( $attachment [ 'file' ], PHP_URL_SCHEME ) == 'vfs' )
{
2016-03-21 11:30:48 +01:00
Vfs :: load_wrapper ( 'vfs' );
2014-10-20 20:08:03 +02:00
$tmp_path = $attachment [ 'file' ];
}
else // non-vfs file has to be in temp_dir
{
2016-07-11 10:08:11 +02:00
$tmp_path = $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] . '/' . basename ( $attachment [ 'file' ]);
2013-07-20 09:23:55 +02:00
}
2014-12-05 12:14:42 +01:00
$_mailObject -> addAttachment (
2014-11-25 00:38:37 +01:00
$tmp_path ,
$attachment [ 'name' ],
$attachment [ 'type' ]
);
2013-07-20 09:23:55 +02:00
}
}
}
2014-11-25 00:38:37 +01:00
if ( $connection_opened ) $mail_bo -> closeConnection ();
2013-07-20 09:23:55 +02:00
}
2021-10-07 10:14:08 +02:00
return $inline_images ? ? [];
2013-07-20 09:23:55 +02:00
}
2014-09-30 14:36:46 +02:00
2014-12-01 21:14:18 +01:00
/**
* Get html or text containing links to attachments
*
* We only care about file attachments , not forwarded messages or parts
*
* @ param array $attachments
2016-03-21 11:30:48 +01:00
* @ param string $filemode Vfs\Sharing :: ( ATTACH | LINK | READONL | WRITABLE )
2014-12-01 21:14:18 +01:00
* @ param boolean $html
2014-12-03 17:25:10 +01:00
* @ param array $recipients = array ()
* @ param string $expiration = null
* @ param string $password = null
2014-12-01 21:14:18 +01:00
* @ return string might be empty if no file attachments found
*/
2017-02-15 12:23:27 +01:00
protected function _getAttachmentLinks ( array $attachments , $filemode , $html , $recipients = array (), $expiration = null , $password = null )
2014-12-01 21:14:18 +01:00
{
2016-03-21 11:30:48 +01:00
if ( $filemode == Vfs\Sharing :: ATTACH ) return '' ;
2014-12-01 21:14:18 +01:00
$links = array ();
foreach ( $attachments as $attachment )
{
$path = $attachment [ 'file' ];
if ( empty ( $path )) continue ; // we only care about file attachments, not forwarded messages or parts
if ( parse_url ( $attachment [ 'file' ], PHP_URL_SCHEME ) != 'vfs' )
{
2016-07-11 10:08:11 +02:00
$path = $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] . '/' . basename ( $path );
2014-12-01 21:14:18 +01:00
}
2014-12-03 17:25:10 +01:00
// create share
2016-03-21 11:30:48 +01:00
if ( $filemode == Vfs\Sharing :: WRITABLE || $expiration || $password )
2014-12-03 17:25:10 +01:00
{
2020-03-25 18:39:22 +01:00
$share = stylite_sharing :: create ( $path , $filemode , $attachment [ 'name' ], $recipients , $expiration , $password );
2014-12-03 17:25:10 +01:00
}
else
{
2020-03-25 03:34:04 +01:00
$share = Vfs\Sharing :: create ( '' , $path , $filemode , $attachment [ 'name' ], $recipients );
2014-12-03 17:25:10 +01:00
}
2016-03-21 11:30:48 +01:00
$link = Vfs\Sharing :: share2link ( $share );
2014-12-01 21:14:18 +01:00
2016-03-21 11:30:48 +01:00
$name = Vfs :: basename ( $attachment [ 'name' ] ? $attachment [ 'name' ] : $attachment [ 'file' ]);
2014-12-01 21:14:18 +01:00
if ( $html )
{
2016-05-03 21:17:44 +02:00
$links [] = Api\Html :: a_href ( $name , $link ) . ' ' .
2016-03-21 11:30:48 +01:00
( is_dir ( $path ) ? lang ( 'Directory' ) : Vfs :: hsize ( $attachment [ 'size' ]));
2014-12-01 21:14:18 +01:00
}
else
{
2016-03-21 11:30:48 +01:00
$links [] = $name . ' ' . Vfs :: hsize ( $attachment [ 'size' ]) . ': ' .
2014-12-03 17:25:10 +01:00
( is_dir ( $path ) ? lang ( 'Directory' ) : $link );
2014-12-01 21:14:18 +01:00
}
}
if ( ! $links )
{
return null ; // no file attachments found
}
elseif ( $html )
{
2022-05-11 18:05:54 +02:00
return self :: wrapBlockWithPreferredFont ( " <ul><li> " . implode ( " </li> \n <li> " , $links ) . " </li></ul> \n " , lang ( 'Download attachments' ), 'attachmentLinks' );
2014-12-01 21:14:18 +01:00
}
return lang ( 'Download attachments' ) . " : \n - " . implode ( " \n - " , $links ) . " \n " ;
}
2014-09-12 13:52:38 +02:00
/**
* Save compose mail as draft
*
* @ param array $content content sent from client - side
2015-02-18 11:10:10 +01:00
* @ param string $action = 'button[saveAsDraft]' 'autosaving' , 'button[saveAsDraft]' or 'button[saveAsDraftAndPrint]'
2014-09-12 13:52:38 +02:00
*/
2015-02-18 11:10:10 +01:00
public function ajax_saveAsDraft ( $content , $action = 'button[saveAsDraft]' )
2014-09-12 13:52:38 +02:00
{
2015-02-19 12:37:42 +01:00
//error_log(__METHOD__.__LINE__.array2string($content)."(, action=$action)");
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
2014-09-12 13:52:38 +02:00
$success = true ;
2014-09-30 14:36:46 +02:00
2014-09-12 13:52:38 +02:00
// check if default account is changed then we need to change profile
if ( ! empty ( $content [ 'serverID' ]) && $content [ 'serverID' ] != $this -> mail_bo -> profileID )
{
$this -> changeProfile ( $content [ 'serverID' ]);
}
2014-09-30 14:36:46 +02:00
2014-09-12 13:52:38 +02:00
$formData = array_merge ( $content , array (
2014-11-25 00:38:37 +01:00
'isDrafted' => 1 ,
'body' => $content [ 'mail_' . ( $content [ 'mimeType' ] ? 'htmltext' : 'plaintext' )],
'mimeType' => $content [ 'mimeType' ] ? 'html' : 'plain' // checkbox has only true|false value
2014-09-12 13:52:38 +02:00
));
2014-09-30 14:36:46 +02:00
2014-09-12 13:52:38 +02:00
//Saving draft procedure
try
{
$folder = $this -> mail_bo -> getDraftFolder ();
$this -> mail_bo -> reopen ( $folder );
$status = $this -> mail_bo -> getFolderStatus ( $folder );
2015-02-18 11:10:10 +01:00
if (( $messageUid = $this -> saveAsDraft ( $formData , $folder , $action )))
2014-09-12 13:52:38 +02:00
{
// saving as draft, does not mean closing the message
$messageUid = ( $messageUid === true ? $status [ 'uidnext' ] : $messageUid );
if ( is_array ( $this -> mail_bo -> getMessageHeader ( $messageUid , '' , false , false , $folder )))
{
2015-01-26 16:04:15 +01:00
$draft_id = mail_ui :: generateRowID ( $this -> mail_bo -> profileID , $folder , $messageUid );
2014-09-12 13:52:38 +02:00
if ( $content [ 'lastDrafted' ] != $draft_id && isset ( $content [ 'lastDrafted' ]))
{
$dhA = mail_ui :: splitRowID ( $content [ 'lastDrafted' ]);
$duid = $dhA [ 'msgUID' ];
$dmailbox = $dhA [ 'folder' ];
2015-03-06 10:23:13 +01:00
// beware: do not delete the original mail as found in processedmail_id
$pMuid = '' ;
2021-10-07 10:14:08 +02:00
if ( ! empty ( $content [ 'processedmail_id' ]))
2014-09-12 13:52:38 +02:00
{
2015-03-06 10:23:13 +01:00
$pMhA = mail_ui :: splitRowID ( $content [ 'processedmail_id' ]);
$pMuid = $pMhA [ 'msgUID' ];
2014-09-12 13:52:38 +02:00
}
2015-03-06 10:23:13 +01:00
//error_log(__METHOD__.__LINE__."#$pMuid#$pMuid!=$duid#".array2string($content['attachments']));
// do not delete the original message if attachments are present
if ( empty ( $pMuid ) || $pMuid != $duid || empty ( $content [ 'attachments' ]))
2014-09-12 13:52:38 +02:00
{
2015-03-06 10:23:13 +01:00
try
{
$this -> mail_bo -> deleteMessages ( $duid , $dmailbox , 'remove_immediately' );
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2015-03-06 10:23:13 +01:00
{
$msg = str_replace ( '"' , " ' " , $e -> getMessage ());
$success = false ;
error_log ( __METHOD__ . __LINE__ . $msg );
}
2016-03-10 12:15:45 +01:00
} else {
error_log ( __METHOD__ . __LINE__ . ': original message (' . $pMuid . ') has attachments and lastDrafted ID (' . $duid . ') equals the former' );
2014-09-12 13:52:38 +02:00
}
2016-03-10 12:15:45 +01:00
} else {
error_log ( __METHOD__ . __LINE__ . " No current draftID ( " . $draft_id . " ), or no lastDrafted Info ( " . $content [ 'lastDrafted' ] . " ) or the former being equal: " . array2string ( $content ) . " (, action= $action ) " );
2014-09-12 13:52:38 +02:00
}
2016-03-10 12:15:45 +01:00
} else {
error_log ( __METHOD__ . __LINE__ . ' No headerdata found for messageUID=' . $messageUid . ' in Folder:' . $folder . ':' . array2string ( $content ) . " (, action= $action ) " );
2014-09-12 13:52:38 +02:00
}
}
else
{
2016-05-03 21:17:44 +02:00
throw new Api\Exception\WrongUserinput ( lang ( " Error: Could not save Message as Draft " ));
2014-09-12 13:52:38 +02:00
}
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2014-09-12 13:52:38 +02:00
{
$msg = str_replace ( '"' , " ' " , $e -> getMessage ());
error_log ( __METHOD__ . __LINE__ . $msg );
$success = false ;
}
if ( $success ) $msg = lang ( 'Message saved successfully.' );
2014-09-30 14:36:46 +02:00
2014-09-12 13:52:38 +02:00
// Include new information to json respose, because we need them in client-side callback
$response -> data ( array (
'draftedId' => $draft_id ,
'message' => $msg ,
2014-09-22 11:07:48 +02:00
'success' => $success ,
'draftfolder' => $this -> mail_bo -> profileID . mail_ui :: $delimiter . $this -> mail_bo -> getDraftFolder ()
2014-09-12 13:52:38 +02:00
));
}
2014-09-23 10:23:10 +02:00
/**
* resolveEmailAddressList
* @ param array $_emailAddressList list of emailaddresses , may contain distributionlists
* @ return array return the list of emailaddresses with distributionlists resolved
*/
static function resolveEmailAddressList ( $_emailAddressList )
{
2022-09-12 14:50:52 +02:00
static $contacts_obs = null ;
2014-09-23 10:23:10 +02:00
$addrFromList = array ();
2014-11-25 00:38:37 +01:00
foreach (( array ) $_emailAddressList as $ak => $address )
{
2023-03-20 17:55:12 +01:00
if ( is_numeric ( $address ) && $address > 0 || preg_match ( '/ <(-?\d+)@lists.egroupware.org>$/' , $address , $matches ))
2014-09-23 10:23:10 +02:00
{
2023-03-20 17:55:12 +01:00
if ( ! isset ( $contacts_obs ))
{
$contacts_obj = new Api\Contacts ();
}
2014-09-23 10:23:10 +02:00
// List was selected, expand to addresses
unset ( $_emailAddressList [ $ak ]);
2022-09-12 14:50:52 +02:00
foreach ( $contacts_obj -> search ( '' , array ( 'n_fn' , 'n_prefix' , 'n_given' , 'n_family' , 'org_name' , 'email' , 'email_home' ),
'' , '' , '' , False , 'AND' , false ,
[ 'list' => ( int )( $matches [ 1 ] ? ? $address )]) as $email )
2014-09-23 10:23:10 +02:00
{
2022-09-12 14:50:52 +02:00
$addrFromList [] = $email [ 'email' ] ? : $email [ 'email_home' ];
2014-09-23 10:23:10 +02:00
}
}
}
2022-09-12 19:29:34 +02:00
return array_values ( array_merge (( array ) $_emailAddressList , $addrFromList ));
2014-09-23 10:23:10 +02:00
}
2014-09-30 14:36:46 +02:00
2014-09-12 13:52:38 +02:00
/**
* Save message as draft to specific folder
*
2015-02-18 11:10:10 +01:00
* @ param array $_formData content
* @ param string & $savingDestination = '' destination folder
* @ param string $action = 'button[saveAsDraft]' 'autosaving' , 'button[saveAsDraft]' or 'button[saveAsDraftAndPrint]'
2014-09-12 13:52:38 +02:00
* @ return boolean return messageUID | false due to an error
*/
2015-02-18 11:10:10 +01:00
function saveAsDraft ( $_formData , & $savingDestination = '' , $action = 'button[saveAsDraft]' )
2013-07-20 09:23:55 +02:00
{
2015-02-18 11:10:10 +01:00
//error_log(__METHOD__."(..., $savingDestination, action=$action)");
2013-07-20 09:23:55 +02:00
$mail_bo = $this -> mail_bo ;
2016-05-03 21:17:44 +02:00
$mail = new Api\Mailer ( $this -> mail_bo -> profileID );
2013-07-20 09:23:55 +02:00
// preserve the bcc and if possible the save to folder information
$this -> sessionData [ 'folder' ] = $_formData [ 'folder' ];
$this -> sessionData [ 'bcc' ] = $_formData [ 'bcc' ];
2014-11-25 00:38:37 +01:00
$this -> sessionData [ 'mailidentity' ] = $_formData [ 'mailidentity' ];
2013-11-22 14:55:09 +01:00
//$this->sessionData['stationeryID'] = $_formData['stationeryID'];
2014-01-13 16:40:34 +01:00
$this -> sessionData [ 'mailaccount' ] = $_formData [ 'mailaccount' ];
2013-10-10 18:11:26 +02:00
$this -> sessionData [ 'attachments' ] = $_formData [ 'attachments' ];
2013-11-22 14:55:09 +01:00
try
{
2016-03-28 20:51:38 +02:00
$acc = Mail\Account :: read ( $this -> sessionData [ 'mailaccount' ]);
2014-01-20 10:26:26 +01:00
//error_log(__METHOD__.__LINE__.array2string($acc));
2016-03-28 20:51:38 +02:00
$identity = Mail\Account :: read_identity ( $acc [ 'ident_id' ], true );
2013-11-22 14:55:09 +01:00
}
catch ( Exception $e )
{
$identity = array ();
}
2013-07-20 09:23:55 +02:00
$flags = '\\Seen \\Draft' ;
2015-02-18 11:10:10 +01:00
$this -> createMessage ( $mail , $_formData , $identity , $action === 'autosaving' );
2014-11-25 00:38:37 +01:00
2013-07-20 09:23:55 +02:00
// folder list as Customheader
if ( ! empty ( $this -> sessionData [ 'folder' ]))
{
$folders = implode ( '|' , array_unique ( $this -> sessionData [ 'folder' ]));
2014-11-25 00:38:37 +01:00
$mail -> addHeader ( 'X-Mailfolder' , $folders );
2013-07-20 09:23:55 +02:00
}
2014-11-25 00:38:37 +01:00
$mail -> addHeader ( 'X-Mailidentity' , $this -> sessionData [ 'mailidentity' ]);
//$mail->addHeader('X-Stationery', $this->sessionData['stationeryID']);
$mail -> addHeader ( 'X-Mailaccount' , ( int ) $this -> sessionData [ 'mailaccount' ]);
2013-07-20 09:23:55 +02:00
// decide where to save the message (default to draft folder, if we find nothing else)
// if the current folder is in draft or template folder save it there
// if it is called from printview then save it with the draft folder
2015-01-09 14:56:14 +01:00
if ( empty ( $savingDestination )) $savingDestination = $mail_bo -> getDraftFolder ();
2013-07-20 09:23:55 +02:00
if ( empty ( $this -> sessionData [ 'messageFolder' ]) && ! empty ( $this -> sessionData [ 'mailbox' ]))
{
$this -> sessionData [ 'messageFolder' ] = $this -> sessionData [ 'mailbox' ];
}
if ( ! empty ( $this -> sessionData [ 'messageFolder' ]) && ( $mail_bo -> isDraftFolder ( $this -> sessionData [ 'messageFolder' ])
|| $mail_bo -> isTemplateFolder ( $this -> sessionData [ 'messageFolder' ])))
{
$savingDestination = $this -> sessionData [ 'messageFolder' ];
//error_log(__METHOD__.__LINE__.' SavingDestination:'.$savingDestination);
}
if ( ! empty ( $_formData [ 'printit' ]) && $_formData [ 'printit' ] == 0 ) $savingDestination = $mail_bo -> getDraftFolder ();
2014-11-25 00:38:37 +01:00
// normaly Bcc is only added to recipients, but not as header visible to all recipients
$mail -> forceBccHeader ();
2013-07-20 09:23:55 +02:00
$mail_bo -> openConnection ();
if ( $mail_bo -> folderExists ( $savingDestination , true )) {
try
{
2014-11-25 00:38:37 +01:00
$messageUid = $mail_bo -> appendMessage ( $savingDestination , $mail -> getRaw (), null , $flags );
2013-07-20 09:23:55 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-07-20 09:23:55 +02:00
{
error_log ( __METHOD__ . __LINE__ . lang ( " Save of message %1 failed. Could not save message to folder %2 due to: %3 " , __METHOD__ , $savingDestination , $e -> getMessage ()));
return false ;
}
} else {
2013-10-10 18:11:26 +02:00
error_log ( __METHOD__ . __LINE__ . " -> " . lang ( " folder " ) . " " . $savingDestination . " " . lang ( " does not exist on IMAP Server. " ));
2013-07-20 09:23:55 +02:00
return false ;
}
$mail_bo -> closeConnection ();
return $messageUid ;
}
2023-07-07 10:49:58 +02:00
function send ( $_formData , int $_acc_id = null )
2013-07-20 09:23:55 +02:00
{
$mail_bo = $this -> mail_bo ;
2023-07-07 10:49:58 +02:00
$mail = new Api\Mailer ( $_acc_id ? : $mail_bo -> profileID );
2013-07-20 09:23:55 +02:00
$messageIsDraft = false ;
2014-01-13 16:40:34 +01:00
$this -> sessionData [ 'mailaccount' ] = $_formData [ 'mailaccount' ];
2014-09-23 10:23:10 +02:00
$this -> sessionData [ 'to' ] = self :: resolveEmailAddressList ( $_formData [ 'to' ]);
$this -> sessionData [ 'cc' ] = self :: resolveEmailAddressList ( $_formData [ 'cc' ]);
$this -> sessionData [ 'bcc' ] = self :: resolveEmailAddressList ( $_formData [ 'bcc' ]);
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'folder' ] = $_formData [ 'folder' ];
$this -> sessionData [ 'replyto' ] = $_formData [ 'replyto' ];
$this -> sessionData [ 'subject' ] = trim ( $_formData [ 'subject' ]);
$this -> sessionData [ 'body' ] = $_formData [ 'body' ];
$this -> sessionData [ 'priority' ] = $_formData [ 'priority' ];
2014-11-25 00:38:37 +01:00
$this -> sessionData [ 'mailidentity' ] = $_formData [ 'mailidentity' ];
2013-11-22 14:55:09 +01:00
//$this->sessionData['stationeryID'] = $_formData['stationeryID'];
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'disposition' ] = $_formData [ 'disposition' ];
$this -> sessionData [ 'mimeType' ] = $_formData [ 'mimeType' ];
$this -> sessionData [ 'to_infolog' ] = $_formData [ 'to_infolog' ];
$this -> sessionData [ 'to_tracker' ] = $_formData [ 'to_tracker' ];
2014-01-29 11:59:14 +01:00
$this -> sessionData [ 'attachments' ] = $_formData [ 'attachments' ];
2017-02-15 12:23:27 +01:00
$this -> sessionData [ 'smime_sign' ] = $_formData [ 'smime_sign' ];
$this -> sessionData [ 'smime_encrypt' ] = $_formData [ 'smime_encrypt' ];
2014-01-29 11:59:14 +01:00
2014-04-01 13:41:34 +02:00
if ( isset ( $_formData [ 'lastDrafted' ]) && ! empty ( $_formData [ 'lastDrafted' ]))
2014-01-23 12:56:34 +01:00
{
2014-04-01 13:41:34 +02:00
$this -> sessionData [ 'lastDrafted' ] = $_formData [ 'lastDrafted' ];
2014-01-23 12:56:34 +01:00
}
//error_log(__METHOD__.__LINE__.' Mode:'.$_formData['mode'].' PID:'.$_formData['processedmail_id']);
if ( isset ( $_formData [ 'mode' ]) && ! empty ( $_formData [ 'mode' ]))
{
if ( $_formData [ 'mode' ] == 'forward' && ! empty ( $_formData [ 'processedmail_id' ]))
{
$this -> sessionData [ 'forwardFlag' ] = 'forwarded' ;
$_formData [ 'processedmail_id' ] = explode ( ',' , $_formData [ 'processedmail_id' ]);
$this -> sessionData [ 'uid' ] = array ();
foreach ( $_formData [ 'processedmail_id' ] as $k => $rowid )
{
$fhA = mail_ui :: splitRowID ( $rowid );
$this -> sessionData [ 'uid' ][] = $fhA [ 'msgUID' ];
$this -> sessionData [ 'forwardedUID' ][] = $fhA [ 'msgUID' ];
if ( ! empty ( $fhA [ 'folder' ])) $this -> sessionData [ 'sourceFolder' ] = $fhA [ 'folder' ];
}
}
if ( $_formData [ 'mode' ] == 'reply' && ! empty ( $_formData [ 'processedmail_id' ]))
{
$rhA = mail_ui :: splitRowID ( $_formData [ 'processedmail_id' ]);
$this -> sessionData [ 'uid' ] = $rhA [ 'msgUID' ];
$this -> sessionData [ 'messageFolder' ] = $rhA [ 'folder' ];
}
2015-03-06 10:23:13 +01:00
if ( $_formData [ 'mode' ] == 'composefromdraft' && ! empty ( $_formData [ 'processedmail_id' ]))
{
$dhA = mail_ui :: splitRowID ( $_formData [ 'processedmail_id' ]);
$this -> sessionData [ 'uid' ] = $dhA [ 'msgUID' ];
$this -> sessionData [ 'messageFolder' ] = $dhA [ 'folder' ];
}
2014-01-23 12:56:34 +01:00
}
2013-07-20 09:23:55 +02:00
// if the body is empty, maybe someone pasted something with scripts, into the message body
// this should not happen anymore, unless you call send directly, since the check was introduced with the action command
if ( empty ( $this -> sessionData [ 'body' ]))
{
// this is to be found with the egw_unset_vars array for the _POST['body'] array
$name = '_POST' ;
$key = 'body' ;
#error_log($GLOBALS['egw_unset_vars'][$name.'['.$key.']']);
if ( isset ( $GLOBALS [ 'egw_unset_vars' ][ $name . '[' . $key . ']' ]))
{
$this -> sessionData [ 'body' ] = self :: _getCleanHTML ( $GLOBALS [ 'egw_unset_vars' ][ $name . '[' . $key . ']' ]);
$_formData [ 'body' ] = $this -> sessionData [ 'body' ];
}
#error_log($this->sessionData['body']);
}
if ( empty ( $this -> sessionData [ 'to' ]) && empty ( $this -> sessionData [ 'cc' ]) &&
empty ( $this -> sessionData [ 'bcc' ]) && empty ( $this -> sessionData [ 'folder' ])) {
$messageIsDraft = true ;
}
2013-11-22 14:55:09 +01:00
try
{
2016-03-28 20:51:38 +02:00
$identity = Mail\Account :: read_identity (( int ) $this -> sessionData [ 'mailidentity' ], true );
2013-11-22 14:55:09 +01:00
}
catch ( Exception $e )
{
2014-11-22 14:17:41 +01:00
$identity = array ();
2013-11-22 14:55:09 +01:00
}
2014-01-13 16:40:34 +01:00
//error_log($this->sessionData['mailaccount']);
2014-11-25 00:38:37 +01:00
//error_log(__METHOD__.__LINE__.':'.array2string($this->sessionData['mailidentity']).'->'.array2string($identity));
2016-09-21 15:52:50 +02:00
// create the messages and store inline images
$inline_images = $this -> createMessage ( $mail , $_formData , $identity );
2013-07-20 09:23:55 +02:00
// remember the identity
2022-04-29 12:49:41 +02:00
/** @noinspection MissingIssetImplementationInspection */
2021-10-07 10:14:08 +02:00
if ( ! empty ( $mail -> From ) && ( $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' )) $fromAddress = $mail -> From ; //$mail->FromName.($mail->FromName?' <':'').$mail->From.($mail->FromName?'>':'');
2013-07-20 09:23:55 +02:00
#print "<pre>". $mail->getMessageHeader() ."</pre><hr><br>";
#print "<pre>". $mail->getMessageBody() ."</pre><hr><br>";
#exit;
2015-01-09 14:56:14 +01:00
// check if there are folders to be used
$folderToCheck = ( array ) $this -> sessionData [ 'folder' ];
$folder = array (); //for counting only
$folderOnServerID = array ();
$folderOnMailAccount = array ();
foreach ( $folderToCheck as $k => $f )
{
$fval = $f ;
$icServerID = $_formData [ 'serverID' ]; //folders always assumed with serverID
if ( stripos ( $f , '::' ) !== false ) list ( $icServerID , $fval ) = explode ( '::' , $f , 2 );
if ( $_formData [ 'serverID' ] != $_formData [ 'mailaccount' ])
{
if ( $icServerID == $_formData [ 'serverID' ] )
{
$folder [ $fval ] = $fval ;
$folderOnServerID [] = $fval ;
}
if ( $icServerID == $_formData [ 'mailaccount' ])
{
$folder [ $fval ] = $fval ;
$folderOnMailAccount [] = $fval ;
}
}
else
{
if ( $icServerID == $_formData [ 'serverID' ] )
{
$folder [ $fval ] = $fval ;
$folderOnServerID [] = $fval ;
}
}
}
//error_log(__METHOD__.__LINE__.'#'.array2string($_formData['serverID']).'<serverID<->mailaccount>'.array2string($_formData['mailaccount']));
// serverID ($_formData['serverID']) specifies where we originally came from.
// mailaccount ($_formData['mailaccount']) specifies the mailaccount we send from and where the sent-copy should end up
// serverID : is or may be needed to mark a mail as replied/forwarded or delete the original draft.
// all other folders are tested against serverID that is carried with the foldername ID::Foldername; See above
// (we work the folder from formData into folderOnMailAccount and folderOnServerID)
// right now only folders from serverID or mailaccount should be selectable in compose form/dialog
// we use the sentFolder settings of the choosen mailaccount
// sentFolder is account specific
$changeProfileOnSentFolderNeeded = false ;
2023-07-07 10:49:58 +02:00
if ( $this -> mailPreferences [ 'sendOptions' ] === 'send_only' )
{
// no need to check for Sent folder
$sentFolder = 'none' ;
}
elseif ( $_formData [ 'serverID' ] != $_formData [ 'mailaccount' ])
2014-05-23 14:21:17 +02:00
{
$this -> changeProfile ( $_formData [ 'mailaccount' ]);
2015-01-09 14:56:14 +01:00
//error_log(__METHOD__.__LINE__.'#'.$this->mail_bo->profileID.'<->'.$mail_bo->profileID.'#');
$changeProfileOnSentFolderNeeded = true ;
// sentFolder is account specific
$sentFolder = $this -> mail_bo -> getSentFolder ();
//error_log(__METHOD__.__LINE__.' SentFolder configured:'.$sentFolder.'#');
if ( $sentFolder && $sentFolder != 'none' && ! $this -> mail_bo -> folderExists ( $sentFolder , true )) $sentFolder = false ;
2014-05-23 14:21:17 +02:00
}
2015-01-09 14:56:14 +01:00
else
{
$sentFolder = $mail_bo -> getSentFolder ();
//error_log(__METHOD__.__LINE__.' SentFolder configured:'.$sentFolder.'#');
if ( $sentFolder && $sentFolder != 'none' && ! $mail_bo -> folderExists ( $sentFolder , true )) $sentFolder = false ;
}
//error_log(__METHOD__.__LINE__.' SentFolder configured:'.$sentFolder.'#');
2014-09-11 16:10:01 +02:00
2015-01-09 14:56:14 +01:00
// we switch $this->mail_bo back to the account we used to work on
2014-05-23 14:21:17 +02:00
if ( $_formData [ 'serverID' ] != $_formData [ 'mailaccount' ])
{
$this -> changeProfile ( $_formData [ 'serverID' ]);
}
2013-07-20 09:23:55 +02:00
2015-01-09 14:56:14 +01:00
2014-05-23 14:21:17 +02:00
if ( isset ( $sentFolder ) && $sentFolder && $sentFolder != 'none' &&
2014-05-13 15:10:53 +02:00
$this -> mailPreferences [ 'sendOptions' ] != 'send_only' &&
2013-07-20 09:23:55 +02:00
$messageIsDraft == false )
{
2014-05-23 14:21:17 +02:00
if ( $sentFolder )
2013-07-20 09:23:55 +02:00
{
2015-01-09 14:56:14 +01:00
if ( $_formData [ 'serverID' ] != $_formData [ 'mailaccount' ])
{
$folderOnMailAccount [] = $sentFolder ;
}
else
{
$folderOnServerID [] = $sentFolder ;
}
$folder [ $sentFolder ] = $sentFolder ;
2013-07-20 09:23:55 +02:00
}
else
{
$this -> errorInfo = lang ( " No (valid) Send Folder set in preferences " );
}
}
else
{
2014-05-13 15:10:53 +02:00
if ((( ! isset ( $sentFolder ) || $sentFolder == false ) && $this -> mailPreferences [ 'sendOptions' ] != 'send_only' ) ||
( $this -> mailPreferences [ 'sendOptions' ] != 'send_only' &&
2013-07-20 09:23:55 +02:00
$sentFolder != 'none' )) $this -> errorInfo = lang ( " No Send Folder set in preferences " );
}
2015-01-09 14:56:14 +01:00
// draftFolder is on Server we start from
2013-07-20 09:23:55 +02:00
if ( $messageIsDraft == true ) {
2015-01-09 14:56:14 +01:00
$draftFolder = $mail_bo -> getDraftFolder ();
if ( ! empty ( $draftFolder ) && $mail_bo -> folderExists ( $draftFolder , true )) {
2013-07-20 09:23:55 +02:00
$this -> sessionData [ 'folder' ] = array ( $draftFolder );
2015-01-09 14:56:14 +01:00
$folderOnServerID [] = $draftFolder ;
$folder [ $draftFolder ] = $draftFolder ;
2013-07-20 09:23:55 +02:00
}
}
2015-01-09 14:56:14 +01:00
if ( $folderOnServerID ) $folderOnServerID = array_unique ( $folderOnServerID );
if ( $folderOnMailAccount ) $folderOnMailAccount = array_unique ( $folderOnMailAccount );
if (( $this -> mailPreferences [ 'sendOptions' ] != 'send_only' && $sentFolder != 'none' ) &&
! ( count ( $folder ) > 0 ) &&
2013-07-20 09:23:55 +02:00
! ( $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' ))
{
$this -> errorInfo = lang ( " Error: " ) . lang ( " No Folder destination supplied, and no folder to save message or other measure to store the mail (save to infolog/tracker) provided, but required. " ) . ( $this -> errorInfo ? ' ' . $this -> errorInfo : '' );
#error_log($this->errorInfo);
return false ;
}
2017-02-15 12:23:27 +01:00
// SMIME SIGN/ENCRYPTION
if ( $_formData [ 'smime_sign' ] == 'on' || $_formData [ 'smime_encrypt' ] == 'on' )
{
2018-09-17 11:08:52 +02:00
$recipients = array_merge ( $_formData [ 'to' ], ( array ) $_formData [ 'cc' ], ( array ) $_formData [ 'bcc' ]);
2017-02-15 12:23:27 +01:00
try {
if ( $_formData [ 'smime_sign' ] == 'on' )
{
2017-08-28 16:14:56 +02:00
if ( $_formData [ 'smime_passphrase' ] != '' ) {
Api\Cache :: setSession (
'mail' ,
'smime_passphrase' ,
$_formData [ 'smime_passphrase' ],
2022-04-26 18:46:23 +02:00
( int )( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'smime_pass_exp' ] ? ? 10 ) * 60
2017-08-28 16:14:56 +02:00
);
}
2017-03-09 17:42:41 +01:00
$smime_success = $this -> _encrypt (
$mail ,
2017-02-15 12:23:27 +01:00
$_formData [ 'smime_encrypt' ] == 'on' ? Mail\Smime :: TYPE_SIGN_ENCRYPT : Mail\Smime :: TYPE_SIGN ,
2018-09-17 11:08:52 +02:00
Mail :: stripRFC822Addresses ( $recipients ),
2017-02-15 12:23:27 +01:00
$identity [ 'ident_email' ],
$_formData [ 'smime_passphrase' ]
);
2017-03-09 17:42:41 +01:00
if ( ! $smime_success )
2017-02-15 12:23:27 +01:00
{
$response = Api\Json\Response :: get ();
2017-07-10 12:57:14 +02:00
$this -> errorInfo = $_formData [ 'smime_passphrase' ] == '' ?
lang ( 'You need to enter your S/MIME passphrase to send this message.' ) :
lang ( 'The entered passphrase is not correct! Please try again.' );
$response -> call ( 'app.mail.smimePassDialog' , $this -> errorInfo );
2017-02-15 12:23:27 +01:00
return false ;
}
}
elseif ( $_formData [ 'smime_sign' ] == 'off' && $_formData [ 'smime_encrypt' ] == 'on' )
{
2017-03-09 17:42:41 +01:00
$smime_success = $this -> _encrypt (
$mail ,
2017-02-15 12:23:27 +01:00
Mail\Smime :: TYPE_ENCRYPT ,
2018-09-17 11:08:52 +02:00
Mail :: stripRFC822Addresses ( $recipients ),
2017-02-15 12:23:27 +01:00
$identity [ 'ident_email' ]
);
}
}
catch ( Exception $ex )
{
2017-03-09 17:42:41 +01:00
$response = Api\Json\Response :: get ();
2017-07-11 11:43:53 +02:00
$this -> errorInfo = $ex -> getMessage ();
2017-03-09 17:42:41 +01:00
return false ;
2017-02-15 12:23:27 +01:00
}
}
2013-07-20 09:23:55 +02:00
// set a higher timeout for big messages
@ set_time_limit ( 120 );
//$mail->SMTPDebug = 10;
//error_log("Folder:".count(array($this->sessionData['folder']))."To:".count((array)$this->sessionData['to'])."CC:". count((array)$this->sessionData['cc']) ."bcc:".count((array)$this->sessionData['bcc']));
if ( count (( array ) $this -> sessionData [ 'to' ]) > 0 || count (( array ) $this -> sessionData [ 'cc' ]) > 0 || count (( array ) $this -> sessionData [ 'bcc' ]) > 0 ) {
try {
2018-10-08 11:30:20 +02:00
// do no close the session before sending, if we have to store the send text for infolog or other integration in the session
if ( ! ( $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' || $_formData [ 'to_calendar' ] == 'on' ))
{
$GLOBALS [ 'egw' ] -> session -> commit_session ();
}
2014-11-25 12:32:25 +01:00
$mail -> send ();
2013-07-20 09:23:55 +02:00
}
2014-11-25 00:38:37 +01:00
catch ( Exception $e ) {
_egw_log_exception ( $e );
2015-12-15 17:13:01 +01:00
//if( $e->details ) error_log(__METHOD__.__LINE__.array2string($e->details));
$this -> errorInfo = $e -> getMessage () . ( $e -> details ? '<br/>' . $e -> details : '' );
2013-07-20 09:23:55 +02:00
return false ;
}
} else {
if ( count ( array ( $this -> sessionData [ 'folder' ])) > 0 && ! empty ( $this -> sessionData [ 'folder' ])) {
//error_log(__METHOD__.__LINE__."Folders:".print_r($this->sessionData['folder'],true));
} else {
$this -> errorInfo = lang ( " Error: " ) . lang ( " No Address TO/CC/BCC supplied, and no folder to save message to provided. " );
//error_log(__METHOD__.__LINE__.$this->errorInfo);
return false ;
}
}
2014-02-03 12:29:12 +01:00
//error_log(__METHOD__.__LINE__."Mail Sent.!");
//error_log(__METHOD__.__LINE__."Number of Folders to move copy the message to:".count($folder));
//error_log(__METHOD__.__LINE__.array2string($folder));
2013-07-20 09:23:55 +02:00
if (( count ( $folder ) > 0 ) || ( isset ( $this -> sessionData [ 'uid' ]) && isset ( $this -> sessionData [ 'messageFolder' ]))
|| ( isset ( $this -> sessionData [ 'forwardFlag' ]) && isset ( $this -> sessionData [ 'sourceFolder' ]))) {
$mail_bo = $this -> mail_bo ;
$mail_bo -> openConnection ();
//$mail_bo->reopen($this->sessionData['messageFolder']);
#error_log("(re)opened Connection");
}
// if copying mail to folder, or saving mail to infolog, we need to gather the needed information
2013-10-16 13:25:46 +02:00
if ( count ( $folder ) > 0 || $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' ) {
2014-09-23 10:23:10 +02:00
//error_log(__METHOD__.__LINE__.array2string($this->sessionData['bcc']));
2014-11-25 00:38:37 +01:00
// normaly Bcc is only added to recipients, but not as header visible to all recipients
$mail -> forceBccHeader ();
2013-07-20 09:23:55 +02:00
}
// copying mail to folder
if ( count ( $folder ) > 0 )
{
2015-01-09 14:56:14 +01:00
foreach ( $folderOnServerID as $folderName ) {
2013-07-20 09:23:55 +02:00
if ( is_array ( $folderName )) $folderName = array_shift ( $folderName ); // should not happen at all
2015-01-09 14:56:14 +01:00
//error_log(__METHOD__.__LINE__." attempt to save message to:".array2string($folderName));
2014-05-23 14:21:17 +02:00
// if $_formData['serverID']!=$_formData['mailaccount'] skip copying to sentfolder on serverID
2015-01-09 14:56:14 +01:00
// if($_formData['serverID']!=$_formData['mailaccount'] && $folderName==$sentFolder && $changeProfileOnSentFolderNeeded) continue;
2013-07-20 09:23:55 +02:00
if ( $mail_bo -> folderExists ( $folderName , true )) {
2015-01-09 14:56:14 +01:00
if ( $mail_bo -> isSentFolder ( $folderName )) {
$flags = '\\Seen' ;
} elseif ( $mail_bo -> isDraftFolder ( $folderName )) {
$flags = '\\Draft' ;
} else {
$flags = '\\Seen' ;
}
#$mailHeader=explode('From:',$mail->getMessageHeader());
#$mailHeader[0].$mail->AddrAppend("Bcc",$mailAddr).'From:'.$mailHeader[1],
//error_log(__METHOD__.__LINE__." Cleared FolderTests; Save Message to:".array2string($folderName));
//$mail_bo->reopen($folderName);
2013-07-20 09:23:55 +02:00
try
{
2014-02-03 12:29:12 +01:00
//error_log(__METHOD__.__LINE__.array2string($folderName));
2014-11-25 00:38:37 +01:00
$mail_bo -> appendMessage ( $folderName , $mail -> getRaw (), null , $flags );
2013-07-20 09:23:55 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2013-07-20 09:23:55 +02:00
{
error_log ( __METHOD__ . __LINE__ . '->' . lang ( " Import of message %1 failed. Could not save message to folder %2 due to: %3 " , $this -> sessionData [ 'subject' ], $folderName , $e -> getMessage ()));
}
}
else
{
error_log ( __METHOD__ . __LINE__ . '->' . lang ( " Import of message %1 failed. Destination Folder %2 does not exist. " , $this -> sessionData [ 'subject' ], $folderName ));
}
}
2014-05-23 14:21:17 +02:00
// if we choose to send from a differing profile
2015-01-09 14:56:14 +01:00
if ( $folderOnMailAccount ) $this -> changeProfile ( $_formData [ 'mailaccount' ]);
foreach ( $folderOnMailAccount as $folderName ) {
if ( is_array ( $folderName )) $folderName = array_shift ( $folderName ); // should not happen at all
//error_log(__METHOD__.__LINE__." attempt to save message to:".array2string($folderName));
// if $_formData['serverID']!=$_formData['mailaccount'] skip copying to sentfolder on serverID
// if($_formData['serverID']!=$_formData['mailaccount'] && $folderName==$sentFolder && $changeProfileOnSentFolderNeeded) continue;
if ( $this -> mail_bo -> folderExists ( $folderName , true )) {
if ( $this -> mail_bo -> isSentFolder ( $folderName )) {
$flags = '\\Seen' ;
} elseif ( $this -> mail_bo -> isDraftFolder ( $folderName )) {
$flags = '\\Draft' ;
} else {
$flags = '\\Seen' ;
}
#$mailHeader=explode('From:',$mail->getMessageHeader());
#$mailHeader[0].$mail->AddrAppend("Bcc",$mailAddr).'From:'.$mailHeader[1],
//error_log(__METHOD__.__LINE__." Cleared FolderTests; Save Message to:".array2string($folderName));
//$mail_bo->reopen($folderName);
2014-05-23 14:21:17 +02:00
try
{
//error_log(__METHOD__.__LINE__.array2string($folderName));
2015-01-09 14:56:14 +01:00
$this -> mail_bo -> appendMessage ( $folderName , $mail -> getRaw (), null , $flags );
2014-05-23 14:21:17 +02:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception\WrongUserinput $e )
2014-05-23 14:21:17 +02:00
{
error_log ( __METHOD__ . __LINE__ . '->' . lang ( " Import of message %1 failed. Could not save message to folder %2 due to: %3 " , $this -> sessionData [ 'subject' ], $folderName , $e -> getMessage ()));
}
2015-01-09 14:56:14 +01:00
}
else
{
error_log ( __METHOD__ . __LINE__ . '->' . lang ( " Import of message %1 failed. Destination Folder %2 does not exist. " , $this -> sessionData [ 'subject' ], $folderName ));
2014-05-23 14:21:17 +02:00
}
}
2015-01-09 14:56:14 +01:00
if ( $folderOnMailAccount ) $this -> changeProfile ( $_formData [ 'serverID' ]);
2014-05-23 14:21:17 +02:00
2013-07-20 09:23:55 +02:00
//$mail_bo->closeConnection();
}
// handle previous drafted versions of that mail
$lastDrafted = false ;
if ( isset ( $this -> sessionData [ 'lastDrafted' ]))
{
2014-01-23 12:56:34 +01:00
$lastDrafted = array ();
2014-04-01 13:41:34 +02:00
$dhA = mail_ui :: splitRowID ( $this -> sessionData [ 'lastDrafted' ]);
2014-01-23 12:56:34 +01:00
$lastDrafted [ 'uid' ] = $dhA [ 'msgUID' ];
$lastDrafted [ 'folder' ] = $dhA [ 'folder' ];
2013-07-20 09:23:55 +02:00
if ( isset ( $lastDrafted [ 'uid' ]) && ! empty ( $lastDrafted [ 'uid' ])) $lastDrafted [ 'uid' ] = trim ( $lastDrafted [ 'uid' ]);
2014-01-23 12:56:34 +01:00
// manually drafted, do not delete
2015-03-06 10:23:13 +01:00
// will be handled later on IF mode was $_formData['mode']=='composefromdraft'
2021-10-07 10:14:08 +02:00
if ( isset ( $lastDrafted [ 'uid' ]) && ( empty ( $lastDrafted [ 'uid' ]) || $lastDrafted [ 'uid' ] == ( $this -> sessionData [ 'uid' ] ? ? null ))) $lastDrafted = false ;
2013-07-20 09:23:55 +02:00
//error_log(__METHOD__.__LINE__.array2string($lastDrafted));
}
2014-01-23 12:56:34 +01:00
if ( $lastDrafted && is_array ( $lastDrafted ) && $mail_bo -> isDraftFolder ( $lastDrafted [ 'folder' ]))
{
try
{
2021-10-07 10:14:08 +02:00
if ( $this -> sessionData [ 'lastDrafted' ] != ( $this -> sessionData [ 'uid' ] ? ? null ) || ! ( $_formData [ 'mode' ] == 'composefromdraft' &&
2015-09-11 15:45:45 +02:00
( $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' || $_formData [ 'to_calendar' ] == 'on' ) && $this -> sessionData [ 'attachments' ]))
{
//error_log(__METHOD__.__LINE__."#".$lastDrafted['uid'].'#'.$lastDrafted['folder'].array2string($_formData));
//error_log(__METHOD__.__LINE__."#".array2string($_formData));
//error_log(__METHOD__.__LINE__."#".array2string($this->sessionData));
$mail_bo -> deleteMessages ( $lastDrafted [ 'uid' ], $lastDrafted [ 'folder' ], 'remove_immediately' );
}
2014-01-23 12:56:34 +01:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2014-01-23 12:56:34 +01:00
{
2014-11-20 18:53:52 +01:00
//error_log(__METHOD__.__LINE__." ". str_replace('"',"'",$e->getMessage()));
unset ( $e );
2014-01-23 12:56:34 +01:00
}
}
2013-07-20 09:23:55 +02:00
unset ( $this -> sessionData [ 'lastDrafted' ]);
//error_log("handling draft messages, flagging and such");
if (( isset ( $this -> sessionData [ 'uid' ]) && isset ( $this -> sessionData [ 'messageFolder' ]))
|| ( isset ( $this -> sessionData [ 'forwardFlag' ]) && isset ( $this -> sessionData [ 'sourceFolder' ]))) {
// mark message as answered
$mail_bo -> openConnection ();
2022-04-26 18:46:23 +02:00
$mail_bo -> reopen ( $this -> sessionData [ 'messageFolder' ] ? ? $this -> sessionData [ 'sourceFolder' ]);
2013-07-20 09:23:55 +02:00
// if the draft folder is a starting part of the messages folder, the draft message will be deleted after the send
// unless your templatefolder is a subfolder of your draftfolder, and the message is in there
2022-04-26 18:46:23 +02:00
if ( ! empty ( $this -> sessionData [ 'messageFolder' ]) && $mail_bo -> isDraftFolder ( $this -> sessionData [ 'messageFolder' ]) && ! $mail_bo -> isTemplateFolder ( $this -> sessionData [ 'messageFolder' ]))
2013-07-20 09:23:55 +02:00
{
2015-03-06 10:23:13 +01:00
try // message may be deleted already, as it maybe done by autosave
{
2015-09-11 15:45:45 +02:00
if ( $_formData [ 'mode' ] == 'composefromdraft' &&
! (( $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' || $_formData [ 'to_calendar' ] == 'on' ) && $this -> sessionData [ 'attachments' ]))
{
//error_log(__METHOD__.__LINE__."#".$this->sessionData['uid'].'#'.$this->sessionData['messageFolder']);
2018-09-20 16:07:36 +02:00
$mail_bo -> deleteMessages ( array ( $this -> sessionData [ 'uid' ]), $this -> sessionData [ 'messageFolder' ], 'remove_immediately' );
2015-09-11 15:45:45 +02:00
}
2015-03-06 10:23:13 +01:00
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2015-03-06 10:23:13 +01:00
{
//error_log(__METHOD__.__LINE__." ". str_replace('"',"'",$e->getMessage()));
unset ( $e );
}
2013-07-20 09:23:55 +02:00
} else {
2022-04-26 18:46:23 +02:00
$mail_bo -> flagMessages ( " answered " , $this -> sessionData [ 'uid' ], $this -> sessionData [ 'messageFolder' ] ? ? $this -> sessionData [ 'sourceFolder' ]);
2014-01-23 12:56:34 +01:00
//error_log(__METHOD__.__LINE__.array2string(array_keys($this->sessionData)).':'.array2string($this->sessionData['forwardedUID']).' F:'.$this->sessionData['sourceFolder']);
2013-07-20 09:23:55 +02:00
if ( array_key_exists ( 'forwardFlag' , $this -> sessionData ) && $this -> sessionData [ 'forwardFlag' ] == 'forwarded' )
{
2015-03-06 10:23:13 +01:00
try
{
//error_log(__METHOD__.__LINE__.':'.array2string($this->sessionData['forwardedUID']).' F:'.$this->sessionData['sourceFolder']);
$mail_bo -> flagMessages ( " forwarded " , $this -> sessionData [ 'forwardedUID' ], $this -> sessionData [ 'sourceFolder' ]);
}
2016-05-03 21:17:44 +02:00
catch ( Api\Exception $e )
2015-03-06 10:23:13 +01:00
{
//error_log(__METHOD__.__LINE__." ". str_replace('"',"'",$e->getMessage()));
unset ( $e );
}
2013-07-20 09:23:55 +02:00
}
}
//$mail_bo->closeConnection();
}
if ( $mail_bo ) $mail_bo -> closeConnection ();
//error_log("performing Infolog Stuff");
//error_log(print_r($this->sessionData['to'],true));
//error_log(print_r($this->sessionData['cc'],true));
//error_log(print_r($this->sessionData['bcc'],true));
if ( is_array ( $this -> sessionData [ 'to' ]))
{
$mailaddresses [ 'to' ] = $this -> sessionData [ 'to' ];
}
else
{
$mailaddresses = array ();
}
if ( is_array ( $this -> sessionData [ 'cc' ])) $mailaddresses [ 'cc' ] = $this -> sessionData [ 'cc' ];
if ( is_array ( $this -> sessionData [ 'bcc' ])) $mailaddresses [ 'bcc' ] = $this -> sessionData [ 'bcc' ];
2021-10-07 10:14:08 +02:00
if ( ! empty ( $mailaddresses ) && ! empty ( $fromAddress )) $mailaddresses [ 'from' ] = Mail\Html :: decodeMailHeader ( $fromAddress );
2013-07-20 09:23:55 +02:00
2015-04-15 17:55:18 +02:00
if ( $_formData [ 'to_infolog' ] == 'on' || $_formData [ 'to_tracker' ] == 'on' || $_formData [ 'to_calendar' ] == 'on' )
{
2016-09-21 15:52:50 +02:00
$this -> sessionData [ 'attachments' ] = array_merge (( array ) $this -> sessionData [ 'attachments' ], ( array ) $inline_images );
2015-04-15 17:55:18 +02:00
foreach ( array ( 'to_infolog' , 'to_tracker' , 'to_calendar' ) as $app_key )
{
2023-02-14 19:46:42 +01:00
list (, $entryid ) = explode ( " : " , $_formData [ 'to_integrate_ids' ][ 0 ]) ? ? null ;
2015-04-15 17:55:18 +02:00
if ( $_formData [ $app_key ] == 'on' )
{
$app_name = substr ( $app_key , 3 );
// Get registered hook data of the app called for integration
2016-05-03 21:17:44 +02:00
$hook = Api\Hooks :: single ( array ( 'location' => 'mail_import' ), $app_name );
2015-04-16 09:03:53 +02:00
// store mail / eml in temp. file to not have to download it from mail-server again
$eml = tempnam ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ], 'mail_integrate' );
$eml_fp = fopen ( $eml , 'w' );
stream_copy_to_stream ( $mail -> getRaw (), $eml_fp );
fclose ( $eml_fp );
2016-08-18 17:30:44 +02:00
$target = array (
2015-04-15 17:55:18 +02:00
'menuaction' => $hook [ 'menuaction' ],
2016-05-03 21:17:44 +02:00
'egw_data' => Link :: set_data ( null , 'mail_integration::integrate' , array (
2015-04-15 17:55:18 +02:00
$mailaddresses ,
$this -> sessionData [ 'subject' ],
$this -> convertHTMLToText ( $this -> sessionData [ 'body' ]),
$this -> sessionData [ 'attachments' ],
false , // date
2015-04-17 11:39:22 +02:00
$eml ,
$_formData [ 'serverID' ]), true ),
'app' => $app_name
2016-08-18 17:30:44 +02:00
);
if ( $entryid ) $target [ 'entry_id' ] = $entryid ;
// Open the app called for integration in a popup
// and store the mail raw data as egw_data, in order to
// be stored from registered app method later
Framework :: popup ( Egw :: link ( '/index.php' , $target ), '_blank' , $hook [ 'popup' ]);
2015-04-15 17:55:18 +02:00
}
}
}
2015-04-17 16:40:43 +02:00
// only clean up temp-files, if we dont need them for mail_integration::integrate
elseif ( is_array ( $this -> sessionData [ 'attachments' ]))
{
2014-11-25 00:38:37 +01:00
foreach ( $this -> sessionData [ 'attachments' ] as $value ) {
2013-07-20 09:23:55 +02:00
if ( ! empty ( $value [ 'file' ]) && parse_url ( $value [ 'file' ], PHP_URL_SCHEME ) != 'vfs' ) { // happens when forwarding mails
2014-12-05 12:25:09 +01:00
unlink ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] . '/' . $value [ 'file' ]);
2013-07-20 09:23:55 +02:00
}
}
}
$this -> sessionData = '' ;
return true ;
}
2013-10-10 13:44:01 +02:00
/**
* setDefaults , sets some defaults
*
* @ param array $content
* @ return array - the input , enriched with some not set attributes
*/
2013-10-10 16:56:30 +02:00
function setDefaults ( $content = array ())
2013-07-20 09:23:55 +02:00
{
2015-03-18 17:31:30 +01:00
// if there's not already an identity selected for current account
if ( empty ( $content [ 'mailidentity' ]))
2014-05-02 12:33:54 +02:00
{
2015-03-18 17:31:30 +01:00
// check if there a preference / previous selection of identity for current account
if ( ! empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'LastSignatureIDUsed' ]))
2014-05-02 12:33:54 +02:00
{
2015-03-18 17:31:30 +01:00
$sigPref = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ][ 'LastSignatureIDUsed' ];
if ( ! empty ( $sigPref [ $this -> mail_bo -> profileID ]) && $sigPref [ $this -> mail_bo -> profileID ] > 0 )
2014-05-02 12:33:54 +02:00
{
2015-03-18 17:31:30 +01:00
$content [ 'mailidentity' ] = $sigPref [ $this -> mail_bo -> profileID ];
2014-05-02 12:33:54 +02:00
}
2015-03-18 17:31:30 +01:00
}
// if we have no preference search for first identity with non-empty signature
if ( empty ( $content [ 'mailidentity' ]))
{
$default_identity = null ;
2016-03-28 20:51:38 +02:00
foreach ( Mail\Account :: identities ( $this -> mail_bo -> profileID , true , 'params' ) as $identity )
2014-05-02 12:33:54 +02:00
{
2015-03-18 17:31:30 +01:00
if ( ! isset ( $default_identity )) $default_identity = $identity [ 'ident_id' ];
if ( ! empty ( $identity [ 'ident_signature' ]))
{
$content [ 'mailidentity' ] = $identity [ 'ident_id' ];
break ;
}
2014-05-02 12:33:54 +02:00
}
}
2015-03-18 17:31:30 +01:00
if ( empty ( $content [ 'mailidentity' ])) $content [ 'mailidentity' ] = $default_identity ;
2014-05-02 12:33:54 +02:00
}
2013-10-10 16:56:30 +02:00
if ( ! isset ( $content [ 'mimeType' ]) || empty ( $content [ 'mimeType' ]))
{
$content [ 'mimeType' ] = 'html' ;
2014-05-13 15:10:53 +02:00
if ( ! empty ( $this -> mailPreferences [ 'composeOptions' ]) && $this -> mailPreferences [ 'composeOptions' ] == " text " ) $content [ 'mimeType' ] = 'plain' ;
2013-10-10 16:56:30 +02:00
}
2013-10-02 16:50:24 +02:00
return $content ;
2013-07-20 09:23:55 +02:00
}
function stripSlashes ( $_string )
{
2021-03-21 18:27:09 +01:00
if ( function_exists ( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc ()) {
2013-07-20 09:23:55 +02:00
return stripslashes ( $_string );
} else {
return $_string ;
}
}
2015-01-19 13:12:18 +01:00
/**
* Callback function to search mail folders
*
2022-08-22 12:05:51 +02:00
* New et2 - select ( -* ) widget sends query string and option array as first to parameters
*
2015-01-19 13:12:18 +01:00
* @ param int $_searchStringLength
* @ param boolean $_returnList
* @ param int $_mailaccountToSearch
2015-01-26 16:04:15 +01:00
* @ param boolean $_noPrefixId = false , if set to true folders name does not get prefixed by account id
2015-01-19 13:12:18 +01:00
* @ return type
*/
function ajax_searchFolder ( $_searchStringLength = 2 , $_returnList = false , $_mailaccountToSearch = null , $_noPrefixId = false ) {
2015-01-09 14:56:14 +01:00
//error_log(__METHOD__.__LINE__.':'.array2string($_REQUEST));
2014-11-20 18:53:52 +01:00
static $useCacheIfPossible = null ;
2013-07-20 15:10:17 +02:00
if ( is_null ( $useCacheIfPossible )) $useCacheIfPossible = true ;
2022-08-22 12:05:51 +02:00
// new et2-select(-*) widget sends query string and option array as first to parameters
if ( ! is_int ( $_searchStringLength )) $_searchStringLength = 2 ;
if ( ! is_bool ( $_returnList )) $_returnList = false ;
2013-07-20 15:10:17 +02:00
$_searchString = trim ( $_REQUEST [ 'query' ]);
2013-07-20 11:27:37 +02:00
$results = array ();
2015-01-09 14:56:14 +01:00
$rememberServerID = $this -> mail_bo -> icServer -> ImapServerId ;
if ( is_null ( $_mailaccountToSearch ) && ! empty ( $_REQUEST [ 'mailaccount' ])) $_mailaccountToSearch = $_REQUEST [ 'mailaccount' ];
if ( empty ( $_mailaccountToSearch )) $_mailaccountToSearch = $this -> mail_bo -> icServer -> ImapServerId ;
if ( $this -> mail_bo -> icServer && $_mailaccountToSearch && $this -> mail_bo -> icServer -> ImapServerId != $_mailaccountToSearch )
{
$this -> changeProfile ( $_mailaccountToSearch );
}
2013-09-02 17:15:35 +02:00
if ( strlen ( $_searchString ) >= $_searchStringLength && isset ( $this -> mail_bo -> icServer ))
2013-07-20 15:10:17 +02:00
{
//error_log(__METHOD__.__LINE__.':'.$this->mail_bo->icServer->ImapServerId);
2013-11-22 14:55:09 +01:00
$this -> mail_bo -> openConnection ( $this -> mail_bo -> icServer -> ImapServerId );
2013-07-20 15:10:17 +02:00
//error_log(__METHOD__.__LINE__.array2string($_searchString).'<->'.$searchString);
$folderObjects = $this -> mail_bo -> getFolderObjects ( true , false , true , $useCacheIfPossible );
if ( count ( $folderObjects ) <= 1 ) {
$useCacheIfPossible = false ;
}
else
{
$useCacheIfPossible = true ;
}
2016-05-03 21:17:44 +02:00
$searchString = Api\Translation :: convert ( $_searchString , Mail :: $displayCharset , 'UTF7-IMAP' );
2013-07-20 15:10:17 +02:00
foreach ( $folderObjects as $k => $fA )
{
2013-07-20 17:15:29 +02:00
//error_log(__METHOD__.__LINE__.$_searchString.'/'.$searchString.' in '.$k.'->'.$fA->displayName);
2013-07-20 15:10:17 +02:00
$f = false ;
2015-01-19 13:12:18 +01:00
$key = $_noPrefixId ? $k : $_mailaccountToSearch . '::' . $k ;
2013-09-02 17:15:35 +02:00
if ( $_searchStringLength <= 0 )
{
$f = true ;
2015-01-09 14:56:14 +01:00
$results [] = array ( 'id' => $key , 'label' => htmlspecialchars ( $fA -> displayName ));
2013-09-02 17:15:35 +02:00
}
if ( $f == false && stripos ( $fA -> displayName , $_searchString ) !== false )
2013-07-20 15:10:17 +02:00
{
$f = true ;
2015-01-09 14:56:14 +01:00
$results [] = array ( 'id' => $key , 'label' => htmlspecialchars ( $fA -> displayName ));
2013-07-20 15:10:17 +02:00
}
if ( $f == false && stripos ( $k , $searchString ) !== false )
{
2015-01-09 14:56:14 +01:00
$results [] = array ( 'id' => $key , 'label' => htmlspecialchars ( $fA -> displayName ));
2013-07-20 15:10:17 +02:00
}
}
}
2015-01-09 14:56:14 +01:00
if ( $this -> mail_bo -> icServer && $rememberServerID != $this -> mail_bo -> icServer -> ImapServerId )
{
$this -> changeProfile ( $rememberServerID );
}
2013-07-20 15:10:17 +02:00
//error_log(__METHOD__.__LINE__.' IcServer:'.$this->mail_bo->icServer->ImapServerId.':'.array2string($results));
2013-09-02 17:15:35 +02:00
if ( $_returnList )
{
2014-10-23 13:28:36 +02:00
foreach (( array ) $results as $k => $_result )
{
$rL [ $_result [ 'id' ]] = $_result [ 'label' ];
}
2013-09-02 17:15:35 +02:00
return $rL ;
}
2014-02-24 20:12:37 +01:00
// switch regular JSON response handling off
2016-05-03 21:17:44 +02:00
Api\Json\Request :: isJSONRequest ( false );
2014-02-24 20:12:37 +01:00
2013-07-20 11:27:37 +02:00
header ( 'Content-Type: application/json; charset=utf-8' );
2013-10-08 16:23:46 +02:00
//error_log(__METHOD__.__LINE__);
2013-07-20 11:27:37 +02:00
echo json_encode ( $results );
2016-05-03 21:17:44 +02:00
exit ();
2013-07-20 11:27:37 +02:00
}
2023-07-27 11:07:49 +02:00
public static function ajax_searchAddress ( $_searchStringLength = 2 )
{
2013-08-21 12:47:20 +02:00
//error_log(__METHOD__. "request from seachAddress " . $_REQUEST['query']);
2022-08-22 12:05:51 +02:00
if ( ! is_int ( $_searchStringLength )) $_searchStringLength = 2 ;
2013-07-20 11:27:37 +02:00
$_searchString = trim ( $_REQUEST [ 'query' ]);
2013-11-21 23:29:57 +01:00
$include_lists = ( boolean ) $_REQUEST [ 'include_lists' ];
2016-03-29 10:46:09 +02:00
$contacts_obj = new Api\Contacts ();
2017-03-07 18:18:06 +01:00
$results = array ();
2021-03-03 13:07:05 +01:00
$mailPrefs = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'mail' ];
$contactLabelPref = ! is_array ( $mailPrefs [ 'contactLabel' ]) && ! empty ( $mailPrefs [ 'contactLabel' ]) ?
explode ( ',' , $mailPrefs [ 'contactLabel' ]) : $mailPrefs [ 'contactLabel' ];
2017-03-07 18:18:06 +01:00
2020-12-14 17:34:17 +01:00
// Add some matching mailing lists, and some groups, limited by config
2017-03-07 18:18:06 +01:00
if ( $include_lists )
{
2018-02-16 19:19:47 +01:00
$results += static :: get_lists ( $_searchString , $contacts_obj );
2017-03-07 18:18:06 +01:00
}
2014-03-03 12:59:18 +01:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'addressbook' ] && strlen ( $_searchString ) >= $_searchStringLength )
{
2013-07-20 11:27:37 +02:00
//error_log(__METHOD__.__LINE__.array2string($_searchString));
2017-12-01 14:58:44 +01:00
$showAccounts = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'addressbook' ][ 'hide_accounts' ] !== '1' ;
2014-03-03 12:59:18 +01:00
$search = explode ( ' ' , $_searchString );
foreach ( $search as $k => $v )
{
if ( mb_strlen ( $v ) < 3 ) unset ( $search [ $k ]);
}
$search_str = implode ( ' +' , $search ); // tell contacts/so_sql to AND search patterns
//error_log(__METHOD__.__LINE__.$_searchString);
$filter = $showAccounts ? array () : array ( 'account_id' => null );
2023-05-08 15:13:00 +02:00
$filter [ 'cols_to_search' ] = array ( 'n_prefix' , 'n_given' , 'n_family' , 'org_name' , 'email' , 'email_home' , 'contact_id' , 'search_cfs' => false );
2023-07-27 11:07:49 +02:00
$cols = array ( 'n_fn' , 'n_prefix' , 'n_given' , 'n_family' , 'org_name' , 'email' , 'email_home' , 'contact_id' , 'modified' , 'files' );
2016-03-29 10:46:09 +02:00
$contacts = $contacts_obj -> search ( $search_str , $cols , 'n_fn' , '' , '%' , false , 'OR' , array ( 0 , 100 ), $filter );
2019-02-01 11:13:43 +01:00
$cfs_type_email = Api\Storage\Customfields :: get_email_cfs ( 'addressbook' );
2014-03-03 12:59:18 +01:00
// additionally search the accounts, if the contact storage is not the account storage
2016-03-29 10:46:09 +02:00
if ( $showAccounts && $contacts_obj -> so_accounts )
2014-03-03 12:59:18 +01:00
{
$filter [ 'owner' ] = 0 ;
2016-03-29 10:46:09 +02:00
$accounts = $contacts_obj -> search ( $search_str , $cols , 'n_fn' , '' , '%' , false , 'OR' , array ( 0 , 100 ), $filter );
2014-03-03 12:59:18 +01:00
if ( $contacts && $accounts )
2013-07-20 11:27:37 +02:00
{
2014-03-03 12:59:18 +01:00
$contacts = array_merge ( $contacts , $accounts );
usort ( $contacts , function ( $a , $b )
2013-07-20 11:27:37 +02:00
{
2014-03-03 12:59:18 +01:00
return strcasecmp ( $a [ 'n_fn' ], $b [ 'n_fn' ]);
});
}
elseif ( $accounts )
{
$contacts =& $accounts ;
2013-07-20 11:27:37 +02:00
}
2014-03-03 12:59:18 +01:00
unset ( $accounts );
2013-07-20 11:27:37 +02:00
}
}
2017-03-09 17:42:41 +01:00
2020-12-02 09:07:09 +01:00
if ( is_array ( $contacts ))
{
2023-07-27 11:07:49 +02:00
$cf_emails = [];
// if we have email type custom-fields, query them all in one query
if ( ! empty ( $cfs_type_email ))
2020-12-02 09:07:09 +01:00
{
2023-07-27 11:07:49 +02:00
$cf_emails = $contacts_obj -> read_customfields ( array_map ( static function ( array $contact )
2020-12-02 09:07:09 +01:00
{
2023-07-27 11:07:49 +02:00
return $contact [ 'id' ];
}, $contacts ), $cfs_type_email );
}
foreach ( $contacts as $contact )
{
foreach ( array_merge ([ $contact [ 'email' ], $contact [ 'email_home' ]], $cf_emails [ $contact [ 'id' ]] ? ? []) as $email )
2020-12-02 09:07:09 +01:00
{
2023-07-27 11:07:49 +02:00
// avoid wrong addresses, if a rfc822 encoded address is in addressbook
2016-03-28 20:51:38 +02:00
$rfcAddr = Mail :: parseAddressList ( $email );
2015-07-07 13:44:02 +02:00
$_rfcAddr = $rfcAddr -> first ();
if ( ! $_rfcAddr -> valid )
{
2015-09-21 22:03:33 +02:00
continue ; // skip address if we encounter an error here
2015-07-07 13:44:02 +02:00
}
$email = $_rfcAddr -> mailbox . '@' . $_rfcAddr -> host ;
2016-03-29 10:46:09 +02:00
if ( method_exists ( $contacts_obj , 'search' ))
2013-07-20 11:27:37 +02:00
{
$contact [ 'n_fn' ] = '' ;
2021-03-03 13:07:05 +01:00
if ( ! empty ( $contact [ 'n_prefix' ]) && ( empty ( $contactLabelPref ) || in_array ( 'n_prefix' , $contactLabelPref ))) $contact [ 'n_fn' ] = $contact [ 'n_prefix' ];
if ( ! empty ( $contact [ 'n_given' ]) && ( empty ( $contactLabelPref ) || in_array ( 'n_given' , $contactLabelPref ))) $contact [ 'n_fn' ] .= ( $contact [ 'n_fn' ] ? ' ' : '' ) . $contact [ 'n_given' ];
if ( ! empty ( $contact [ 'n_family' ]) && ( empty ( $contactLabelPref ) || in_array ( 'n_family' , $contactLabelPref ))) $contact [ 'n_fn' ] .= ( $contact [ 'n_fn' ] ? ' ' : '' ) . $contact [ 'n_family' ];
if ( ! empty ( $contact [ 'org_name' ]) && ( empty ( $contactLabelPref ) || in_array ( 'org_name' , $contactLabelPref ))) $contact [ 'n_fn' ] .= ( $contact [ 'n_fn' ] ? ' ' : '' ) . '(' . $contact [ 'org_name' ] . ')' ;
2013-07-20 11:27:37 +02:00
$contact [ 'n_fn' ] = str_replace ( array ( ',' , '@' ), ' ' , $contact [ 'n_fn' ]);
}
else
{
$contact [ 'n_fn' ] = str_replace ( array ( ',' , '@' ), ' ' , $contact [ 'n_fn' ]);
}
2015-06-09 10:54:23 +02:00
$args = explode ( '@' , trim ( $email ));
$args [] = trim ( $contact [ 'n_fn' ] ? $contact [ 'n_fn' ] : $contact [ 'fn' ]);
$completeMailString = call_user_func_array ( 'imap_rfc822_write_address' , $args );
2013-07-20 11:27:37 +02:00
if ( ! empty ( $email ) && in_array ( $completeMailString , $results ) === false ) {
2023-01-27 18:34:40 +01:00
$result = array (
2022-08-09 10:47:57 +02:00
'value' => $completeMailString ,
2013-08-09 19:47:53 +02:00
'label' => $completeMailString ,
2013-07-30 16:20:23 +02:00
// Add just name for nice display, with title for hover
2023-01-27 18:34:40 +01:00
'name' => $contact [ 'n_fn' ],
2018-06-22 15:08:34 +02:00
'title' => $email ,
2023-01-27 18:34:40 +01:00
'lname' => $contact [ 'n_family' ],
'fname' => $contact [ 'n_given' ]
);
2023-07-27 11:07:49 +02:00
// if we have a real photo, add avatar.php URL
if ( Api\Contacts :: hasPhoto ( $contact ))
2023-01-27 18:34:40 +01:00
{
2023-07-27 11:07:49 +02:00
$result [ 'icon' ] = Framework :: link ( '/api/avatar.php' , [
2018-06-22 15:08:34 +02:00
'contact_id' => $contact [ 'id' ],
2023-07-27 11:07:49 +02:00
'modified' => $contact [ 'modified' ],
]);
2023-01-27 18:34:40 +01:00
}
$results [] = $result ;
2013-07-20 11:27:37 +02:00
}
}
}
2013-11-21 23:29:57 +01:00
}
2013-07-20 11:27:37 +02:00
2015-03-23 23:18:38 +01:00
// Add groups
$group_options = array ( 'account_type' => 'groups' );
$groups = $GLOBALS [ 'egw' ] -> accounts -> link_query ( $_searchString , $group_options );
foreach ( $groups as $g_id => $name )
{
$group = $GLOBALS [ 'egw' ] -> accounts -> read ( $g_id );
if ( ! $group [ 'account_email' ]) continue ;
2015-06-09 10:54:23 +02:00
$args = explode ( '@' , trim ( $group [ 'account_email' ]));
$args [] = $name ;
$completeMailString = call_user_func_array ( 'imap_rfc822_write_address' , $args );
2015-03-23 23:18:38 +01:00
$results [] = array (
2023-08-23 17:39:16 +02:00
'value' => $completeMailString ,
2015-03-23 23:18:38 +01:00
'label' => $completeMailString ,
'name' => $name ,
'title' => $group [ 'account_email' ]
);
}
2015-03-31 19:01:25 +02:00
2014-02-24 19:46:14 +01:00
// switch regular JSON response handling off
2016-05-03 21:17:44 +02:00
Api\Json\Request :: isJSONRequest ( false );
2013-11-21 23:29:57 +01:00
2013-07-20 17:15:29 +02:00
//error_log(__METHOD__.__LINE__.array2string($jsArray));
2013-07-20 11:27:37 +02:00
header ( 'Content-Type: application/json; charset=utf-8' );
2023-11-15 23:23:20 +01:00
echo json_encode ( array_values ( array_unique ( $results , SORT_REGULAR )));
2016-05-03 21:17:44 +02:00
exit ();
2013-07-20 11:27:37 +02:00
}
2013-07-20 09:23:55 +02:00
2018-02-16 19:19:47 +01:00
/**
* Get list of matching distribution lists when searching for email addresses
*
2020-12-14 17:34:17 +01:00
* The results are limited by config setting . Default 10 each of group lists and normal lists
2018-02-28 17:30:29 +01:00
*
2018-02-16 19:19:47 +01:00
* @ param String $_searchString
* @ param Contacts $contacts_obj
* @ return array
*/
protected static function get_lists ( $_searchString , & $contacts_obj )
{
$group_lists = array ();
$manual_lists = array ();
$lists = array_filter (
$contacts_obj -> get_lists ( Acl :: READ ),
function ( $element ) use ( $_searchString ) {
return ( stripos ( $element , $_searchString ) !== false );
}
);
foreach ( $lists as $key => $list_name )
{
$type = $key > 0 ? 'manual' : 'group' ;
$list = array (
2023-04-18 16:27:01 +02:00
'value' => '"' . str_replace ( '"' , '' , $list_name ) . '" <' . $key . '@lists.egroupware.org>' ,
2018-02-16 19:19:47 +01:00
'label' => $list_name ,
'title' => lang ( 'Mailinglist' ),
2022-09-12 14:50:52 +02:00
'icon' => Api\Image :: find ( 'api' , 'email' ),
2018-02-16 19:19:47 +01:00
);
$ { " ${ type}_lists" } [] = $list ;
}
2020-12-14 17:34:17 +01:00
$config = Api\Config :: read ( 'mail' );
$limit = $config [ 'address_list_limit' ] ? : 10 ;
$trim = function ( $list ) use ( $limit ) {
2018-02-16 19:19:47 +01:00
if ( count ( $list ) <= $limit ) return $list ;
$list [ $limit - 1 ][ 'class' ] .= ' more_results' ;
$list [ $limit - 1 ][ 'title' ] .= ' (' . lang ( '%1 more' , count ( $list ) - $limit ) . ')' ;
return array_slice ( $list , 0 , $limit );
};
return array_merge ( $trim ( $group_lists ), $trim ( $manual_lists ));
}
2014-01-16 15:05:07 +01:00
/**
* Merge the selected contact ID into the document given in $_REQUEST [ 'document' ]
* and send it .
*
* @ param int $contact_id
*/
public function ajax_merge ( $contact_id )
{
2016-05-03 21:17:44 +02:00
$response = Api\Json\Response :: get ();
if ( class_exists ( $_REQUEST [ 'merge' ]) && is_subclass_of ( $_REQUEST [ 'merge' ], 'EGroupware\\Api\\Storage\\Merge' ))
2015-05-19 21:24:02 +02:00
{
$document_merge = new $_REQUEST [ 'merge' ]();
}
else
{
2016-05-03 21:17:44 +02:00
$document_merge = new Api\Contacts\Merge ();
2015-05-19 21:24:02 +02:00
}
2014-01-16 15:05:07 +01:00
$this -> mail_bo -> openConnection ();
2014-01-18 15:00:19 +01:00
2014-11-20 18:53:52 +01:00
if (( $error = $document_merge -> check_document ( $_REQUEST [ 'document' ], '' )))
2014-01-16 15:05:07 +01:00
{
$response -> error ( $error );
return ;
}
// Actually do the merge
2014-11-20 18:53:52 +01:00
$folder = $merged_mail_id = null ;
2016-06-30 23:45:31 +02:00
try
{
$results = $this -> mail_bo -> importMessageToMergeAndSend (
$document_merge , Vfs :: PREFIX . $_REQUEST [ 'document' ],
// Send an extra non-numeric ID to force actual send of document
// instead of save as draft
array (( int ) $contact_id , '' ),
$folder , $merged_mail_id
);
2017-01-19 17:36:38 +01:00
// Also save as infolog
if ( $merged_mail_id && $_REQUEST [ 'to_app' ] && isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $_REQUEST [ 'to_app' ]]))
{
$rowid = mail_ui :: generateRowID ( $this -> mail_bo -> profileID , $folder , $merged_mail_id , true );
$data = mail_integration :: get_integrate_data ( $rowid );
if ( $data && $_REQUEST [ 'to_app' ] == 'infolog' )
{
$bo = new infolog_bo ();
$entry = $bo -> import_mail ( $data [ 'addresses' ], $data [ 'subject' ], $data [ 'message' ], $data [ 'attachments' ], $data [ 'date' ]);
2017-01-20 16:37:08 +01:00
if ( $_REQUEST [ 'info_type' ] && isset ( $bo -> enums [ 'type' ][ $_REQUEST [ 'info_type' ]]))
{
$entry [ 'info_type' ] = $_REQUEST [ 'info_type' ];
}
2017-01-19 17:36:38 +01:00
$bo -> write ( $entry );
}
}
2016-06-30 23:45:31 +02:00
}
catch ( Exception $e )
{
$contact = $document_merge -> contacts -> read (( int ) $contact_id );
//error_log(__METHOD__.' ('.__LINE__.') '.' ID:'.$val.' Data:'.array2string($contact));
$email = ( $contact [ 'email' ] ? $contact [ 'email' ] : $contact [ 'email_home' ]);
$nfn = ( $contact [ 'n_fn' ] ? $contact [ 'n_fn' ] : $contact [ 'n_given' ] . ' ' . $contact [ 'n_family' ]);
$response -> error ( lang ( 'Sending mail to "%1" failed' , " $nfn < $email > " ) .
" \n " . $e -> getMessage ()
);
}
2014-01-16 15:05:07 +01:00
if ( $results [ 'success' ])
{
$response -> data ( implode ( ',' , $results [ 'success' ]));
}
if ( $results [ 'failed' ])
{
$response -> error ( implode ( ',' , $results [ 'failed' ]));
}
}
2017-02-03 12:33:49 +01:00
/**
2017-03-09 17:42:41 +01:00
* Method to do encryption on given mail object
2017-02-03 12:33:49 +01:00
*
2017-07-10 12:57:14 +02:00
* @ param Api\Mailer $mail
2017-02-03 12:33:49 +01:00
* @ param string $type encryption type
* @ param array | string $recipients list of recipients
* @ param string $sender email of sender
2017-07-10 12:57:14 +02:00
* @ param string $passphrase = '' , SMIME Private key passphrase
2017-07-11 11:43:53 +02:00
*
2017-03-09 17:42:41 +01:00
* @ return boolean returns true if successful and false if passphrase required
2017-02-03 12:33:49 +01:00
* @ throws Api\Exception\WrongUserinput if no certificate found
*/
2017-03-09 17:42:41 +01:00
protected function _encrypt ( $mail , $type , $recipients , $sender , $passphrase = '' )
2017-02-03 12:33:49 +01:00
{
$AB = new addressbook_bo ();
2017-08-30 17:00:28 +02:00
// passphrase of sender private key
$params [ 'passphrase' ] = $passphrase ;
2017-02-03 12:33:49 +01:00
2017-03-09 17:42:41 +01:00
try
2017-02-03 12:33:49 +01:00
{
2018-08-17 11:50:26 +02:00
$sender_cert = $AB -> get_smime_keys ( $sender );
2020-04-21 18:58:08 +02:00
if ( ! $sender_cert ) throw new Exception ( lang ( " S/MIME Encryption failed because no certificate has been found for sender address: %1 " , $sender ));
2019-03-25 17:12:00 +01:00
$params [ 'senderPubKey' ] = $sender_cert [ strtolower ( $sender )];
2018-08-17 11:50:26 +02:00
2017-03-09 17:42:41 +01:00
if ( isset ( $sender ) && ( $type == Mail\Smime :: TYPE_SIGN || $type == Mail\Smime :: TYPE_SIGN_ENCRYPT ))
2017-02-03 12:33:49 +01:00
{
2017-08-30 17:00:28 +02:00
$acc_smime = Mail\Smime :: get_acc_smime ( $this -> mail_bo -> profileID , $params [ 'passphrase' ]);
2022-04-26 18:46:23 +02:00
$params [ 'senderPrivKey' ] = $acc_smime [ 'pkey' ] ? ? null ;
$params [ 'extracerts' ] = $acc_smime [ 'extracerts' ] ? ? null ;
2017-02-03 12:33:49 +01:00
}
2017-02-15 12:23:27 +01:00
2017-03-09 17:42:41 +01:00
if ( isset ( $recipients ) && ( $type == Mail\Smime :: TYPE_ENCRYPT || $type == Mail\Smime :: TYPE_SIGN_ENCRYPT ))
2017-02-15 12:23:27 +01:00
{
2017-03-09 17:42:41 +01:00
$params [ 'recipientsCerts' ] = $AB -> get_smime_keys ( $recipients );
2017-04-11 18:03:16 +02:00
foreach ( $recipients as & $recipient )
{
2019-03-25 17:12:00 +01:00
if ( ! $params [ 'recipientsCerts' ][ strtolower ( $recipient )]) $missingCerts [] = $recipient ;
2017-04-11 18:03:16 +02:00
}
2017-09-08 13:40:25 +02:00
if ( is_array ( $missingCerts )) throw new Exception ( 'S/MIME Encryption failed because no certificate has been found for following addresses: ' . implode ( '|' , $missingCerts ));
2017-02-15 12:23:27 +01:00
}
2017-02-03 12:33:49 +01:00
2017-03-09 17:42:41 +01:00
return $mail -> smimeEncrypt ( $type , $params );
2017-02-03 12:33:49 +01:00
}
2017-03-09 17:42:41 +01:00
catch ( Api\Exception\WrongUserinput $e )
2017-02-03 12:33:49 +01:00
{
2017-03-09 17:42:41 +01:00
throw new $e ;
2017-02-03 12:33:49 +01:00
}
}
2018-07-11 14:39:28 +02:00
/**
* Builds attachments from provided UIDs and add them to sessionData
*
* @ param string | array $_ids series of message ids
* @ param int $_serverID compose current profileID
*
* @ return array returns an array of attachments
*
* @ throws Exception throws exception on cross account attempt
*/
function _get_uids_as_attachments ( $_ids , $_serverID )
{
$ids = is_array ( $_ids ) ? $_ids : explode ( ',' , $_ids );
if ( is_array ( $ids ) && $_serverID )
{
$parts = mail_ui :: splitRowID ( $ids [ 0 ]);
if ( $_serverID != $parts [ 'profileID' ])
{
throw new Exception ( lang ( 'Cross account forward attachment is not allowed!' ));
}
}
foreach ( $ids as & $id )
{
$parts = mail_ui :: splitRowID ( $id );
$mail_bo = $this -> mail_bo ;
$mail_bo -> openConnection ();
$mail_bo -> reopen ( $parts [ 'folder' ]);
$headers = $mail_bo -> getMessageEnvelope ( $parts [ 'msgUID' ], null , false , $parts [ 'folder' ]);
$this -> addMessageAttachment ( $parts [ 'msgUID' ], null , $parts [ 'folder' ],
$mail_bo -> decode_header (( $headers [ 'SUBJECT' ] ? $headers [ 'SUBJECT' ] : lang ( 'no subject' ))) . '.eml' ,
'MESSAGE/RFC822' , $headers [ 'SIZE' ] ? $headers [ 'SIZE' ] : lang ( 'unknown' ));
$mail_bo -> closeConnection ();
}
return $this -> sessionData [ 'attachments' ];
}
2022-04-26 18:46:23 +02:00
}