egroupware_official/mail/inc/class.mail_sieve.inc.php

1285 lines
36 KiB
PHP
Raw Normal View History

2013-07-25 17:48:18 +02:00
<?php
/**
* EGroupware - Mail - interface class
*
* @link http://www.egroupware.org
* @package mail
* @author Hadi Nategh [hn@stylite.de]
* @copyright (c) 2013 by Hadi Nategh <hn-AT-stylite.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
2014-04-03 14:31:52 +02:00
* @version $Id$
2013-07-25 17:48:18 +02:00
*/
class mail_sieve
{
var $public_functions = array(
'editVacation' => True,
'index' => True,
'edit' => True,
'editEmailNotification'=> True, // Added email notifications
);
2013-07-25 17:48:18 +02:00
var $errorStack;
/**
* Current Identitiy
*
* @var String
*/
var $currentIdentity;
/**
* user has admin right to emailadmin
*
* @var boolean
*/
var $mail_admin = false;
/**
* account object
*
* @var emailadmin_account
*/
var $account;
/**
* flag to check if vacation is called from admin
*
* @var boolean
*/
var $is_admin_vac = false;
/**
* siteConfigs
*
* @var array
*/
var $mailConfig = array();
2013-07-25 17:48:18 +02:00
/**
* Constructor
*/
function __construct()
{
$this->displayCharset = translation::charset();
$this->mail_admin = isset($GLOBALS['egw_info']['user']['apps']['emailadmin']);
$this->mailConfig = config::read('mail');
$acc_id = isset($_GET['acc_id']) ? (int)$_GET['acc_id'] : egw_cache::getSession(__CLASS__, 'acc_id');
if ($acc_id > 0)
{
$this->account = emailadmin_account::read($acc_id);
$identity = emailadmin_account::read_identity($this->account->ident_id,true);
$this->currentIdentity = mail_bo::generateIdentityString($identity,false);
}
2013-07-25 17:48:18 +02:00
$this->restoreSessionData();
}
2013-07-25 17:48:18 +02:00
/**
* Sieve rules list
*
* @param {array} $content
* @param {string} $msg
2013-07-25 17:48:18 +02:00
*/
function index(array $content=null,$msg=null)
{
if (!is_array($content))
{
egw_cache::setSession(__CLASS__, 'acc_id', $this->account->acc_id);
}
//Instantiate an etemplate_new object
$tmpl = new etemplate_new('mail.sieve.index');
2013-08-09 19:47:53 +02:00
if ($msg)
{
$content['msg'] = $msg;
}
if ($this->account->acc_sieve_enabled)
{
//Initializes the Grid contents
$content['rg']= $this->get_rows();
2013-07-25 17:48:18 +02:00
// Set content-menu actions
$tmpl->set_cell_attribute('rg', 'actions',$this->get_actions());
2013-07-25 17:48:18 +02:00
$sel_options = array(
'status' => array(
'ENABLED' => lang('Enabled'),
'DISABLED' => lang('Disabled'),
)
);
}
else
{
$content['msg'] = lang('error').':'.lang('Serverside Filterrules (Sieve) are not activated').'. '.lang('Please contact your Administrator to validate if your Server supports Serverside Filterrules, and how to enable them in EGroupware for your active Account (%1) with ID:%2.',$this->currentIdentity,$this->account->acc_id);
$content['hideIfSieveDisabled']='mail_DisplayNone';
}
$tmpl->exec('mail.mail_sieve.index',$content,$sel_options,array());
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
/**
* Email Notification Edit
*
*
* @param {array} $content
* @param {string} $msg
2013-08-09 19:47:53 +02:00
*/
function editEmailNotification($content=null, $msg='')
{
//Instantiate an etemplate_new object, representing sieve.emailNotification
$eNotitmpl = new etemplate_new('mail.sieve.emailNotification');
if ($this->account->acc_sieve_enabled)
2013-08-09 19:47:53 +02:00
{
$eNotification = $this->getEmailNotification();
2013-08-09 19:47:53 +02:00
if (!is_array($content))
2013-08-09 19:47:53 +02:00
{
$content = $eNotification;
2013-08-09 19:47:53 +02:00
if (!empty($eNotification['externalEmail']))
{
$content['externalEmail'] = explode(",",$eNotification['externalEmail']);
}
}
else
2013-08-09 19:47:53 +02:00
{
$this->restoreSessionData();
list($button) = @each($content['button']);
unset ($content['button']);
switch($button)
{
case 'save':
case 'apply':
if (isset($content['status']))
2013-08-09 19:47:53 +02:00
{
$newEmailNotification = $content;
if (empty($this->mailConfig['prefpreventforwarding']) ||
$this->mailConfig['prefpreventforwarding'] == 0 )
2013-08-09 19:47:53 +02:00
{
if (is_array($content['externalEmail']) && !empty($content['externalEmail']))
{
$newEmailNotification['externalEmail'] = implode(",",$content['externalEmail']);
}
2013-08-09 19:47:53 +02:00
}
}
if (isset($content['externalEmail']) && !empty($content['externalEmail']))
2013-08-09 19:47:53 +02:00
{
if (!$this->account->imapServer()->setEmailNotification($newEmailNotification))
{
$msg = lang("email notification update failed")."<br />";
break;
}
else
{
$msg .= lang("email notification successfully updated!");
}
2013-08-09 19:47:53 +02:00
}
else
{
$msg .= lang('email notification update failed! You need to set an email address!');
break;
2013-08-09 19:47:53 +02:00
}
egw_framework::refresh_opener($msg, 'mail');
2014-05-13 09:54:42 +02:00
if ($button === 'apply')
{
break;
}
2013-08-09 19:47:53 +02:00
case 'cancel':
egw_framework::window_close();
common::egw_exit();
}
$this->saveSessionData();
2013-08-09 19:47:53 +02:00
}
$sel_options = array(
'status' => array(
'on' => lang('Active'),
'off' => lang('Deactive'),
),
'displaySubject' => array(
0 => lang('No'),
1 => lang('Yes'),
),
);
$content['msg'] = $msg;
}
else
{
$content['msg'] = lang('error').':'.lang('Serverside Filterrules (Sieve) are not activated').'. '.lang('Please contact your Administrator to validate if your Server supports Serverside Filterrules, and how to enable them in EGroupware for your active Account (%1) with ID:%2.',$this->currentIdentity,$this->account->acc_id);
$content['hideIfSieveDisabled']='mail_DisplayNone';
}
2013-08-09 19:47:53 +02:00
$eNotitmpl->exec('mail.mail_sieve.editEmailNotification', $content,$sel_options);
}
2013-07-25 17:48:18 +02:00
/**
* Sieve rules edit
*
* @param {array} $content
2013-07-25 17:48:18 +02:00
*/
function edit ($content=null)
{
//Instantiate an etemplate_new object, representing sieve.edit template
$etmpl = new etemplate_new('mail.sieve.edit');
$etmpl->setElementAttribute('action_folder_text','autocomplete_params', array('noPrefixId'=> true));
2013-07-25 17:48:18 +02:00
if (!is_array($content))
{
if ( $this->getRules($_GET['ruleID']) && isset($_GET['ruleID']))
{
$rules = $this->rulesByID;
2013-08-09 19:47:53 +02:00
$content= $rules;
2013-07-25 17:48:18 +02:00
switch ($rules['action'])
{
case 'folder':
$content['action_folder_text'][] = $rules['action_arg'];
2013-08-09 19:47:53 +02:00
2013-07-25 17:48:18 +02:00
break;
case 'address':
2013-08-09 19:47:53 +02:00
$content['action_address_text'] = explode(',', $rules['action_arg']);
2013-07-25 17:48:18 +02:00
break;
case 'reject':
$content['action_reject_text'] = $rules['action_arg'];
}
}
else // Adding new rule
{
2013-08-09 19:47:53 +02:00
$this->getRules(null);
2013-07-25 17:48:18 +02:00
$newRulePriority = count($this->rules)*2+1;
$newRules ['priority'] = $newRulePriority;
$newRules ['status'] = 'ENABLED';
2013-08-09 19:47:53 +02:00
$readonlys = array(
'button[delete]' => 'true',
);
2013-07-25 17:48:18 +02:00
$this->rulesByID = $newRules;
2013-08-09 19:47:53 +02:00
$content = $this->rulesByID;
2013-07-25 17:48:18 +02:00
}
$this->saveSessionData();
}
else
{
$this->restoreSessionData();
list($button) = @each($content['button']);
2013-08-09 19:47:53 +02:00
//$ruleID is calculated by priority from the selected rule and is an unique ID
$ruleID = ($this->rulesByID['priority'] -1) / 2;
$error = 0;
2013-07-25 17:48:18 +02:00
switch ($button)
{
case 'save':
2013-08-09 19:47:53 +02:00
case 'apply':
2013-07-25 17:48:18 +02:00
if($content)
{
unset($content['button']);
2013-08-09 19:47:53 +02:00
2013-07-25 17:48:18 +02:00
$newRule = $content;
$newRule['priority'] = $this->rulesByID['priority'];
$newRule['status'] = $this->rulesByID['status'];
switch ($content['action'])
2013-07-25 17:48:18 +02:00
{
case 'folder':
$newRule['action_arg'] = implode($content['action_folder_text']);
2013-07-25 17:48:18 +02:00
break;
case 'address':
$content['action_address_text'] = self::strip_rfc882_addresses($content['action_address_text']);
$newRule['action_arg'] = implode(',', $content['action_address_text']);
2013-07-25 17:48:18 +02:00
break;
case 'reject':
$newRule['action_arg'] = $content['action_reject_text'];
}
unset($newRule['action_folder_text']);
unset($newRule['action_address_text']);
unset($newRule['action_reject_text']);
$newRule['flg'] = 0 ;
if( $newRule['continue'] ) { $newRule['flg'] += 1; }
if( $newRule['gthan'] ) { $newRule['flg'] += 2; }
if( $newRule['anyof'] ) { $newRule['flg'] += 4; }
if( $newRule['keep'] ) { $newRule['flg'] += 8; }
if( $newRule['regexp'] ) { $newRule['flg'] += 128; }
2013-07-25 17:48:18 +02:00
if($newRule['action'] && $this->rulesByID['priority'])
{
$this->rules[$ruleID] = $newRule;
$ret = $this->account->imapServer()->setRules($this->rules);
if (!$ret && !empty($this->account->imapServer()->error))
2013-07-25 17:48:18 +02:00
{
$msg .= lang("Saving the rule failed:")."<br />".$this->account->imapServer()->error."<br />";
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
else
{
$msg .= lang("The rule with priority %1 successfully saved!",$ruleID);
}
2013-07-25 17:48:18 +02:00
$this->saveSessionData();
}
else
{
$msg .= "\n".lang("Error: Could not save rule").' '.lang("No action defined!");
$error++;
}
}
else
{
$msg .= "\n".lang("Error: Could not save rule").' '.lang("No action defined!");
$error++;
}
egw_framework::refresh_opener($msg, 'mail', 'sieve');
2014-05-13 09:54:42 +02:00
if ($button == "apply")
{
break;
}
2013-08-09 19:47:53 +02:00
//fall through
2013-07-25 17:48:18 +02:00
case 'delete':
2013-08-09 19:47:53 +02:00
if ($button == "delete")
2014-05-13 09:54:42 +02:00
{
if ($ruleID === count($this->rules)-1)
{
$msg = lang('rule with priority ') . $ruleID . lang(' deleted!');
}
else
{
$msg = lang('rule with priority ') . $ruleID . lang(' deleted!') . lang(' And the rule with priority %1, now got the priority %2',$ruleID+1,$ruleID);
}
unset($this->rules[$ruleID]);
$this->rules = array_values($this->rules);
2014-05-23 10:01:56 +02:00
$this->updateScript();
2014-05-13 09:54:42 +02:00
}
egw_framework::refresh_opener($msg, 'mail', 'sieve');
2013-08-09 19:47:53 +02:00
case 'cancel':
egw_framework::window_close();
2013-08-09 19:47:53 +02:00
common::egw_exit();
2013-07-25 17:48:18 +02:00
}
}
2013-08-09 19:47:53 +02:00
$sel_options = array(//array_merge($sel_options,array(
2013-07-25 17:48:18 +02:00
'anyof' => array(
0 => lang('all of'),
1 => lang('any of'),
),
'gthan' => array(
0 => lang('less than'),
1 => lang('greater than'),
),
'bodytransform' => array(
0 => 'raw',
1 => 'text',
),
'ctype' => emailadmin_script::$btransform_ctype_array,
);
//Set the preselect_options for mail/folders as we are not allow free entry for folder taglist
$sel_options['action_folder_text'] = $this->ajax_getFolders(0,true,null,true);
2013-07-25 17:48:18 +02:00
return $etmpl->exec('mail.mail_sieve.edit',$content,$sel_options,$readonlys,array(),2);
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
/**
* Read email notification script from the sieve script from server
*
*
2013-08-09 19:47:53 +02:00
* @return type, returns array of email notification data, and in case of failure returns false
* @todo Need to be checked if it is still needed
2013-08-09 19:47:53 +02:00
*/
function getEmailNotification()
2013-07-25 17:48:18 +02:00
{
if(!(empty($this->mailConfig['prefpreventnotificationformailviaemail']) || $this->mailConfig['prefpreventnotificationformailviaemail'] == 0))
2014-05-13 09:54:42 +02:00
{
throw new egw_exception_no_permission();
}
2013-07-25 17:48:18 +02:00
try {
$emailNotification = $this->account->imapServer()->getEmailNotification();
2013-08-09 19:47:53 +02:00
}
catch(Exception $e) {
unset($e);
$emailNotification = array();
}
2013-08-09 19:47:53 +02:00
return $emailNotification;
}
/**
* Fetch Vacation rules and predefined Addresses from mailserver
*
* @param string $accountID
*
* @return array return multi-dimentional array of vacation and aliases
2013-08-09 19:47:53 +02:00
*/
function getVacation($accountID = null)
2013-08-09 19:47:53 +02:00
{
if(!(empty($this->mailConfig['prefpreventabsentnotice']) || $this->mailConfig['prefpreventabsentnotice'] == 0))
2013-07-25 17:48:18 +02:00
{
2014-05-13 09:54:42 +02:00
throw new egw_exception_no_permission();
2013-07-25 17:48:18 +02:00
}
try {
if ($this->is_admin_vac)
2013-07-25 17:48:18 +02:00
{
$icServer = $this->account->imapServer($accountID);
$vacation = $icServer->getVacationUser($accountID);
2013-07-25 17:48:18 +02:00
}
else
{
$icServer = $this->account->imapServer();
$icServer->retrieveRules(null);
$vacation = $icServer->getVacation();
2013-07-25 17:48:18 +02:00
}
}
catch(Exception $e)
2013-07-25 17:48:18 +02:00
{
egw_framework::window_close(lang($e->getMessage()));
2013-07-25 17:48:18 +02:00
}
if (is_null($accountID)) $accountID = $GLOBALS['egw_info']['user']['account_id'];
$accAllIdentities = $this->account->smtpServer()->getAccountEmailAddress(accounts::id2name($accountID));
$allAliases = array($this->account->ident_email);
foreach ($accAllIdentities as &$arrVal)
{
if ($arrVal['type'] !='default')
{
$allAliases[] = $arrVal['address'];
}
}
asort($allAliases);
2013-08-09 19:47:53 +02:00
return array(
'vacation' =>$vacation,
'aliases' => array_values($allAliases),
);
2013-08-09 19:47:53 +02:00
}
/**
* Vacation edit
*
* @param {array} $content
* @param {string} $msg
2013-08-09 19:47:53 +02:00
*/
function editVacation($content=null, $msg='')
{
//Instantiate an etemplate_new object, representing the sieve.vacation template
$vtmpl = new etemplate_new('mail.sieve.vacation');
2014-05-13 09:54:42 +02:00
$vacation = array();
if (isset($_GET['account_id'])) $account_id = $preserv['account_id'] = $_GET['account_id'];
if (isset($content['account_id']))
{
$account_id = $content['account_id'];
$preserv['acc_id'] = $content['acc_id'];
}
if(isset($account_id) && $this->mail_admin)
{
foreach(emailadmin_account::search($account_id, false, null, false, 0, false) as $account)
{
try {
// check if account is valid for multiple users, has admin credentials and sieve enabled
if (emailadmin_account::is_multiple($account) &&
($icServer = $account->imapServer(true)) && // check on icServer object, so plugins can overwrite
$icServer->acc_imap_admin_username && $icServer->acc_sieve_enabled)
{
$allAccounts[$account->acc_id] = $account->acc_name;
$accounts[$account->acc_id] = $account;
}
}
catch(Exception $e) {
unset($e);
// ignore broken accounts
}
}
$profileID = !isset($content['acc_id']) ? key($accounts):$content['acc_id'];
if (isset($_GET['acc_id']) && isset($allAccounts[$_GET['acc_id']]))
{
$profileID = $content['acc_id'] = (int)$_GET['acc_id'];
}
//Chooses the right account
$this->account = $accounts[$profileID];
$this->is_admin_vac = true;
$preserv['account_id'] = $account_id;
}
elseif(!is_array($content) && isset($_GET['acc_id']))
{
$this->account = emailadmin_account::read($_GET['acc_id']);
$preserv['acc_id'] = $this->account->acc_id;
}
elseif ($content['acc_id'])
{
$this->account = emailadmin_account::read($content['acc_id']);
$preserv['acc_id'] = $content['acc_id'];
}
$icServer = $this->account->imapServer($this->is_admin_vac ? $account_id : false);
if ($icServer->acc_sieve_enabled)
2013-07-25 17:48:18 +02:00
{
$vacRules = $this->getVacation($account_id);
if ($vacRules['vacation']===false)
{
$content['msg'] = lang('error').':'.lang('Serverside Vacationnotice (via Sieve) are not activated').'. '.
lang('Please contact your Administrator to validate if your Server supports Serverside Vacationmessages, and how to enable them in EGroupware for your active Account (%1) with ID:%2.',$this->currentIdentity,$icServer->ImapServerId);
$content['hideIfSieveDisabled']='mail_DisplayNone';
}
else
2013-07-25 17:48:18 +02:00
{
if ($icServer->acc_imap_administration)
2014-05-13 09:54:42 +02:00
{
$ByDate = array('by_date' => lang('By date'));
2014-05-13 09:54:42 +02:00
}
if (!is_array($content) || ($content['acc_id'] && !isset($content['button'])) || (strlen(trim($content['text']))==0 && in_array($content['status'],array('on','by_date'))))
{
$content = $vacation = $vacRules['vacation'];
if (!empty($profileID)) $content['acc_id'] = $profileID;
if (empty($vacation['addresses']) || implode('',$vacation['addresses']) == '')
{
$content['addresses'] = $vacRules['aliases'];
}
if (!empty($vacation['forwards']))
{
$content['forwards'] = explode(",",$vacation['forwards']);
}
else
{
$content['forwards'] = '';
}
if (strlen(trim($vacation['text']))==0 && $this->mailConfig['default_vacation_text']) $content['text'] = $this->mailConfig['default_vacation_text'];
if (strlen(trim($content['text']))==0)
{
$content['msg'] = $msg = lang('error').': '.lang('No vacation notice text provided. Please enter a message.');
egw_framework::refresh_opener($msg, 'mail');
}
//Set default value for days new entry
if (empty($content['days']))
{
$content['days'] = '3';
}
$preserv['is_admin_vac'] = $content['is_admin_vac'] = $this->is_admin_vac;
}
else
{
$this->restoreSessionData();
list($button) = @each($content['button']);
unset ($content['button']);
2013-08-09 19:47:53 +02:00
switch($button)
{
case 'save':
case 'apply':
if ($GLOBALS['egw_info']['user']['apps']['admin'])
{
// store text as default
if ($content['set_as_default'] == 1 && $content['text'])
{
config::save_value('default_vacation_text', $content['text'], 'mail');
}
}
if (isset($content['status']))
2013-08-09 19:47:53 +02:00
{
//error_log(__METHOD__. 'content:' . array2string($content));
$newVacation = $content;
if (empty($this->mailConfig['prefpreventforwarding']) ||
$this->mailConfig['prefpreventforwarding'] == 0 )
{
$content['forwards'] = self::strip_rfc882_addresses($content['forwards']);
$newVacation['forwards'] = implode(',', $content['forwards']);
}
else
{
unset($newVacation ['forwards']);
}
2013-08-09 19:47:53 +02:00
if (!in_array($newVacation['status'],array('on','off','by_date')))
{
$newVacation['status'] = 'off';
}
$checkAddresses = isset($content['check_mail_sent_to']) && $content['check_mail_sent_to'] != 0;
if ($content['addresses'])
{
$newVacation ['addresses'] = $content['addresses'] =
self::strip_rfc882_addresses($content['addresses']);
}
if($this->checkRule($newVacation,$checkAddresses))
{
if (isset($account_id) && $this->mail_admin)
{
$resSetvac = $icServer->setVacationUser($account_id, $newVacation, $this->scriptName);
}
else
{
$resSetvac = $icServer->setVacation($newVacation);
}
if (!$resSetvac)
{
$msg = lang('vacation update failed') . "\n" . lang('Vacation notice update failed') . ":" . $this->account->imapServer()->error;
break;
}
// schedule job to switch message on/off, if request and not already in past
else
{
if ($newVacation['status'] == 'by_date' && $newVacation['end_date']+24*3600 > time() ||
$vacRules && $vacRules['vacation']['status'] == 'by_date')
{
self::setAsyncJob($newVacation);
}
//Reset vacationNotice cache which is used in mail_ui get_rows
if (isset($account_id) && $this->mail_admin)
{
2016-01-28 12:24:24 +01:00
$account_lid = accounts::id2name($account_id,'account_lid');
$cachedVacations = array($icServer->acc_id => $newVacation) + (array)egw_cache::getCache(egw_cache::INSTANCE, 'email', 'vacationNotice'.$account_lid);
//error_log(__METHOD__.__LINE__.' Setting Cache for '.$account_lid.':'.array2string($cachedVacations));
egw_cache::setCache(egw_cache::INSTANCE,'email', 'vacationNotice'.$account_lid, $cachedVacations);
}
else
{
$cachedVacations = array($icServer->acc_id => $newVacation) + (array)egw_cache::getCache(egw_cache::INSTANCE, 'email', 'vacationNotice'.$GLOBALS['egw_info']['user']['account_lid']);
2016-01-28 12:24:24 +01:00
//error_log(__METHOD__.__LINE__.' Setting Cache for own ('.$GLOBALS['egw_info']['user']['account_lid'].'):'.array2string($cachedVacations));
egw_cache::setCache(egw_cache::INSTANCE,'email', 'vacationNotice'.$GLOBALS['egw_info']['user']['account_lid'], $cachedVacations);
}
$msg = lang('Vacation notice sucessfully updated.');
}
}
else
{
$msg .= implode("\n",$this->errorStack);
}
// refresh vacationNotice on index
$response = egw_json_response::get();
$response->call('app.mail.mail_callRefreshVacationNotice',$icServer->ImapServerId);
egw_framework::refresh_opener($msg, 'mail');
if ($button === 'apply' || $icServer->error !=="")
{
break;
}
2013-08-09 19:47:53 +02:00
}
case 'cancel':
egw_framework::window_close();
}
}
$sel_options = array(
'status' => array(
'on' => lang('Active'),
'off' => lang('Deactive'),
),
'addresses' => array_combine($vacRules['aliases'],$vacRules['aliases']),
);
if (!isset($account_id))
{
$readonlys['acc_id'] = true;
}
else
{
$sel_options['acc_id'] = $allAccounts;
}
if (!empty($ByDate))
{
$sel_options['status'] += $ByDate;
}
if (!isset($GLOBALS['egw_info']['user']['apps']['admin']))
{
$content['is_not_admin_user'] = true;
$readonlys['set_as_default'] = true;
}
$content['msg'] = $msg;
}
}
else
{
$content['msg'] = lang('error').':'.lang('Serverside Filterrules (Sieve) are not activated').'. '.lang('Please contact your Administrator to validate if your Server supports Serverside Filterrules, and how to enable them in EGroupware for your active Account (%1) with ID:%2.',$this->currentIdentity,$icServer->ImapServerId);
$content['hideIfSieveDisabled']='mail_DisplayNone';
}
$vtmpl->exec('mail.mail_sieve.editVacation',$content,$sel_options,$readonlys,$preserv,2);
2013-08-09 19:47:53 +02:00
}
/**
* Strip personal part from rfc822 addresses: "Ralf Becker <rb@stylite.de>" --> rb@stylite.de
*
* Sieve only allows email-addresses, without angle brakets and personal parts.
*
* @param array|string $_addresses
* @return array of email-addresses without personal part
*/
static function strip_rfc882_addresses($_addresses)
{
$addresses = array();
foreach(emailadmin_imapbase::parseAddressList($_addresses) as $addr)
{
if ($addr->valid)
{
$addresses[] = $addr->mailbox.'@'.$addr->host;
}
}
return $addresses;
}
/**
* set the asyncjob for a timed vacation
*
* @param array $_vacation vacation to set/unset with values for 'account_id', 'acc_id' and vacation stuff
* @param boolean $_reschedule do nothing but reschedule the job by 3 minutes
* @return void
*/
static function setAsyncJob (array $_vacation, $_reschedule=false)
{
if (!($_vacation['acc_id'] > 0))
{
throw new egw_exception_wrong_parameter('No acc_id given!');
}
// setting up an async job to enable/disable the vacation message
$async = new asyncservice();
if (empty($_vacation['account_id'])) $_vacation['account_id'] = $GLOBALS['egw_info']['user']['account_id'];
$async_id = !empty($_vacation['id']) ? $_vacation['id'] : 'mail-vacation-'.$_vacation['account_id'];
$async->delete($async_id);
$end_date = $_vacation['end_date'] + 24*3600; // end-date is inclusive, so we have to add 24h
if ($_vacation['status'] == 'by_date' && time() < $end_date && !$_reschedule)
{
$time = time() < $_vacation['start_date'] ? $_vacation['start_date'] : $end_date;
$async->set_timer($time,$async_id, 'mail_sieve::async_vacation', $_vacation, $_vacation['account_id']);
}
if ($_reschedule)
{
$_vacation['rescheduled'] = $_vacation['rescheduled'] ? 2*$_vacation['rescheduled'] : 5;
// only try to reschedule for 2 days max
if ($_vacation['rescheduled'] <= 2 * 24 * 60)
{
$time = time() + 60*($_vacation['rescheduled']);
unset($_vacation['next']);
unset($_vacation['times']);
$async->set_timer($time, $async_id, 'mail_sieve::async_vacation', $_vacation, $_vacation['account_id']);
}
}
}
/**
* Callback for the async job to enable/disable the vacation message
*
* @param array $_vacation
* @throws egw_exception_not_found if mail account is not found
*/
static function async_vacation(array $_vacation)
{
//error_log(__METHOD__.'('.array2string($_vacation).')');
$account = emailadmin_account::read($_vacation['acc_id'], $_vacation['account_id']);
$icServer = $account->imapServer($_vacation['account_id']);
//error_log(__METHOD__.'() imap username='.$icServer->acc_imap_username);
try
{
$ret = $icServer->setVacationUser($_vacation['account_id'], $_vacation);
self::setAsyncJob($_vacation);
}
// if mail account no longer exists --> remove async job
catch (egw_exception_not_found $e)
{
$_vacation['status'] = 'off';
self::setAsyncJob($_vacation);
}
catch (Exception $e) {
error_log(__METHOD__.'('.array2string($_vacation).' failed '.$e->getMessage());
self::setAsyncJob($_vacation, true); // reschedule
$ret = false;
}
return $ret;
}
2013-08-09 19:47:53 +02:00
/**
* Checking vaction validation
*
* @param {array} $_vacation
* @param {boolean} $_checkAddresses
*
2013-08-09 19:47:53 +02:00
* @return boolean
*/
function checkRule($_vacation,$_checkAddresses=true)
{
$this->errorStack = array();
if (!$_vacation['text'])
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
$this->errorStack['text'] = lang('Please supply the message to send with auto-responses').'! ';
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
if (!$_vacation['days'])
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
$this->errorStack['days'] = lang('Please select the number of days to wait between responses').'!';
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
if(is_array($_vacation['addresses']) && !empty($_vacation['addresses']))
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
$regexp="/^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}$/i";
foreach ($_vacation['addresses'] as $addr)
{
if (!preg_match($regexp,$addr) && $_checkAddresses)
{
$this->errorStack['addresses'] = lang('One address is not valid').'!';
}
}
2013-07-25 17:48:18 +02:00
}
else
{
2013-08-09 19:47:53 +02:00
$this->errorStack['addresses'] = lang('Please select a address').'!';
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
if ($_vacation['status'] == 'by_date')
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
if (!$_vacation['start_date'] || !$_vacation['end_date'])
{
$this->errorStack['status'] = lang('Activating by date requires a start- AND end-date!');
}
elseif($_vacation['start_date'] > $_vacation['end_date'])
{
$this->errorStack['status'] = lang('Vacation start-date must be BEFORE the end-date!');
}
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
if ($_vacation['forwards'])
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
foreach(preg_split('/, ?/',$_vacation['forwards']) as $addr)
{
if (!preg_match($regexp,$addr) && $_checkAddresses)
{
$this->errorStack['forwards'] = lang('One address is not valid'.'!');
}
}
2013-07-25 17:48:18 +02:00
}
//error_log(__METHOD__. array2string($this->errorStack));
2013-08-09 19:47:53 +02:00
if(count($this->errorStack) == 0)
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
return true;
2013-07-25 17:48:18 +02:00
}
else
{
2013-08-09 19:47:53 +02:00
$this->errorStack['message'] = lang('Vacation notice is not saved yet! (But we filled in some defaults to cover some of the above errors. Please correct and check your settings and save again.)');
return false;
2013-07-25 17:48:18 +02:00
}
}
/**
* Move rule to an other position in list
*
* @param {array} $orders
2013-07-25 17:48:18 +02:00
*/
function ajax_moveRule($orders)
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
2014-05-13 09:54:42 +02:00
foreach ($orders as $keys => $val)
{
$orders[$keys] = $val -1;
2014-05-13 09:54:42 +02:00
}
2013-07-25 17:48:18 +02:00
$this->getRules(null);
$newrules = $this->rules;
2014-05-13 09:54:42 +02:00
2013-07-25 17:48:18 +02:00
foreach($orders as $keys => $ruleID)
{
$newrules[$keys] = $this->rules[$ruleID];
}
2013-08-09 19:47:53 +02:00
$this->rules = $newrules;
2013-07-25 17:48:18 +02:00
$this->updateScript();
$this->saveSessionData();
2013-08-09 19:47:53 +02:00
//Calling to referesh after move action
$response = egw_json_response::get();
2014-05-13 09:54:42 +02:00
$response->call('app.mail.sieve_refresh');
2013-08-09 19:47:53 +02:00
}
/**
* Ajax function to handle actions over sieve rules list on gd
2013-07-25 17:48:18 +02:00
*
* @param string $action name of action
* @param string $checked the selected rule id
* @param string $msg containing the message comming from the client-side
*
2013-07-25 17:48:18 +02:00
*/
function ajax_action($action, $checked, $msg)
2013-07-25 17:48:18 +02:00
{
2013-08-09 19:47:53 +02:00
$this->getRules(null);
2013-07-25 17:48:18 +02:00
switch ($action)
{
case 'delete':
2013-08-09 19:47:53 +02:00
if ($checked === count($this->rules)-1)
{
$msg = lang('rule with priority ') . $checked . lang(' deleted!');
}
else
2013-08-09 19:47:53 +02:00
{
$msg = lang('rule with priority ') . $checked . lang(' deleted!') . lang(' And the rule with priority %1, now got the priority %2',$checked+1,$checked);
}
2013-07-25 17:48:18 +02:00
unset($this->rules[$checked]);
$this->rules = array_values($this->rules);
break;
case 'enable':
2013-08-09 19:47:53 +02:00
$msg = lang('rule with priority ') . $checked . lang(' enabled!');
2013-07-25 17:48:18 +02:00
$this->rules[$checked][status] = 'ENABLED';
break;
case 'disable':
2013-08-09 19:47:53 +02:00
$msg = lang('rule with priority ') . $checked . lang(' disabled!');
2013-07-25 17:48:18 +02:00
$this->rules[$checked][status] = 'DISABLED';
break;
2013-08-09 19:47:53 +02:00
case 'move':
break;
2013-07-25 17:48:18 +02:00
}
2013-08-09 19:47:53 +02:00
ob_start();
$result = $this->updateScript();
$response = egw_json_response::get();
if($result)
{
$response->error($result);
return;
}
2013-07-25 17:48:18 +02:00
$this->saveSessionData();
$response->call('app.mail.sieve_refresh');
2013-08-09 19:47:53 +02:00
}
2013-07-25 17:48:18 +02:00
/**
2013-08-09 19:47:53 +02:00
* Convert an script seive format rule to human readable format
2013-07-25 17:48:18 +02:00
*
* @param {array} $rule Array of rules
* @return {string} return the rule as a string.
2013-07-25 17:48:18 +02:00
*/
function buildRule($rule)
{
$andor = ' '. lang('and') .' ';
$started = 0;
2014-05-13 09:54:42 +02:00
if ($rule['anyof'])
{
$andor = ' '. lang('or') .' ';
}
2013-07-25 17:48:18 +02:00
$complete = lang('IF').' ';
2014-05-13 09:54:42 +02:00
if ($rule['unconditional'])
{
$complete = "[Unconditional] ";
}
2013-07-25 17:48:18 +02:00
if ($rule['from'])
{
$match = $this->setMatchType($rule['from'],$rule['regexp']);
$complete .= "'From:' " . $match . " '" . $rule['from'] . "'";
$started = 1;
}
if ($rule['to'])
{
2014-05-13 09:54:42 +02:00
if ($started)
{
$complete .= $andor;
}
2013-07-25 17:48:18 +02:00
$match = $this->setMatchType($rule['to'],$rule['regexp']);
$complete .= "'To:' " . $match . " '" . $rule['to'] . "'";
$started = 1;
}
if ($rule['subject'])
{
2014-05-13 09:54:42 +02:00
if ($started)
{
$complete .= $andor;
}
2013-07-25 17:48:18 +02:00
$match = $this->setMatchType($rule['subject'],$rule['regexp']);
$complete .= "'Subject:' " . $match . " '" . $rule['subject'] . "'";
$started = 1;
}
if ($rule['field'] && $rule['field_val'])
{
2014-05-13 09:54:42 +02:00
if ($started)
{
$complete .= $andor;
}
2013-07-25 17:48:18 +02:00
$match = $this->setMatchType($rule['field_val'],$rule['regexp']);
$complete .= "'" . $rule['field'] . "' " . $match . " '" . $rule['field_val'] . "'";
$started = 1;
}
if ($rule['size'])
{
$xthan = " less than '";
2014-05-13 09:54:42 +02:00
if ($rule['gthan'])
{
$xthan = " greater than '";
}
if ($started)
{
$complete .= $andor;
}
2013-07-25 17:48:18 +02:00
$complete .= "message " . $xthan . $rule['size'] . "KB'";
$started = 1;
}
if (!empty($rule['field_bodytransform']))
2013-08-09 19:47:53 +02:00
{
2014-05-13 09:54:42 +02:00
if ($started)
{
$newruletext .= ", ";
}
2013-08-09 19:47:53 +02:00
$btransform = " :raw ";
$match = ' :contains';
2014-05-13 09:54:42 +02:00
if ($rule['bodytransform'])
{
$btransform = " :text ";
}
if (preg_match("/\*|\?/", $rule['field_bodytransform']))
{
$match = ':matches';
}
if ($rule['regexp'])
{
$match = ':regex';
}
2013-08-09 19:47:53 +02:00
$complete .= " body " . $btransform . $match . " \"" . $rule['field_bodytransform'] . "\"";
$started = 1;
}
if ($rule['ctype']!= '0' && !empty($rule['ctype']))
2013-08-09 19:47:53 +02:00
{
2014-05-13 09:54:42 +02:00
if ($started)
{
$newruletext .= ", ";
}
2013-08-09 19:47:53 +02:00
$btransform_ctype = emailadmin_script::$btransform_ctype_array[$rule['ctype']];
$ctype_subtype = "";
2014-05-13 09:54:42 +02:00
if ($rule['field_ctype_val'])
{
$ctype_subtype = "/";
}
2013-08-09 19:47:53 +02:00
$complete .= " body :content " . " \"" . $btransform_ctype . $ctype_subtype . $rule['field_ctype_val'] . "\"" . " :contains \"\"";
$started = 1;
//error_log(__CLASS__."::".__METHOD__.array2string(emailadmin_script::$btransform_ctype_array));
}
2014-05-13 09:54:42 +02:00
if (!$rule['unconditional'])
{
$complete .= ' '.lang('THEN').' ';
}
2013-07-25 17:48:18 +02:00
if (preg_match("/folder/i",$rule['action']))
2014-05-13 09:54:42 +02:00
{
2013-07-25 17:48:18 +02:00
$complete .= lang('file into')." '" . $rule['action_arg'] . "';";
2014-05-13 09:54:42 +02:00
}
2013-07-25 17:48:18 +02:00
if (preg_match("/reject/i",$rule['action']))
2014-05-13 09:54:42 +02:00
{
2013-07-25 17:48:18 +02:00
$complete .= lang('reject with')." '" . $rule['action_arg'] . "'.";
2014-05-13 09:54:42 +02:00
}
2013-07-25 17:48:18 +02:00
if (preg_match("/address/i",$rule['action']))
2014-05-13 09:54:42 +02:00
{
2013-07-25 17:48:18 +02:00
$complete .= lang('forward to').' ' . $rule['action_arg'] .'.';
2014-05-13 09:54:42 +02:00
}
2013-07-25 17:48:18 +02:00
if (preg_match("/discard/i",$rule['action']))
2014-05-13 09:54:42 +02:00
{
2013-07-25 17:48:18 +02:00
$complete .= lang('discard').'.';
2014-05-13 09:54:42 +02:00
}
if ($rule['continue'])
{
$complete .= " [Continue]";
}
if ($rule['keep'])
{
$complete .= " [Keep a copy]";
}
2013-07-25 17:48:18 +02:00
return $complete;
}
/**
* Helper function to find the type of content
2013-07-25 17:48:18 +02:00
*
* @param {string} $matchstr string that should be compared
* @param {string} $regex regular expresion as pattern to be matched
* @return {string} return the type
2013-07-25 17:48:18 +02:00
*/
function setMatchType (&$matchstr, $regex = false)
{
$match = lang('contains');
if (preg_match("/^\s*!/", $matchstr))
2014-05-13 09:54:42 +02:00
{
$match = lang('does not contain');
}
if (preg_match("/\*|\?/", $matchstr))
{
$match = lang('matches');
if (preg_match("/^\s*!/", $matchstr))
{
2014-05-13 09:54:42 +02:00
$match = lang('does not match');
}
2014-05-13 09:54:42 +02:00
}
if ($regex)
2013-07-25 17:48:18 +02:00
{
2014-05-13 09:54:42 +02:00
$match = lang('matches regexp');
if (preg_match("/^\s*!/", $matchstr))
2013-07-25 17:48:18 +02:00
{
2014-05-13 09:54:42 +02:00
$match = lang('does not match regexp');
2013-07-25 17:48:18 +02:00
}
}
2014-05-13 09:54:42 +02:00
if ($regex && preg_match("/^\s*\\\\!/", $matchstr))
{
$matchstr = preg_replace("/^\s*\\\\!/","!",$matchstr);
}
else
{
$matchstr = preg_replace("/^\s*!/","",$matchstr);
}
return $match;
2013-07-25 17:48:18 +02:00
}
/**
2013-08-09 19:47:53 +02:00
* Save session data
2013-07-25 17:48:18 +02:00
*/
function saveSessionData()
{
$sessionData['sieve_rules'] = $this->rules;
$sessionData['sieve_rulesByID'] = $this->rulesByID;
$sessionData['sieve_scriptToEdit'] = $this->scriptToEdit;
$GLOBALS['egw']->session->appsession('sieve_session_data','',$sessionData);
}
/**
2013-08-09 19:47:53 +02:00
* Update the sieve script on mail server
2013-07-25 17:48:18 +02:00
*/
function updateScript()
{
if (!$this->account->imapServer()->setRules($this->rules))
2013-07-25 17:48:18 +02:00
{
return "update failed";
2013-07-25 17:48:18 +02:00
}
}
/**
* Fetched rules save on array()rules.
*
* @param {string} $ruleID Numeric Id of the rule if specify return the specitic rule| otherwise ruleByID would be null
*
* @return {boolean} returns false in case of failure and true in case of success.
2013-07-25 17:48:18 +02:00
*/
function getRules($ruleID = null)
2013-07-25 17:48:18 +02:00
{
try {
$this->account->imapServer()->retrieveRules();
$this->rules = $this->account->imapServer()->getRules();
$this->rulesByID = $this->rules[$ruleID];
$this->vacation = $this->account->imapServer()->getVacation();
2013-07-25 17:48:18 +02:00
}
catch(Exception $e) {
error_log(__METHOD__.__LINE__.$e->getMessage().': '.$e->details);
$this->rules = array();
$this->rulesByID = array();
$this->vacation = array();
return false;
}
return true;
2013-07-25 17:48:18 +02:00
}
/**
2013-08-09 19:47:53 +02:00
* Restore session data
2013-07-25 17:48:18 +02:00
*/
function restoreSessionData()
{
$sessionData = $GLOBALS['egw']->session->appsession('sieve_session_data');
$this->rules = $sessionData['sieve_rules'];
$this->rulesByID = $sessionData['sieve_rulesByID'];
$this->scriptToEdit = $sessionData['sieve_scriptToEdit'];
}
/**
*
2013-08-09 19:47:53 +02:00
* Get the data for iterating the rows on rules list grid
*
* @return {boolean|array} Array of rows | false if failed
2013-07-25 17:48:18 +02:00
*/
function get_rows()
2013-07-25 17:48:18 +02:00
{
$rows = array();
$this->getRules(null);
2013-07-25 17:48:18 +02:00
if (is_array($this->rules) && !empty($this->rules) )
{
$rows = $this->rules;
foreach ($rows as &$row )
{
$row['rules'] = $this->buildRule($row);
$row['ruleID'] =(string)(($row['priority'] -1) / 2 );
if ($row ['status'] === 'DISABLED')
2013-07-25 17:48:18 +02:00
{
$row['class'] = 'mail_sieve_DISABLED';
2013-07-25 17:48:18 +02:00
}
}
}
else
2013-07-25 17:48:18 +02:00
{
//error_log(__METHOD__.'There are no rules or something is went wrong at getRules()!');
return false;
2013-07-25 17:48:18 +02:00
}
// Shift one down, because in grid the first row is reserved for header
2013-07-25 17:48:18 +02:00
array_unshift($rows,array(''=> ''));
return $rows;
}
/**
* Get actions / context menu for index
*
* @return {array} returns defined actions as an array
2013-07-25 17:48:18 +02:00
*/
private function get_actions()
2013-07-25 17:48:18 +02:00
{
$actions =array(
'edit' => array(
'caption' => 'Edit',
'default' => true,
'onExecute' => 'javaScript:app.mail.action',
'disableClass' => 'th'
2013-07-25 17:48:18 +02:00
),
'add' => array(
'caption' => 'Add',
'onExecute' => 'javaScript:app.mail.action'
),
'enable' => array(
'caption' => 'Enable',
'onExecute' => 'javaScript:app.mail.action',
'enableClass' => 'mail_sieve_DISABLED',
'hideOnDisabled' => true
2013-07-25 17:48:18 +02:00
),
'disable' => array(
'caption' => 'Disable',
'onExecute' => 'javaScript:app.mail.action',
'disableClass' => 'mail_sieve_DISABLED',
'hideOnDisabled' => true
2013-07-25 17:48:18 +02:00
),
'delete' => array(
'caption' => 'Delete',
'onExecute' => 'javaScript:app.mail.action'
),
);
return $actions;
}
/**
* Callback function to get mail folders
* int $_searchStringLength
* @param boolean $_returnList
* @param int $_mailaccountToSearch
* @param boolean $_noPrefixID = false, if set to true folders name does not get prefixed by account id
*/
function ajax_getFolders ($_searchStringLength=2, $_returnList=false, $_mailaccountToSearch=null, $_noPrefixId=false)
{
$mailCompose = new mail_compose();
if ($_REQUEST['noPrefixId']) $_noPrefixId = $_REQUEST['noPrefixId'];
$mailCompose->ajax_searchFolder($_searchStringLength, $_returnList, $_mailaccountToSearch, $_noPrefixId);
}
2013-07-25 17:48:18 +02:00
}
2014-05-13 09:54:42 +02:00