<?php
namespace App\Controller;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use OTPHP\TOTP;
use Endroid\QrCode\Builder\Builder;
use App\Form\LoginHistory;
use App\Form\QUser\AutoresponderForm;
use App\Form\QUser\AutoresponderAdvRulesForm;
use App\Form\QUser\ForwardMailEdit;
use App\Form\QUser\ForwardsMass;
use App\Form\QUser\Imap;
use App\Form\QUser\ImapMass;
use App\Form\QUser\NoticeSMS;
use App\Form\QUser\PasswordChange;
use App\Form\QUser\ForwardMail;
use App\Form\QUser\Procmail;
use App\Form\QUser\ProcmailMass;
use App\Form\QUser\Settings;
use App\Form\QUser\SpamAssassinLists;
use App\Form\QUser\SpamAssassinScore;
use App\Security\User;
use App\Util\AccountTools;
use App\Util\Api;
use App\Util\AppLogger;
use App\Util\TwoFactor;
use App\Model\Autoresponder;
use App\Model\Account;
use App\Form\QUser\SpamAssassinLocales;
use App\Model\LoginMessage;
use App\Model\ProcmailRule;
use App\Model\UserPref;
use App\Model\Qs;
use App\Model\ImapDir;
use App\Form\QUser\SpamAssassinListsMass;
use App\Form\QUser\AutomatedForward;
use App\Twig\AppExtension;
class QUserController extends AbstractController
{
private $logger;
private $translator;
private $security;
private $params;
private $session;
private $mailer;
private $skin;
private $requestStack;
private $appExtension;
public function __construct(AppLogger $logger, TranslatorInterface $translator, Security $security,
ParameterBagInterface $params, MailerInterface $mailer, RequestStack $requestStack,
AppExtension $appExtension)
{
$this->logger = $logger;
$this->translator = $translator;
$this->security = $security;
$this->params = $params;
$this->mailer = $mailer;
$this->requestStack = $requestStack;
$this->appExtension = $appExtension;
$this->session = $this->requestStack->getSession();
$this->_isReloadNeeded();
$defaultSkin = 'raw';
if(isset($_SERVER['DEFAULT_SKIN'])) {
$defaultSkin = $_SERVER['DEFAULT_SKIN'];
}
$user = $this->security->getUser();
$account = $user ? $user->getAccount() : null;
if(!is_null($account)) { // may be null for superadmin
$this->skin = $account->findSOption('cfgSkin') == null ? $defaultSkin : $account->findSOption('cfgSkin');
}
else {
$this->skin = $defaultSkin;
}
QUserController::overwriteEnvs();
}
public static function overwriteEnvs()
{
// maybe we need to overwrite some envs
$license = Api::getLicense();
if(array_key_exists('envs', $license) && (count($license['envs']) > 0)) {
foreach($license['envs'] as $e) {
$eArr = explode('=', $e);
if(count($eArr) != 2) {
continue;
}
$_SERVER[$eArr[0]] = $eArr[1];
}
}
}
/**
* @Route("/panel", name="qu_main")
*/
public function index(Request $request)
{
$locale = $this->requestStack->getSession()->get(User::LOCALE_SESSION_NAME);
$account = $this->security->getUser()->getAccount();
try {
$version = Api::getVersion();
}
catch(\Exception $e) {
$this->logger->log('Api::getVersion() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical getting API version, contact administrator.'));
return $this->redirectToRoute("app_login");
}
$modal = null;
$showModal = false;
if(!$this->session->get('modalShown', false)) {
$msgs = Api::listLoginMessages($account);
$this->session->set('modalShown', true);
if(count($msgs) > 0) {
$showModal = true;
$modal = $msgs[0];
// dismissing if must be shown only once
if($modal->getMessageTrigger() == LoginMessage::MESSAGE_TRIGGER_AT_FIRST_LOGIN) {
Api::loginMessageDismiss($account, $modal->getId());
}
}
}
$showVersionWarning = true;
if(isset($_SERVER['APP_USERPANEL_SHOW_VERSION_WARNING']) && $_SERVER['APP_USERPANEL_SHOW_VERSION_WARNING'] == 'false') {
$showVersionWarning = false;
}
$response = $this->render('skins/' . $this->skin . '/q_user/index.html.twig', [
'apiVersion' => $version,
'appVersion' => $this->params->get('app.version.panel'),
'showVersionWarning' => $showVersionWarning,
'showModal' => $showModal,
'modal' => $modal,
]);
if($locale != null && $locale != "") {
// save cookie with locales
$cookie = Cookie::create(User::LOCALE_COOKIE_NAME, $locale, time() + 24*7*3600, '/');
$response->headers->setCookie($cookie);
}
return $response;
}
/**
* password change
* @Route("/panel/password", name="qu_password")
*/
public function password(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
// access to this module
$this->denyAccessUnlessGranted('PASSWORD_CHANGE', $account);
$this->denyAccessUnlessGranted('EDIT', $account);
$form = $this->createForm(PasswordChange::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
try {
// check if provided password matches user current password
if(!Api::checkPassword($user->getUserNamePart(), $user->getUserDomainPart(), $form->get('oldPassword')->getData())) {
$this->addFlash('error', $this->translator->trans('Wrong current password. Password NOT changed'));
return $this->render('skins/' . $this->skin . '/q_user/password.html.twig', [
'form' => $form->createView(),
'userEmail' => $user->getEmail(),
]);
}
// check if new password is different than the old one
if($form->get('oldPassword')->getData() == $form->get('newPassword')->getData()) {
$this->addFlash('error', $this->translator->trans('New password is the same as current password. Password NOT changed'));
return $this->render('skins/' . $this->skin . '/q_user/password.html.twig', [
'form' => $form->createView(),
'userEmail' => $user->getEmail(),
]);
}
if(Api::changePassword($user->getUserNamePart(), $user->getUserDomainPart(), $form->get('newPassword')->getData())) {
$this->addFlash('notice', $this->translator->trans('Password changed'));
$this->logger->log('Password change', $request);
//$request->getSession()->set('storedPassword', AccountTools::encryptString($form->get('newPassword')->getData()));
$this->requestStack->getSession()->set('storedPassword', AccountTools::encryptString($form->get('newPassword')->getData()));
if(!AccountTools::callExternalScript($user->getUserNamePart(), $user->getUserDomainPart(), 'quser', 'pwchange', $form->get('newPassword')->getData())) {
$this->logger->log('Calling external script failed for changing password for an account', $request, ['accountName' => $user->getUserName()]);
}
return $this->redirectToRoute('qu_password');
}
else {
$this->addFlash('error', $this->translator->trans('Password NOT changed - error'));
}
}
catch(\Exception $e) {
$this->logger->log('Api::changePassword() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error changing password, contact administrator.'));
return $this->redirectToRoute("qu_main");
}
}
elseif($form->isSubmitted() && !$form->isValid()){
$errorStr = '';
$num = 1;
$errorsCnt = count($form->getErrors(true));
foreach($form->getErrors(true) as $e) {
$errorStr .= ($errorsCnt > 1 ? $num . '. ' : '') . lcfirst($e->getMessage()) . ' ';
$num = $num + 1;
}
$errorStr = rtrim($errorStr);
$this->addFlash('error', $this->translator->trans('Password NOT changed') . ': '.$errorStr,'');
}
return $this->render('skins/' . $this->skin . '/q_user/password.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @Route("/panel/forward/{orderDir}", defaults={"orderDir"="asc"}, name="qu_forward", requirements={"orderDir"="asc|desc"})
*/
public function forwarding($orderDir, Request $request, ValidatorInterface $validator, PaginatorInterface $paginator)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
$pagination = $account->findSOption('cfgUserPagination') == null ?
(isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
: $account->findSOption('cfgUserPagination');
$formMass = $this->createForm(ForwardsMass::class);
$formAutomated = $this->createForm(AutomatedForward::class);
$form = $this->createForm(ForwardMail::class);
$form->handleRequest($request);
$forwardsErrors = [];
try {
$forwards = Api::getForwards($account);
$automated = Api::listAutomatedForwards($account);
if($orderDir == 'asc') {
sort($forwards);
}
else {
rsort($forwards);
}
$localForwarding = Api::getForwardLocal($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
try {
$disabledForwards = Api::getDisabledForwards($account);
if($orderDir == 'asc') {
sort($forwards);
}
else {
rsort($forwards);
}
}
catch(\Exception $e) {
$this->logger->log('Api::getDisabledForwards() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$maxForwards = $this->_maxForwards($account);
$maxExternalForwards = $this->_maxExternalForwards($account);
if(($maxForwards == -1) || ($maxExternalForwards == -1)) {
$this->addFlash('error', $this->translator->trans('Domain settings not available'));
$this->logger->log('Error while getting domain ' . $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
return $this->redirectToRoute('qp_main');
}
$procmailRulesCnt = $this->_numberProcmailRulesEmail($account);
$procmailRulesExternalCnt = $this->_numberProcmailRulesEmailExternal($account);
if($form->isSubmitted() && $form->isValid()) {
$alreadyExists = false;
$loopDetected = false;
$addresses = explode(',', $form->get('address')->getData());
$added = false;
$affected = [];
$faultyAddresses = [];
// first - checking existance & loops
foreach(array_unique($addresses) as $adr) {
$adr = trim($adr);
foreach($forwards as $f) {
if($adr == $f) {
$alreadyExists = true;
$forwardsErrors[] = $this->translator->trans('Already exists');
$faultyAddresses[] = $adr;
}
}
if(!$alreadyExists) {
if($adr == $user->getEmail()) {
$loopDetected = true;
$forwardsErrors[] = $this->translator->trans('Loop detected');
$faultyAddresses[] = $adr;
}
else {
$forwardsErrors[] = '';
}
}
}
if($alreadyExists || $loopDetected) {
if($alreadyExists) {
$this->addFlash('error', $this->translator->trans('Forwarding NOT set - already exists') . ': ' . implode(', ', $faultyAddresses));
}
else {
$this->addFlash('error', $this->translator->trans('Forwarding NOT set - loop detected') . ': ' . implode(', ', $faultyAddresses));
}
$mixedForwardsArr = self::_mixForwardsArrays($forwards, $disabledForwards, $orderDir);
return $this->_showForwardingTemplate($request, $form, $formMass, $formAutomated,
$paginator, $mixedForwardsArr, $pagination, $automated, $forwards, $procmailRulesCnt,
$localForwarding, $forwardsErrors, $orderDir, $maxForwards);
}
// check if limit of forwards is not exceeded
if((count($forwards) + count(array_unique($addresses)) + $procmailRulesCnt) > $maxForwards) {
$this->addFlash('error', $this->translator->trans('Forwarding NOT set - limit of forwards exceeded') . ' (' . $maxForwards . '). ' . $this->translator->trans('Forwards used in sorting') . ': ' . $procmailRulesCnt . '. ' . $this->translator->trans('Forwards used in forwarding') . ': ' . count($forwards));
$mixedForwardsArr = self::_mixForwardsArrays($forwards, $disabledForwards, $orderDir);
return $this->_showForwardingTemplate($request, $form, $formMass, $formAutomated,
$paginator, $mixedForwardsArr, $pagination, $automated, $forwards, $procmailRulesCnt,
$localForwarding, $forwardsErrors, $orderDir, $maxForwards);
}
// check if limit of external forwards is not exceeded
$externalForwardsCnt = $this->_externalForwardsCount($forwards, $user->getAccount());
$externalForwardsCurrentCnt = $externalForwardsCnt;
foreach(array_unique($addresses) as $adr) {
if(AccountTools::isEmailExternal($adr, [$user->getAccount()->getUserDomain()])) {
$externalForwardsCurrentCnt++;
}
}
if(($externalForwardsCurrentCnt + $procmailRulesExternalCnt) > $maxExternalForwards) {
$this->addFlash('error', $this->translator->trans('Forwarding NOT set - limit of external forwards exceeded') . ' (' . $maxExternalForwards . '). ' . $this->translator->trans('External forwards used in sorting') . ': ' . $procmailRulesExternalCnt . '. ' . $this->translator->trans('External forwards used in forwarding') . ': ' . $externalForwardsCnt);
$mixedForwardsArr = self::_mixForwardsArrays($forwards, $disabledForwards, $orderDir);
return $this->_showForwardingTemplate($request, $form, $formMass, $formAutomated,
$paginator, $mixedForwardsArr, $pagination, $automated, $forwards, $procmailRulesCnt,
$localForwarding, $forwardsErrors, $orderDir, $maxForwards);
}
foreach(array_unique($addresses) as $adr) {
$adr = trim($adr);
if(Api::addForward($account, $adr)) {
$added = true;
$affected[] = $adr;
}
}
if($added) {
$this->addFlash('notice', $this->translator->trans('Forwarding set'));
$this->addFlash('rowsAffected', implode(':', $affected)); // highlight the last one
$this->logger->log('New forward(s) added', $request, ['forward' => implode(', ', $affected)]);
}
else {
$this->addFlash('error', $this->translator->trans('Forwarding NOT set'));
}
return $this->redirectToRoute('qu_forward');
}
elseif($form->isSubmitted() && !$form->isValid()) {
$errors = $form['address']->getErrors();
// there are errors in address field
// check which one is problematic
if(count($errors)) {
$checkAccount = new Account();
foreach(explode(',', $form->get('address')->getData()) as $usernameDomain) {
$nameDomainArr = explode('@', $usernameDomain);
if(count($nameDomainArr) == 1) {
// no domain
$forwardsErrors[] = $this->translator->trans("No domain");
}
else {
// check against validator
$checkAccount->setUserName($nameDomainArr[0]);
$checkAccount->setUserDomain($nameDomainArr[1]);
// allow 1 character usernames
if(strlen($nameDomainArr[0]) == 1) {
$checkAccount->setUserName($nameDomainArr[0] . $nameDomainArr[0]);
}
$validationErrors = $validator->validate($checkAccount);
// check existance
$alreadyExists = false;
foreach($forwards as $f) {
if($usernameDomain == $f) {
$alreadyExists = true;
}
}
if(count($validationErrors)) {
$veStr = '';
foreach($validationErrors as $ve) {
$veStr .= $ve->getMessage() . ' | ';
}
if($alreadyExists) {
$veStr .= $this->translator->trans(' | Already exists');
}
$forwardsErrors[] = rtrim($veStr, ' | ');
}
else {
if($alreadyExists) {
$forwardsErrors[] = $this->translator->trans("Already exists");
}
else {
$forwardsErrors[] = "";
}
}
}
}
}
$this->addFlash('error', $this->translator->trans('Forwarding NOT set'));
}
$mixedForwardsArr = self::_mixForwardsArrays($forwards, $disabledForwards, $orderDir);
return $this->_showForwardingTemplate($request, $form, $formMass, $formAutomated,
$paginator, $mixedForwardsArr, $pagination, $automated, $forwards, $procmailRulesCnt,
$localForwarding, $forwardsErrors, $orderDir, $maxForwards);
}
private function _showForwardingTemplate($request, $form, $formMass, $formAutomated,
$paginator, $mixedForwardsArr, $pagination, $automated, $forwards, $procmailRulesCnt,
$localForwarding, $forwardsErrors, $orderDir, $maxForwards)
{
return $this->render('skins/' . $this->skin . '/q_user/forward.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'formAutomated' => $formAutomated->createView(),
'forwards' => $paginator->paginate(
$mixedForwardsArr, $request->query->getInt('page', 1), $pagination
),
'automatedForwards' => $automated,
'forwardsCount' => count($forwards) + $procmailRulesCnt,
'localForwarding' => $localForwarding,
'forwardsErrors' => $forwardsErrors,
'orderDir' => $orderDir,
'maxForwards' => $maxForwards,
]);
}
/**
* @Route("/panel/forward/mass", name="qu_forwards_mass")
*/
public function forwardingMassAction(Request $request) {
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
$form = $this->createForm(ForwardsMass::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$selected = $request->request->get('forwardMassCheckbox');
$actionFailed = false;
foreach($selected as $forward) {
if(!Api::deleteForward($account, $forward)) {
$actionFailed = true;
}
}
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('Forwards NOT deleted'));
$this->logger->log('Error while deleting forward(s) (mass action)', $request, ['forward' => implode(', ', $selected)]);
}
else {
$this->addFlash('notice', $this->translator->trans('All forwards successfuly deleted'));
$this->logger->log('Forward(s) deleted (mass action)', $request, ['forward' => implode(', ', $selected)]);
}
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
if(count($forwards) == 0) {
$this->logger->log('All forwards deleted, local delivery activated', $request);
$this->addFlash('notice', $this->translator->trans("You've removed all forwards, local delivery activated"));
}
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/forward/automated", name="qu_forwards_automated")
*/
public function automatedForwardingAction(Request $request) {
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
$form = $this->createForm(AutomatedForward::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$activeFrom = $form->get('activeFrom')->getData();
$activeFromHour = $form->get('activeFromHour')->getData();
$activeFromMinute = $form->get('activeFromMinute')->getData();
$activeTo = $form->get('activeTo')->getData();
$activeToHour = $form->get('activeToHour')->getData();
$activeToMinute = $form->get('activeToMinute')->getData();
$tsFrom = $activeFrom->getTimestamp() + $activeFromHour * 3600 + $activeFromMinute * 60;
$tsTo = $activeTo->getTimestamp() + $activeToHour * 3600 + $activeToMinute * 60;
$address = $form->get('address')->getData();
$activeOrDisabled = $form->get('settingActiveOrDisabled')->getData();
$ret = false;
if($activeOrDisabled == 'D') {
$ret = Api::addAutomatedForward($account, $address, 0, 0, $tsFrom, $tsTo);
}
else {
$ret = Api::addAutomatedForward($account, $address, $tsFrom, $tsTo, 0, 0);
}
if($ret == false) {
$this->addFlash('error', $this->translator->trans('Unknown error - automatic forward NOT set'));
$this->logger->log('Error while saving automated forward', $request, ['forward' => $address]);
}
else {
$this->addFlash('notice', $this->translator->trans('Automatic forward successfuly set'));
$this->logger->log('Automatic forward set', $request, ['forward' => $address]);
}
}
elseif($form->isSubmitted() && !$form->isValid()) {
$errors = $form['activeTo']->getErrors();
$msg = '';
foreach($errors as $e) {
$msg .= $e->getMessage();
$msg .= ' ';
}
$this->addFlash('error', $this->translator->trans('Automatic forward NOT set') . ': ' . $msg);
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/forward/edit/{forward}/{page}", defaults={"page"=1}, name="qu_forward_edit")
*/
public function forwardEdit($forward, Request $request, int $page)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
$form = $this->createForm(ForwardMailEdit::class);
$form->handleRequest($request);
if(!$form->isSubmitted()) {
$form->get('address')->setData($forward);
}
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwards() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
if($form->isSubmitted() && $form->isValid()) {
$alreadyExists = false;
$loopDetected = false;
if($forward == $form->get('address')->getData()) {
$this->addFlash('notice', $this->translator->trans('Forwarding not changed'));
return $this->redirectToRoute('qu_forward', ['page' => $page]);
}
foreach($forwards as $f) {
if($form->get('address')->getData() == $f) {
$alreadyExists = true;
}
}
if($alreadyExists) {
$this->addFlash('error', $this->translator->trans('Forwarding NOT changed - already exists'));
}
if($form->get('address')->getData() == $user->getEmail()) {
$this->addFlash('error', $this->translator->trans('Forwarding NOT set - loop detected'));
$loopDetected = true;
}
// check if limit of external forwards is not exceeded (if edit is from internal to external)
if(AccountTools::isEmailExternal($form->get('address')->getData(), [$account->getUserDomain()]) &&
!AccountTools::isEmailExternal($forward, [$account->getUserDomain()])
) {
$maxExternalForwards = $this->_maxExternalForwards($account);
if($maxExternalForwards == -1) {
$this->addFlash('error', $this->translator->trans('Domain settings not available'));
$this->logger->log('Error while getting domain ' . $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
return $this->redirectToRoute('qp_main');
}
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$externalForwardsCnt = $this->_externalForwardsCount($forwards, $account);
$externalRulesCnt = $this->_numberProcmailRulesEmailExternal($account);
if(($externalForwardsCnt + $externalRulesCnt) >= $maxExternalForwards) {
$this->addFlash('error', $this->translator->trans('Forwarding NOT changed - limit of maximum external forwards exceeded') . ' (' . $maxExternalForwards . ')');
return $this->render('skins/' . $this->skin . '/q_user/forward_edit.html.twig', [
'form' => $form->createView(),
'page' => $page,
]);
}
}
if(!$alreadyExists && !$loopDetected) {
if(Api::addForward($account, $form->get('address')->getData())) {
if(!Api::deleteForward($account, $forward)) {
$this->logger->log('error while deleting old forward', $request, ['forward' => urldecode($forward)]);
$this->addFlash('error', $this->translator->trans('Forward NOT deleted'));
}
$this->logger->log('Forward edited', $request, ['forwardOld' => urldecode($forward), 'forwardNew' => $form->get('address')->getData()]);
$this->addFlash('notice', $this->translator->trans('Forwarding changed'));
$this->addFlash('rowsAffected', $form->get('address')->getData());
return $this->redirectToRoute('qu_forward', ['page' => $page]);
}
else {
$this->addFlash('error', $this->translator->trans('Forwarding NOT changed'));
}
}
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Forwarding NOT changed'));
}
return $this->render('skins/' . $this->skin . '/q_user/forward_edit.html.twig', [
'form' => $form->createView(),
'page' => $page,
]);
}
/**
* @Route("/panel/forward/del/{forward}", name="qu_forward_del")
*/
public function forwardDel($forward, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
// first enable it to remove from disabled forwards table
Api::enableForward($account, $forward);
if(Api::deleteForward($account, $forward)) {
$this->logger->log('Forward deleted', $request, ['forward' => urldecode($forward)]);
$this->addFlash('notice', $this->translator->trans('Forward deleted'));
}
else {
$this->logger->log('Error while deleting forward', $request, ['forward' => urldecode($forward)]);
$this->addFlash('error', $this->translator->trans('Forward NOT deleted'));
}
if(!Api::deleteAutomatedForwardByAddress($account, $forward)) {
$this->logger->log('Error while deleting automated forwards', $request, ['forward' => urldecode($forward)]);
}
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
if(count($forwards) == 0) {
$this->logger->log('Last forward deleted, local delivery activated', $request);
$this->addFlash('notice', $this->translator->trans("You've removed last existing forward, local delivery activated"));
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/automatedforward/del/{id}", name="qu_automatedforward_del")
*/
public function automatedForwardDel($id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
if(Api::deleteAutomatedForward($account, $id)) {
$this->logger->log('Automated forward rule deleted', $request, ['id' => $id]);
$this->addFlash('notice', $this->translator->trans('Automated forward rule deleted'));
}
else {
$this->logger->log('Error while deleting automated forward', $request, ['id' => $id]);
$this->addFlash('error', $this->translator->trans('Automated forward rule NOT deleted'));
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/forward/disable/{forward}", name="qu_forward_disable")
*/
public function forwardDisable($forward, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
if(Api::disableForward($account, $forward)) {
$this->logger->log('Forward disabled', $request, ['forward' => urldecode($forward)]);
$this->addFlash('notice', $this->translator->trans('Forward disabled'));
}
else {
$this->logger->log('Error while disabling forward', $request, ['forward' => urldecode($forward)]);
$this->addFlash('error', $this->translator->trans('Forward NOT disabled'));
}
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardsl() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
if(count($forwards) == 0) {
$this->logger->log('Last forward disabled, local delivery activated', $request);
$this->addFlash('notice', $this->translator->trans("You've removed last existing forward, local delivery activated"));
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/forward/enable/{forward}", name="qu_forward_enable")
*/
public function forwardEnable($forward, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
// check limit
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::forwards() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$maxForwards = $this->_maxForwards($account);
$maxExternalForwards = $this->_maxExternalForwards($account);
if(($maxForwards == -1) || ($maxExternalForwards == -1)) {
$this->addFlash('error', $this->translator->trans('Domain settings not available'));
$this->logger->log('Error while getting domain ' . $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
return $this->redirectToRoute('qp_main');
}
$procmailRulesCnt = $this->_numberProcmailRulesEmail($account);
if((count($forwards) + 1 + $procmailRulesCnt) > $maxForwards) {
$this->addFlash('error', $this->translator->trans('Forward NOT enabled - limit of forwards exceeded') . ' (' . $maxForwards . '). ' . $this->translator->trans('Forwards used in sorting') . ': ' . $procmailRulesCnt . '. ' . $this->translator->trans('Forwards used in forwarding') . ': ' . count($forwards));
return $this->redirectToRoute('qu_forward');
}
if(Api::enableForward($account, $forward)) {
$this->logger->log('Forward enabled', $request, ['forward' => urldecode($forward)]);
$this->addFlash('notice', $this->translator->trans('Forward enabled'));
}
else {
$this->logger->log('Error while enabling forward', $request, ['forward' => urldecode($forward)]);
$this->addFlash('error', $this->translator->trans('Forward NOT enabled'));
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/forward/localon", name="qu_forward_local_on")
*/
public function forwardLocalOn(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
if(Api::forwardLocal($account, true)) {
$this->logger->log('Local forward activated', $request);
$this->addFlash('notice', $this->translator->trans('Local forward activated'));
}
else {
$this->addFlash('error', $this->translator->trans('Local forward NOT activated'));
}
// redirect to spamassassin main page or to a specific subpage
$referer = $request->headers->get('referer');
if(strlen($referer))
return $this->redirect($referer);
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/forward/localoff", name="qu_forward_local_off")
*/
public function forwardLocalOff(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('FORWARD', $account);
if(Api::forwardLocal($account, false)) {
$this->logger->log('Local forward desactivated', $request);
$this->addFlash('notice', $this->translator->trans('Local forward desactivated'));
}
else {
$this->addFlash('error', $this->translator->trans('Local forward NOT desactivated'));
}
return $this->redirectToRoute("qu_forward");
}
/**
* @Route("/panel/autoresponder", name="qu_autoresponder")
*/
public function autoresponder(Request $request)
{
$areAdvancedRulesAllowed = false;
if(isset($_SERVER['APP_ADV_AUTORESP_ALLOWED']) && ($_SERVER['APP_ADV_AUTORESP_ALLOWED'] == 'true')) {
$areAdvancedRulesAllowed = true;
}
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
$autoresponderStatus = '';
$autoresponder = $this->_getAutoresponderForUser($account, $autoresponderStatus);
$advancedRulesNumber = 0;
if($areAdvancedRulesAllowed) {
if($autoresponderStatus != 'no') {
$rules = Api::getAutoresponderAdvRules($autoresponder->getId(), false);
$advancedRulesNumber = count($rules);
}
}
if($autoresponderStatus != 'no') {
$autorespFromRule = Api::isAutoresponderFromRule($autoresponder->getUserName(), $autoresponder->getUserDomain());
}
else {
$autorespFromRule = false;
}
$form = $this->createForm(AutoresponderForm::class, $autoresponder);
$form->handleRequest($request);
$needSetOwnPrefix = false; // do we need to show user's own subject input field
if(!$form->isSubmitted()) {
if($autoresponderStatus == 'no') {
if(isset($_SERVER['APP_AUTOOPT_TIMELIMIT'])) {
$timeLimit = (int)$_SERVER['APP_AUTOOPT_TIMELIMIT'];
}
else {
$timeLimit = 7 * 24 * 3600; // tydzień
}
$timeLimitArr = Autoresponder::timelimitSplit($timeLimit);
$form->get('periodWeeks')->setData($timeLimitArr['weeks']);
$form->get('periodDays')->setData($timeLimitArr['days']);
$form->get('periodHours')->setData($timeLimitArr['hours']);
$form->get('messagesLimit')->setData(isset($_SERVER['APP_AUTOOPT_MSGLIMIT']) ? $_SERVER['APP_AUTOOPT_MSGLIMIT'] : 1);
$form->get('copyLines')->setData(isset($_SERVER['APP_AUTOOPT_NUMLINES']) ? $_SERVER['APP_AUTOOPT_NUMLINES'] : 5);
if(isset($_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'])) {
// if it doesn't end with space, we need to add it to have a match with the form
if(substr($_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'], -1) == ' ') {
$prefixToSet = $_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'];
}
else {
$prefixToSet = $_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'] . ' ';
}
$form->get('subject')->setData($prefixToSet);
}
}
// dd($autoresponder);
// user's subject and prefix are kept in the same field in GUI (ownSubject) but not in Autoresponder object
// own subject is in Autoresponder::ownSubject field, own prefix in Autoresponder::subject
//
// if subject is empty it means user has his own subject - we have to manually change state of the select in GUI
if($autoresponder->getSubject() == '' && strlen($autoresponder->getOwnSubject()) > 0) {
$form->get('subject')->setData('own');
$needSetOwnPrefix = true;
}
elseif($autoresponder->getSubject() != '') {
$needSetOwnPrefix = true;
// if user has his own prefix we have to detect it and manually change state of the select in GUI
// so if the object's subject is not one of the choices it must be own prefix
foreach(AutoresponderForm::getSubjectChoices() as $v) {
if($autoresponder->getSubject() == $this->translator->trans($v)) {
$needSetOwnPrefix = false;
break;
}
}
if($needSetOwnPrefix) {
$form->get('ownSubject')->setData($autoresponder->getSubject());
$form->get('subject')->setData('ownPrefix');
}
}
}
if($form->isSubmitted() && $form->isValid()) {
$autoresponder->setUserName($account->getUserName());
$autoresponder->setUserDomain($account->getUserDomain());
if(Api::addAutoresponder($autoresponder)) {
if($autoresponderStatus == 'no') {
$this->logger->log('New autoresponder added', $request);
}
else {
$this->logger->log('Autoresponder changed', $request);
}
$this->addFlash('notice', $this->translator->trans('Autoresponder set'));
if($autoresponder->getActivationType() == 'auto') {
$now = new \DateTime("now");
//$now->setTime(0, 0, 0);
if(($autoresponderStatus == 'inactive' || $autoresponderStatus == 'no') &&
($autoresponder->getActiveFromWithMinutes() <= $now) && ($autoresponder->getActiveToWithMinutes() >= $now)) {
return $this->redirectToRoute('qu_autoresponder_activate');
}
if(($autoresponderStatus == 'active') &&
(($autoresponder->getActiveFromWithMinutes() > $now) || ($autoresponder->getActiveToWithMinutes() < $now))) {
return $this->redirectToRoute('qu_autoresponder_desactivate');
}
}
return $this->redirectToRoute('qu_autoresponder');
}
else {
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set'));
}
return $this->redirectToRoute('qu_autoresponder');
}
elseif($form->isSubmitted() && !$form->isValid()){
if(count($form['ownSubject']->getErrors()) > 0) {
$needSetOwnPrefix = true;
}
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set'));
}
return $this->render('skins/' . $this->skin . '/q_user/autoresponder.html.twig', [
'form' => $form->createView(),
'autoresponderStatus' => $autoresponderStatus,
'autoresponder' => $autoresponder,
'setOwnPrefix' => $needSetOwnPrefix,
'autoresponderFromRule' => $autorespFromRule,
'advancedRulesNumber' => $advancedRulesNumber,
]);
}
/**
* @Route("/panel/autoresponder/activate", name="qu_autoresponder_activate")
*/
public function autoresponderActivate(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
try {
$autoresponder = Api::getAutoresponder(Autoresponder::NOT_ACTIVE_PREFIX . $account->getUserName(),
Autoresponder::NOT_ACTIVE_PREFIX . $account->getUserDomain());
}
catch(\Exception $e) {
$this->logger->log('Trying to set active not existing autoresponder', $request);
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set active'));
return $this->redirectToRoute('qu_autoresponder');
}
try {
Api::activateAutoresponder($autoresponder);
$this->logger->log('Autoresponder activated', $request);
}
catch(\Exception $e) {
$this->logger->log('Error while setting autoresponder active', $request);
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set active'));
return $this->redirectToRoute('qu_autoresponder');
}
$this->addFlash('notice', $this->translator->trans('Autoresponder set active'));
return $this->redirectToRoute('qu_autoresponder');
}
/**
* @Route("/panel/autoresponder/desactivate", name="qu_autoresponder_desactivate")
*/
public function autoresponderDesactivate(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
try {
$autoresponder = Api::getAutoresponder($account->getUserName(), $account->getUserDomain());
}
catch(\Exception $e) {
$this->logger->log('Trying to set inactive not existing autoresponder', $request);
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set inactive'));
return $this->redirectToRoute('qu_autoresponder');
}
try {
Api::desactivateAutoresponder($autoresponder);
$this->logger->log('Autoresponder desactivated', $request);
}
catch(\Exception $e) {
$this->logger->log('Error while setting autoresponder inactive', $request);
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set inactive'));
return $this->redirectToRoute('qu_autoresponder');
}
$this->addFlash('notice', $this->translator->trans('Autoresponder set inactive'));
return $this->redirectToRoute('qu_autoresponder');
}
/**
* @Route("/panel/autoresponder/del", name="qu_autoresponder_del")
*/
public function autoresponderDelete(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
$autoresponderStatus = 'no';
$autoresponder = $this->_getAutoresponderForUser($account, $autoresponderStatus);
if($autoresponderStatus == 'active') {
// we should first make the autoresponder inactive
if(!Api::desactivateAutoresponder($autoresponder)) {
$this->logger->log('Error while trying to delete autoresponder - deactivation failed', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('Autoresponder NOT deleted'));
return $this->redirectToRoute('qu_autoresponder');
}
}
if($autoresponderStatus != 'no') {
if(Api::deleteAutoresponder($account)) {
$this->logger->log('Autoresponder deleted', $request);
// delete also advanced rules
Api::deleteAutoresponderAdvRulesForUser($account);
// delete copy of the autoresponder
Api::deleteAutoresponderCopy($account);
$this->addFlash('notice', $this->translator->trans('Autoresponder deleted'));
}
else {
$this->logger->log('Error while trying to delete autoresponder', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('Autoresponder NOT deleted'));
}
}
else {
$this->logger->log('Error while trying to delete not existing autoresponder', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('Autoresponder NOT deleted'));
}
return $this->redirectToRoute('qu_autoresponder');
}
/**
* @Route("/panel/autoresponder/recipients", name="qu_autoresponder_recipients")
*/
public function autoresponderRecipients(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
$autoresponderStatus = '';
$autoresponder = $this->_getAutoresponderForUser($account, $autoresponderStatus);
$recipients = [];
if($autoresponderStatus != 'no') {
try {
$recipients = Api::getAutoresponderRecipients($autoresponder->getId(), $autoresponder->timeLimit());
}
catch(\Exception $e) {
$this->logger->log('Error while getting autoresponder recipients', $request);
$this->addFlash('error', $this->translator->trans('Error while loading autoresponder recipients'));
return $this->redirectToRoute('qu_autoresponder');
}
}
return $this->render('skins/' . $this->skin . '/q_user/autoresponder_recipients.html.twig', [
'recipients' => $recipients,
'autoresponder' => $autoresponder,
]);
}
/**
* @Route("/panel/autoresponder/delrcpt/{rcpt}", name="qu_autoresponder_del_rcpt")
*/
public function autoresponderDeleteRecipient(String $rcpt, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
$autoresponderStatus = '';
$autoresponder = $this->_getAutoresponderForUser($account, $autoresponderStatus);
if($autoresponderStatus == 'no') {
$this->logger->log('Error while getting autoresponder for deleting recipient', $request, ['rcpt' => $rcpt]);
$this->addFlash('error', $this->translator->trans('Error while loading autoresponder'));
return $this->redirectToRoute('qu_autoresponder');
}
if(Api::deleteAutoresponderRecipients($autoresponder->getId(), $rcpt)) {
$this->logger->log('Autoresponder recipient deleted', $request, ['rcpt' => $rcpt]);
$this->addFlash('notice', $this->translator->trans('Autoresponder\'s recipient deleted'));
}
else {
$this->logger->log('Error while trying to delete autoresponder\'s recipient', $request, ['rcpt' => $rcpt], 'critical');
$this->addFlash('error', $this->translator->trans('Autoresponder\'s recipient NOT deleted'));
}
return $this->redirectToRoute('qu_autoresponder_recipients');
}
/**
* @Route("/panel/autoresponder/advrules", name="qu_autoresponder_adv_rules")
*/
public function autoresponderAdvancedRules(Request $request)
{
if(!isset($_SERVER['APP_ADV_AUTORESP_ALLOWED'])) {
exit;
}
if(isset($_SERVER['APP_ADV_AUTORESP_ALLOWED']) && ($_SERVER['APP_ADV_AUTORESP_ALLOWED'] == 'false')) {
exit;
}
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('AUTORESPONDER', $account);
$autoresponderStatus = '';
$autoresponder = $this->_getAutoresponderForUser($account, $autoresponderStatus);
if($autoresponderStatus == 'no') {
return $this->redirectToRoute('qu_autoresponder');
}
$needSetOwnPrefix = false; // do we need to show user's own subject input field
$needSetOwnPrefixes = [];
$form = $this->createForm(AutoresponderAdvRulesForm::class, $autoresponder);
$form->handleRequest($request);
if(!$form->isSubmitted()) {
$rules = Api::getAutoresponderAdvRules($autoresponder->getId(), false);
$form->get('advRules')->setData($rules);
// now own subject / own prefix for each rule
foreach($rules as $rIdx => $r) {
// user's subject and prefix are kept in the same field in GUI (ownSubject) but not in Autoresponder object
// own subject is in Autoresponder::ownSubject field, own prefix in Autoresponder::subject
//
// if subject is empty it means user has his own subject - we have to manually change state of the select in GUI
if($r['subject'] == '' && strlen($r['ownSubject']) > 0) {
foreach($form->get('advRules')->all() as $childName => $childForm) {
if($childName == $rIdx) {
$childForm->get('subject')->setData('own');
}
}
$needSetOwnPrefix = true;
}
elseif($r['subject'] != '') {
$needSetOwnPrefix = true;
// if user has his own prefix we have to detect it and manually change state of the select in GUI
// so if the object's subject is not one of the choices it must be own prefix
foreach(AutoresponderForm::getSubjectChoices() as $v) {
if($r['subject'] == $this->translator->trans($v)) {
$needSetOwnPrefix = false;
break;
}
}
if($needSetOwnPrefix) {
foreach($form->get('advRules')->all() as $childName => $childForm) {
if($childName == $rIdx) {
$childForm->get('ownSubject')->setData($r['subject']);
$childForm->get('subject')->setData('ownPrefix');
}
}
}
}
$needSetOwnPrefixes[$rIdx] = $needSetOwnPrefix;
}
}
else {
if($form->isValid()) {
$autoresponder->setUserName($account->getUserName());
$autoresponder->setUserDomain($account->getUserDomain());
// delete rules that are no longer in form
$formData = $form->get('advRules')->getData();
$formDataIds = [];
foreach($formData as $row) {
$formDataIds[] = $row['id'];
}
$rules = Api::getAutoresponderAdvRules($autoresponder->getId(), false);
foreach($rules as $rule) {
if(!in_array($rule['id'], $formDataIds)) {
Api::deleteAutoresponderRule($rule['id']);
}
}
if(Api::addAutoresponderRules($autoresponder, $form->get('advRules')->getData())) {
if($autoresponderStatus == 'no') {
$this->logger->log('New autoresponder rule(s) added', $request);
}
else {
$this->logger->log('Autoresponder rule(s) changed', $request);
}
$this->addFlash('notice', $this->translator->trans('Autoresponder rules set'));
// check if there is no conflict in rules
$rules = Api::getAutoresponderAdvRules($autoresponder->getId(), false);
$activationTimeArr = [];
for($i = 0; $i < count($rules); $i++) {
if($rules[$i]['activeOnceConsumed']) {
continue;
}
$activationTime = $rules[$i]['activationHour'] * 60 + $rules[$i]['activationMinute'];
foreach($activationTimeArr as $k => $v) {
if($activationTime == $v) {
// time is the same
// now check the date
$theSameDay = false;
if(!$rules[$i]['activeOnce']) {
if($rules[$k]['activeOnce']) {
$dayOfWeekNumeric = $rules[$k]['activeOnceDate']->format('w');
// dd($dayOfWeekNumeric);
$activeDayVar = 'activeDay' . $dayOfWeekNumeric;
if($rules[$i][$activeDayVar] == true) {
$theSameDay = true;
}
}
else {
for($j = 1; $j < 8; $j++) {
$activeDayVar = 'activeDay' . $j;
if(($rules[$i][$activeDayVar] == true) && ($rules[$k][$activeDayVar] == true)) {
$theSameDay = true;
}
}
}
}
else {
// previous rule is activeOnce, checking one day of week
if($rules[$k]['activeOnce']) {
// is the same date?
if ($rules[$i]['activeOnceDate']->format('Y-m-d') === $rules[$k]['activeOnceDate']->format('Y-m-d')) {
$theSameDay = true;
}
}
else { // previous rule is not activeOnce
$dayOfWeekNumeric = $rules[$i]['activeOnceDate']->format('w');
$activeDayVar = 'activeDay' . $dayOfWeekNumeric;
if($rules[$k][$activeDayVar] == true) {
$theSameDay = true;
}
}
}
if($theSameDay) {
$this->addFlash('error', $this->translator->trans('Warning! Rules conflict. Rule number') . ' ' . ($i + 1) . ' ' . $this->translator->trans('with rule number') . ' ' . ($k + 1));
break;
}
}
}
$activationTimeArr[$i] = $activationTime;
}
return $this->redirectToRoute('qu_autoresponder_adv_rules');
}
else {
$this->addFlash('error', $this->translator->trans('Autoresponder NOT set'));
}
return $this->redirectToRoute('qu_autoresponder_adv_rules');
}
else {
echo "not valid"; exit;
}
}
return $this->render('skins/' . $this->skin . '/q_user/autoresponder_adv_rules.html.twig', [
'form' => $form->createView(),
'autoresponderStatus' => $autoresponderStatus,
'autoresponder' => $autoresponder,
'setOwnPrefixes' => $needSetOwnPrefixes,
// 'rules' -> $rules,
]);
}
/**
* @Route("/panel/spamassassin", name="qu_sa")
*/
public function spamAssassin(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$antispamOn = $this->_isAntispamOn($account);
return $this->render('skins/' . $this->skin . '/q_user/spamassassin.html.twig', [
'antispamOn' => $antispamOn,
]);
}
/**
* @Route("/panel/spamassassin/change_activity", name="qu_sa_change_activity")
*/
public function spamAssassinChangeActivity(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
if(Api::getSAProtection($account)) {
Api::saProtection($account, false);
$this->logger->log('Antispam protection desactivated', $request);
}
else {
Api::saProtection($account, true);
$this->logger->log('Antispam protection activated', $request);
}
// redirect to spamassassin main page or to a specific subpage
$referer = $request->headers->get('referer');
if(strlen($referer))
return $this->redirect($referer);
return $this->redirectToRoute('qu_sa');
}
/**
* @Route("/panel/spamassassin/score", name="qu_sa_score")
*/
public function spamAssassinScore(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$antispamOn = $this->_isAntispamOn($account);
$form = $this->createForm(SpamAssassinScore::class);
$form->handleRequest($request);
$saPref = null;
$qsPref = null;
try {
foreach(Api::getSAPrefVal($account, 'required_score') as $pref) {
$saPref = $pref;
break;
}
foreach(Api::getQS($account) as $pref) {
$qsPref = $pref;
break;
}
}
catch(\Exception $e) {}
if($saPref) {
$sliderRangeScoreVal = $saPref->getValue();
}
else {
$sliderRangeScoreVal = UserPref::DEFAULT_SPAM_SCORE;
}
$saMaxScore = $account->findSOption('cfgSAMaxScore') == null ? UserPref::SA_MAX_SCORE : $account->findSOption('cfgSAMaxScore');
$neverDelete = false;
if($qsPref) {
// these values are stored as delta - we have to add them to user's "score" value
$sliderRangeValMin = $qsPref->getQuarantine() + $sliderRangeScoreVal;
$prefix = $qsPref->getSubject();
// if getDel() is 0, it means "never delete" is enabled
if($qsPref->getDel() == 0) {
$neverDelete = true;
// don't set sliderRangeValMax, use max value instead
$sliderRangeValMax = $saMaxScore;
}
else {
$sliderRangeValMax = $qsPref->getDel() + $sliderRangeScoreVal;
}
// if given value is exactly less by 0.05 it means it is 0 but was written to the database this way
// because setting 0 switches off given funcionality completely
if($sliderRangeValMin + 0.05 == $sliderRangeScoreVal) {
$sliderRangeValMin = $sliderRangeScoreVal;
}
if(!$neverDelete && $sliderRangeValMax + 0.05 == $sliderRangeScoreVal) {
$sliderRangeValMax = $sliderRangeScoreVal;
}
}
else {
$sliderRangeValMin = UserPref::DEFAULT_QUARANTINE_THRESHOLD + $sliderRangeScoreVal;
$sliderRangeValMax = UserPref::DEFAULT_DELETE_THRESHOLD + $sliderRangeScoreVal;
$prefix = null;
}
if(!$form->isSubmitted()) {
$form->get('score')->setData($sliderRangeScoreVal);
$form->get('ok')->setData($sliderRangeScoreVal . ' - ' . $sliderRangeValMin);
$form->get('quarantine')->setData($sliderRangeValMin . ' - ' . $sliderRangeValMax);
$neverDeleteText = $this->translator->trans('NIGDY');
$form->get('delete')->setData($neverDelete ? $neverDeleteText : $sliderRangeValMax);
$form->get('neverDelete')->setData($neverDelete);
if($prefix != null) {
$form->get('prefix')->setData($prefix);
}
}
if($form->isSubmitted() && $form->isValid()) {
if($saPref == null) {
$saPref = new UserPref();
}
$saPref->setUsername($account->userAddress());
$saPref->setPreference('required_score');
$saPref->setValue($form->get('score')->getData());
try {
Api::saveUserPref($saPref);
}
catch(\Exception $e) {
$this->logger->log('Api::saveUserPref() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_score');
}
if($qsPref == null) {
$qsPref = new Qs();
}
$qsPref->setAddress($account->userAddress());
$valOK = explode(' - ', $form->get('ok')->getData());
$qsPref->setQuarantine($valOK[1] - $form->get('score')->getData());
// if "never delete" checkbox is checked, set del to 0
if($form->get('neverDelete')->getData()) {
$qsPref->setDel(0);
}
else {
$deleteValue = $form->get('delete')->getData();
$neverDeleteText = $this->translator->trans('NIGDY');
// if delete value is "NIGDY" (translated) or not numeric, use max value
if($deleteValue === $neverDeleteText || !is_numeric($deleteValue)) {
$deleteValue = $saMaxScore;
}
$qsPref->setDel($deleteValue - $form->get('score')->getData());
}
if($form->get('prefix')->getData() == null) {
$qsPref->setSubject('');
}
else {
$qsPref->setSubject($form->get('prefix')->getData());
}
// Qs default values
$scanners = 'clamdscan_scanner,sa,perlscan_scanner';
if(isset($_SERVER['APP_QS_SCANNERS'])) {
$scanners = $_SERVER['APP_QS_SCANNERS'];
}
$qsPref->setScanners($scanners);
$qsPref->setDelta(0);
$qsPref->setReject(0);
$qsPref->setForward('none');
$qsPref->setForwardVerbose(0);
$qsPref->setHdrReport(0);
$qsPref->setSpamdir('spam');
try {
Api::saveQs($qsPref);
}
catch(\Exception $e) {
$this->logger->log('Api::saveQs() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_score');
}
$this->addFlash('notice', $this->translator->trans('Antispam score saved'));
$this->logger->log('Autoresponder score settings saved', $request, ['prefix' => $form->get('prefix')->getData(),
'spam_threshold' => $form->get('score')->getData(), 'inbox_deliver_threshold' => $form->get('ok')->getData(),
'delete_threshold' => $form->get('delete')->getData()]);
return $this->redirectToRoute('qu_sa_score');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Antispam score NOT saved'));
}
$neverDeleteText = $this->translator->trans('NIGDY');
return $this->render('skins/' . $this->skin . '/q_user/spamassassin_score.html.twig', [
'form' => $form->createView(),
'antispamOn' => $antispamOn,
'sliderRangeScoreVal' => $sliderRangeScoreVal,
'sliderRangeValMin' => $sliderRangeValMin,
'sliderRangeValMax' => $sliderRangeValMax,
'sliderMaxConfig' => $saMaxScore,
'neverDelete' => $neverDelete,
'neverDeleteText' => $neverDeleteText,
]);
}
/**
* @Route("/panel/spamassassin/bwlists/{orderBy}/{orderDir}", defaults={"orderBy"="listType", "orderDir"="asc"}, name="qu_sa_bwlists", requirements={"orderBy"="listType|enableStatus|address|session"})
*/
public function spamAssassinLists($orderBy, $orderDir, Request $request, PaginatorInterface $paginator)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$antispamOn = $this->_isAntispamOn($account);
$pagination = $account->findSOption('cfgUserPagination') == null ?
(isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
: $account->findSOption('cfgUserPagination');
$form = $this->createForm(SpamAssassinLists::class);
$formMass = $this->createForm(SpamAssassinListsMass::class,
null, [
'action' => $this->generateUrl('qu_sa_bwlists_mass'),
]);
$form->handleRequest($request);
$prefs = [];
try {
foreach(Api::getSAPrefVal($account, 'whitelist_from') as $pref) {
$prefs[$pref->getPrefid()] = $pref;
}
foreach(Api::getSAPrefVal($account, '_NA_whitelist_from') as $pref) {
$prefs[$pref->getPrefid()] = $pref;
}
foreach(Api::getSAPrefVal($account, 'blacklist_from') as $pref) {
$prefs[$pref->getPrefid()] = $pref;
}
foreach(Api::getSAPrefVal($account, '_NA_blacklist_from') as $pref) {
$prefs[$pref->getPrefid()] = $pref;
}
}
catch(\Exception $e) {}
if($orderBy == 'listType' || $orderBy == 'enableStatus' || $orderBy == 'address') {
$this->session->set('app_user_sa_lists_order_by', $orderBy);
$this->session->set('app_user_sa_lists_order_dir', $orderDir);
}
if($orderBy == 'session') {
if($this->session->has('app_user_sa_lists_order_by')) {
$orderBy = $this->session->get('app_user_sa_lists_order_by');
$orderDir = $this->session->get('app_user_sa_lists_order_dir');
}
else {
$orderBy = 'listType';
$orderDir = 'asc';
}
}
if($orderBy == 'listType') {
if($orderDir == 'asc') {
uasort($prefs, '\App\Model\UserPref::cmpObjectsByPreference');
}
else {
uasort($prefs, '\App\Model\UserPref::cmpObjectsByPreferenceDesc');
}
}
else if($orderBy == 'enableStatus'){
if($orderDir == 'asc') {
uasort($prefs, '\App\Model\UserPref::cmpObjectsByEnableStatus');
}
else {
uasort($prefs, '\App\Model\UserPref::cmpObjectsByEnableStatusDesc');
}
}
else {
if($orderDir == 'asc') {
uasort($prefs, '\App\Model\UserPref::cmpObjectsByVal');
}
else {
uasort($prefs, '\App\Model\UserPref::cmpObjectsByValDesc');
}
}
if($form->isSubmitted() && $form->isValid()) {
// check if this entry
$saPref = new UserPref();
$saPref->setUsername($account->userAddress());
if($form->get('type')->getData() == 'w') {
$saPref->setPreference('whitelist_from');
}
else {
$saPref->setPreference('blacklist_from');
}
$saPref->setValue($form->get('address')->getData());
try {
if(Api::checkListExists($saPref)) {
$this->addFlash('error', $this->translator->trans('List item NOT added - already exists'));
return $this->render('skins/' . $this->skin . '/q_user/spamassassin_bwlists.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'antispamOn' => $antispamOn,
'prefs' => $prefs,
'orderDir' => $orderDir,
'orderBy' => $orderBy,
/*'prefs' => $paginator->paginate(
$prefs, $request->query->getInt('page', 1), $pagination
),*/
]);
}
}
catch(\Exception $e) {
$this->logger->log('Api::checkListExists() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
}
try {
Api::saveUserPref($saPref);
}
catch(\Exception $e) {
$this->logger->log('Api::saveUserPref() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_bwlists');
}
if($form->get('type')->getData() == 'w') {
$this->logger->log('Whitelist added ', $request, ['value' => $saPref->getValue()]);
}
else {
$this->logger->log('Blacklist added ', $request, ['value' => $saPref->getValue()]);
}
$this->addFlash('notice', $this->translator->trans('List item added'));
$this->addFlash('rowsAffected', -1); // highlight the last one
return $this->redirectToRoute('qu_sa_bwlists');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('List item NOT added'));
}
return $this->render('skins/' . $this->skin . '/q_user/spamassassin_bwlists.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'antispamOn' => $antispamOn,
'prefs' =>
$prefs,
'orderDir' => $orderDir,
'orderBy' => $orderBy,
/*'prefs' => $paginator->paginate(
$prefs, $request->query->getInt('page', 1), $pagination
),*/
]);
}
/**
* @Route("/panel/spamassassin/massbwlists", name="qu_sa_bwlists_mass")
*/
public function spamAssassinListsMassAction(Request $request) {
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$form = $this->createForm(SpamAssassinListsMass::class,
null, [
'action' => $this->generateUrl('qu_sa_bwlists_mass'),
]);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$actionType = $form->get('actionType')->getData();
$selected = $request->request->get('listsMassCheckbox');
$actionFailed = false;
$affectedArr = [];
foreach($selected as $id) {
try {
$pref = Api::getSAPrefById($id);
}
catch(\Exception $e) {
$this->logger->log('Error while trying to delete not existent SA list entry', $request, ['id' => $id], 'critical');
$actionFailed = true;
continue;
}
$this->denyAccessUnlessGranted('SPAMASSASSIN', $pref);
switch($actionType) {
case 'delete':
if(Api::deleteSAPref($pref->getPrefid())) {
$this->logger->log('Deleted SA list entry', $request, ['value' => $pref->getValue()]);
}
else {
$this->logger->log('Error while trying to delete SA list entry', $request, [], 'critical');
$actionFailed = true;
}
break;
case 'towhite':
if($pref->isEnabled()) {
$pref->setPreference('whitelist_from');
}
else {
$pref->setPreference('_NA_whitelist_from');
}
break;
case 'toblack':
if($pref->isEnabled()) {
$pref->setPreference('blacklist_from');
}
else {
$pref->setPreference('_NA_blacklist_from');
}
break;
case 'disable':
if(Api::disableSAPref($pref->getPrefid())) {
$this->logger->log('Disabled SA list entry', $request, ['value' => $pref->getValue()]);
}
else {
$this->logger->log('Error while trying to disable SA list entry', $request, [], 'critical');
$actionFailed = true;
}
break;
case 'enable':
if(Api::enableSAPref($pref->getPrefid())) {
$this->logger->log('Enabled SA list entry', $request, ['value' => $pref->getValue()]);
}
else {
$this->logger->log('Error while trying to enable SA list entry', $request, [], 'critical');
$actionFailed = true;
}
break;
}
if($actionType == 'towhite' || $actionType == 'toblack') {
try {
Api::saveUserPref($pref);
if($actionType == 'towhite') {
$this->logger->log('Changed SA list entry to whitelist', $request, ['value' => $pref->getValue()]);
}
else {
$this->logger->log('Changed SA list entry to blacklist', $request, ['value' => $pref->getValue()]);
}
}
catch(\Exception $e) {
$this->logger->log('Api::saveUserPref() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$actionFailed = true;
}
}
$affectedArr[] = $id;
}
switch($actionType) {
case 'delete':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL entries deleted'));
}
else {
$this->addFlash('notice', $this->translator->trans('All entries successfuly deleted'));
}
break;
case 'towhite':
case 'toblack':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL entries changed'));
}
else {
$this->addFlash('notice', $this->translator->trans('All entries successfuly changed'));
}
break;
case 'enable':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL entries enabled'));
}
else {
$this->addFlash('notice', $this->translator->trans('All entries successfuly enabled'));
}
break;
case 'disable':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL entries disabled'));
}
else {
$this->addFlash('notice', $this->translator->trans('All entries successfuly disabled'));
}
break;
}
$this->addFlash('rowsAffected', implode(':', $affectedArr));
}
return $this->redirectToRoute("qu_sa_bwlists");
}
/**
* @Route("/panel/spamassassin/bwlists/del/{id}", name="qu_sa_bwlists_del")
*/
public function spamassassinListsDelete(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
try {
$pref = Api::getSAPrefById($id);
}
catch(\Exception $e) {
$this->logger->log('Error while trying to delete not existent SA list entry', $request, ['id' => $id], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_bwlists');
}
$this->denyAccessUnlessGranted('SPAMASSASSIN', $pref);
if(Api::deleteSAPref($pref->getPrefid())) {
$this->logger->log('Deleted SA list entry', $request, ['value' => $pref->getValue(), 'type' => $pref->getPreference()]);
$this->addFlash('notice', $this->translator->trans('List item deleted'));
}
else {
$this->logger->log('Error while trying to delete SA list entry', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('List item NOT deleted'));
}
return $this->redirectToRoute('qu_sa_bwlists');
}
/**
* @Route("/panel/spamassassin/bwlists/enable/{id}", name="qu_sa_bwlists_enable")
*/
public function spamassassinListsEnable(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
try {
$pref = Api::getSAPrefById($id);
}
catch(\Exception $e) {
$this->logger->log('Error while trying to enable not existent SA list entry', $request, ['id' => $id], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_bwlists');
}
$this->denyAccessUnlessGranted('SPAMASSASSIN', $pref);
if(Api::enableSAPref($pref->getPrefid())) {
$this->logger->log('Enabled SA list entry', $request, ['value' => $pref->getValue(), 'type' => $pref->getPreference()]);
$this->addFlash('notice', $this->translator->trans('List item enabled'));
$this->addFlash('rowsAffected', $pref->getPrefid());
}
else {
$this->logger->log('Error while trying to enable SA list entry', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('List item NOT enabled'));
}
return $this->redirectToRoute('qu_sa_bwlists');
}
/**
* @Route("/panel/spamassassin/bwlists/disable/{id}", name="qu_sa_bwlists_disable")
*/
public function spamassassinListsDisable(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
try {
$pref = Api::getSAPrefById($id);
}
catch(\Exception $e) {
$this->logger->log('Error while trying to disable not existent SA list entry', $request, ['id' => $id], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_bwlists');
}
$this->denyAccessUnlessGranted('SPAMASSASSIN', $pref);
if(Api::disableSAPref($pref->getPrefid())) {
$this->logger->log('Disabled SA list entry', $request, ['value' => $pref->getValue(), 'type' => $pref->getPreference()]);
$this->addFlash('notice', $this->translator->trans('List item disabled'));
$this->addFlash('rowsAffected', $pref->getPrefid());
}
else {
$this->logger->log('Error while trying to disable SA list entry', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('List item NOT disabled'));
}
return $this->redirectToRoute('qu_sa_bwlists');
}
/**
* @Route("/panel/spamassassin/bwlists/edit/{id}/{page}/{orderBy}/{orderDir}", defaults={"page"=1, "orderBy"="listType", "orderDir"="asc"}, name="qu_sa_bwlists_edit")
*/
public function spamassassinListsEdit(int $id, Request $request, int $page, $orderBy, $orderDir)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$form = $this->createForm(SpamAssassinLists::class);
$form->handleRequest($request);
try {
$pref = Api::getSAPrefById($id);
}
catch(\Exception $e) {
$this->logger->log('Error while trying to edit not existent SA list entry', $request, ['id' => $id], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_bwlists');
}
$this->denyAccessUnlessGranted('SPAMASSASSIN', $pref);
if(!$form->isSubmitted()) {
if($pref->getPreference() == 'whitelist_from') {
$form->get('type')->setData('w');
}
else {
$form->get('type')->setData('b');
}
$form->get('address')->setData($pref->getValue());
}
if($form->isSubmitted() && $form->isValid()) {
$pref->setValue($form->get('address')->getData());
$pref->setPreference(($form->get('type')->getData() == 'w') ? 'whitelist_from' : 'blacklist_from');
try {
Api::saveUserPref($pref);
}
catch(\Exception $e) {
$this->logger->log('Api::saveUserPref() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_bwlists');
}
$this->addFlash('notice', $this->translator->trans('List item edited successfully'));
$this->addFlash('rowsAffected', $pref->getPrefid());
return $this->redirectToRoute('qu_sa_bwlists', ['page' => $page, 'orderBy' => $orderBy, 'orderDir' => $orderDir]);
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Procmail rule NOT saved'));
}
return $this->render('skins/' . $this->skin . '/q_user/spamassassin_bwlists_edit.html.twig', [
'form' => $form->createView(),
'page' => $page,
'orderBy' => $orderBy,
'orderDir' => $orderDir,
]);
}
/**
* @Route("/panel/spamassassin/langs", name="qu_sa_langs")
*/
public function spamAssassinLangs(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$antispamOn = $this->_isAntispamOn($account);
$form = $this->createForm(SpamAssassinLocales::class);
$form->handleRequest($request);
$saPref = new UserPref();
$saPref->setPreference('ok_locales');
$saPref->setUsername($account->useraddress());
try {
foreach(Api::getSAPrefVal($account, 'ok_locales') as $pref) {
$saPref = $pref;
break;
}
}
catch(\Exception $e) {}
if(!$form->isSubmitted()) {
if($saPref->getPrefid() == 0 || strpos($saPref->getValue(), 'all') !== false) {
$form->get('locale')->setData(['l_all', 'l_en', 'l_ja', 'l_ru', 'l_ko', 'l_th', 'l_zh']);
}
else {
$localeArr = [];
if(strpos($saPref->getValue(), 'en') !== false) {
$localeArr[] = 'l_en';
}
if(strpos($saPref->getValue(), 'ja') !== false) {
$localeArr[] = 'l_ja';
}
if(strpos($saPref->getValue(), 'ru') !== false) {
$localeArr[] = 'l_ru';
}
if(strpos($saPref->getValue(), 'ko') !== false) {
$localeArr[] = 'l_ko';
}
if(strpos($saPref->getValue(), 'th') !== false) {
$localeArr[] = 'l_th';
}
if(strpos($saPref->getValue(), 'zh') !== false) {
$localeArr[] = 'l_zh';
}
$form->get('locale')->setData($localeArr);
}
}
if($form->isSubmitted() && $form->isValid()) {
$localeStr = '';
foreach($form->get('locale')->getData() as $l) {
$localeStr .= str_replace('l_', '', $l) . ' ';
}
$localeStr = trim($localeStr);
if(strpos($localeStr, 'all') !== false) {
$localeStr = 'all';
}
$saPref->setValue($localeStr);
try {
Api::saveUserPref($saPref);
}
catch(\Exception $e) {
$this->logger->log('Api::saveUserPref() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_sa_langs');
}
$this->logger->log('Spamassassin languages set', $request, []);
$this->addFlash('notice', $this->translator->trans('Antispam languages set'));
return $this->redirectToRoute('qu_sa_langs');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Antispam languages NOT set'));
}
return $this->render('skins/' . $this->skin . '/q_user/spamassassin_langs.html.twig', [
'form' => $form->createView(),
'antispamOn' => $antispamOn,
]);
}
/**
* @Route("/panel/spamassassin/setdefaults/{type}", name="qu_sa_set_defaults", requirements={"type"="^(lang|score)$"})
* @param type - lang or score
*/
public function spamAssassinSetDefaults(String $type, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SPAMASSASSIN', $account);
$saPref = null;
$qsPref = null;
if($type == "lang") {
try {
foreach(Api::getSAPrefVal($account, 'ok_locales') as $pref) {
$saPref = $pref;
break;
}
}
catch(\Exception $e) {}
}
else {
try {
foreach(Api::getSAPrefVal($account, 'required_score') as $pref) {
$saPref = $pref;
break;
}
foreach(Api::getQS($account) as $pref) {
$qsPref = $pref;
break;
}
}
catch(\Exception $e) {}
}
if(is_null($saPref) || Api::deleteSAPref($saPref->getPrefid())) {
$this->logger->log('Antispam/Antispam ' . $type . ' - default settings set', $request);
$this->addFlash('notice', $this->translator->trans('Default settings set'));
}
else {
$this->logger->log('Error while trying to set default settings', $request, [], 'critical');
$this->addFlash('error', $this->translator->trans('Default settings NOT set'));
}
if($qsPref != null) {
Api::deleteQs($qsPref->getId());
}
// redirect to spamassassin main page or to a specific subpage
$referer = $request->headers->get('referer');
if(strlen($referer)) {
return $this->redirect($referer);
}
return $this->redirectToRoute('qu_sa');
}
/**
* @Route("/panel/procmail", name="qu_procmail")
*/
public function procmail(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
$headers = ProcmailRule::mailHeaders();
$form = $this->createForm(Procmail::class);
$formMass = $this->createForm(ProcmailMass::class);
$form->handleRequest($request);
try {
$rules = Api::getProcmailRules($account);
$localForwarding = Api::getForwardLocal($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRules() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
foreach($rules as &$r) {
if(!$r->isDestEmail()) {
$r->setDestExist(Api::checkImapDir($account, mb_convert_encoding($r->getDest(), 'UTF7-imap', 'utf8')));
}
}
if($form->isSubmitted() && $form->isValid()) {
$rule = new ProcmailRule();
$rule->setOwner($account->userAddress());
$rule->setNo(-1);
$rule->setType($form->get('src')->getData());
// if src is "header" we need to set header-type
if($rule->getType() == 'header') {
$rule->setHeaderType($form->get('headerTypeVal')->getData());
//$pattern = $form->get('header_type_val')->getData() . ': ' . $pattern;
}
$rule->setValue($form->get('pattern')->getData());
$dest = $form->get('dest')->getData();
// if dest is '...email' save value of destEmail
if($dest == '...email') {
$dest = '...' . str_replace(' ', '', $form->get('destEmail')->getData());
// check if number of forwards is not exceeded
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$maxForwards = $this->_maxForwards($account);
$maxExternalForwards = $this->_maxExternalForwards($account);
$forwardsCnt = count($forwards);
$externalForwardsCnt = $this->_externalForwardsCount($forwards, $user->getAccount());
$externalRulesCnt = $this->_numberProcmailRulesEmailExternal($account);
$rulesCnt = $this->_numberProcmailRulesEmail($account);
if(($forwardsCnt + $rulesCnt + 1) > $maxForwards) {
$this->addFlash('error', $this->translator->trans('Rule NOT added - limit of forwards exceeded') . ' (' . $maxForwards . '). ' . $this->translator->trans('Forwards used in forwarding') . ': ' . $forwardsCnt . '. ' . $this->translator->trans('Forwards used in sorting') . ': ' . $rulesCnt);
return $this->render('skins/' . $this->skin . '/q_user/procmail.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'rules' => $rules,
'headers' => $headers,
'localForwarding' => $localForwarding,
]);
}
// check if limit of external forwards is not exceeded
$externalForwardsCnt = $this->_externalForwardsCount($forwards, $user->getAccount());
$currentExternalRules = 0;
if(AccountTools::isEmailExternal($form->get('destEmail')->getData(), [$user->getAccount()->getUserDomain()])) {
$currentExternalRules = 1;
}
if(($externalForwardsCnt + $externalRulesCnt + $currentExternalRules) > $maxExternalForwards) {
$this->addFlash('error', $this->translator->trans('Rule NOT added - limit of external forwards exceeded') . ' (' . $maxExternalForwards . '). ' . $this->translator->trans('External forwards used in forwards') . ': ' . $externalForwardsCnt. '. ' . $this->translator->trans('External forwards used in sorting') . ': ' . $externalRulesCnt);
return $this->render('skins/' . $this->skin . '/q_user/procmail.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'rules' => $rules,
'headers' => $headers,
'localForwarding' => $localForwarding,
]);
}
}
else {
$dest = mb_convert_encoding(urldecode($dest), 'UTF7-imap', 'utf8');
}
$rule->setDest($dest);
$rule->setFinal($form->get('last')->getData());
try {
Api::addProcmailRule($rule);
}
catch(\Exception $e) {
$this->logger->log('Api::addProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
}
$this->logger->log('New rule added', $request, ['rule' => $rule->getValue()]);
$this->addFlash('notice', $this->translator->trans('Rule added'));
$this->addFlash('rowsAffected', -1); // highlight the last one
return $this->redirectToRoute('qu_procmail');
}
elseif($form->isSubmitted() && !$form->isValid()){
$dest = $form->get('dest')->getData();
$this->addFlash('error', $this->translator->trans('Procmail rule NOT added'));
}
return $this->render('skins/' . $this->skin . '/q_user/procmail.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'rules' => $rules,
'headers' => $headers,
'localForwarding' => $localForwarding,
]);
}
/**
* @Route("/panel/procmail/mass", name="qu_procmail_mass")
*/
public function procmailMassAction(Request $request) {
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
$form = $this->createForm(ProcmailMass::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$actionType = $form->get('actionType')->getData();
$selected = $request->request->get('rulesMassCheckbox');
$actionFailed = false;
$affected = [];
foreach($selected as $id) {
try {
$rule = Api::getProcmailRule($id);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$actionFailed = true;
continue;
}
$this->denyAccessUnlessGranted('PROCMAIL', $rule);
switch($actionType) {
case 'delete':
try {
if(Api::deleteProcmailRule($id)) {
$this->logger->log('Procmail rule deleted', $request, ['rule' => $rule->getValue()]);
}
else {
$this->logger->log('Error deleting procmail rule, id = ' . $id, $request, ['rule' => $rule->getValue()]);
$actionFailed = true;
}
}
catch(\Exception $e) {
$this->logger->log('Api::deleteProcmailRule() - exception from API, id = ' . $id, $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$actionFailed = true;
}
break;
case 'enable':
if(Api::enableProcmailRule($id)) {
$this->logger->log('Procmail rule enabled', $request, ['rule' => $rule->getValue()]);
$affected[] = $id;
}
else {
$this->logger->log('Error enabling procmail rule', $request, ['rule' => $rule->getValue()]);
$actionFailed = true;
}
break;
case 'disable':
if(Api::disableProcmailRule($id)) {
$this->logger->log('Procmail rule disabled', $request, ['rule' => $rule->getValue()]);
$affected[] = $id;
}
else {
$this->logger->log('Error disabling procmail rule', $request, ['rule' => $rule->getValue()]);
$actionFailed = true;
}
break;
}
}
switch($actionType) {
case 'delete':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL rules deleted'));
}
else {
$this->addFlash('notice', $this->translator->trans('All rules successfuly deleted'));
}
break;
case 'enable':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL rules enabled'));
}
else {
$this->addFlash('notice', $this->translator->trans('All rules successfuly enabled'));
}
break;
case 'disable':
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL rules disabled'));
}
else {
$this->addFlash('notice', $this->translator->trans('All rules successfuly disabled'));
}
break;
}
$this->addFlash('rowsAffected', implode(':', $affected));
}
return $this->redirectToRoute("qu_procmail");
}
/**
* @Route("/panel/procmail/edit/{id}", name="qu_procmail_edit")
*/
public function procmailEdit(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
$headers = ProcmailRule::mailHeaders();
$form = $this->createForm(Procmail::class);
$form->handleRequest($request);
$rule = Api::getProcmailRule($id);
$this->denyAccessUnlessGranted('PROCMAIL', $rule);
if(!$form->isSubmitted()) {
$form->get('src')->setData($rule->getType());
if($rule->getType() == 'header') {
$form->get('headerType')->setData($rule->getHeaderType());
$form->get('headerTypeVal')->setData($rule->getHeaderType());
}
$form->get('pattern')->setData($rule->getValue());
$dest = $rule->getDest();
if(substr($dest, 0, 3) == '...') {
$form->get('dest')->setData('...email');
$form->get('destEmail')->setData(substr($dest, 3));
}
else {
$form->get('dest')->setData(urlencode($dest));
}
$form->get('last')->setData($rule->getFinal());
}
if($form->isSubmitted() && $form->isValid()) {
$newRule = new ProcmailRule();
$newRule->setId($rule->getId());
$newRule->setOwner($account->userAddress());
$newRule->setNo($rule->getNo());
$newRule->setType($form->get('src')->getData());
if($newRule->getType() == 'header') {
$newRule->setHeaderType($form->get('headerTypeVal')->getData());
}
$newRule->setValue($form->get('pattern')->getData());
$dest = $form->get('dest')->getData();
// if dest is '...email' save value of destEmail
if($dest == '...email') {
$dest = '...' . str_replace(' ', '', $form->get('destEmail')->getData());
// check if we don't exceed limits of forwards
try {
$forwards = Api::getForwards($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$maxForwards = $this->_maxForwards($account);
$maxExternalForwards = $this->_maxExternalForwards($account);
$forwardsCnt = count($forwards);
$externalForwardsCnt = $this->_externalForwardsCount($forwards, $user->getAccount());
$externalRulesCnt = $this->_numberProcmailRulesEmailExternal($account);
$rulesCnt = $this->_numberProcmailRulesEmail($account);
if(($forwardsCnt + $rulesCnt + 1) > $maxForwards) {
$this->addFlash('error', $this->translator->trans('Procmail rule NOT saved - limit of forwards exceeded') . ' (' . $maxForwards . '). ' . $this->translator->trans('Forwards used in forwarding') . ': ' . $forwardsCnt . '. ' . $this->translator->trans('Forwards used in sorting') . ': ' . $rulesCnt);
return $this->render('skins/' . $this->skin . '/q_user/procmail_edit.html.twig', [
'form' => $form->createView(),
'headers' => $headers,
]);
}
// check if limit of external forwards is not exceeded
$externalForwardsCnt = $this->_externalForwardsCount($forwards, $user->getAccount());
$currentExternalRules = 0;
if(AccountTools::isEmailExternal($form->get('destEmail')->getData(), [$user->getAccount()->getUserDomain()])) {
$currentExternalRules = 1;
}
if(($externalForwardsCnt + $externalRulesCnt + $currentExternalRules) > $maxExternalForwards) {
$this->addFlash('error', $this->translator->trans('Rule NOT added - limit of external forwards exceeded') . ' (' . $maxExternalForwards . '). ' . $this->translator->trans('External forwards used in forwards') . ': ' . $externalForwardsCnt. '. ' . $this->translator->trans('External forwards used in sorting') . ': ' . $externalRulesCnt);
return $this->render('skins/' . $this->skin . '/q_user/procmail_edit.html.twig', [
'form' => $form->createView(),
'headers' => $headers,
]);
}
}
else {
$dest = mb_convert_encoding(urldecode($dest), 'UTF7-imap', 'utf8');
}
$newRule->setDest($dest);
$newRule->setFinal($form->get('last')->getData());
try {
Api::saveProcmailRule($newRule);
}
catch(\Exception $e) {
$this->logger->log('Api::saveProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
}
$this->addFlash('notice', $this->translator->trans('Rule saved'));
$this->addFlash('rowsAffected', $rule->getId());
return $this->redirectToRoute('qu_procmail');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Procmail rule NOT saved'));
}
return $this->render('skins/' . $this->skin . '/q_user/procmail_edit.html.twig', [
'form' => $form->createView(),
'headers' => $headers,
]);
}
/**
* @Route("/panel/procmail/del/{id}", name="qu_procmail_del")
*/
public function procmailDel(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
try {
$rule = Api::getProcmailRule($id);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_procmail');
}
$this->denyAccessUnlessGranted('PROCMAIL', $rule);
try {
if(Api::deleteProcmailRule($id)) {
$this->logger->log('Procmail rule deleted', $request, ['rule' => $rule->getValue()]);
$this->addFlash('notice', $this->translator->trans('Rule deleted'));
}
}
catch(\Exception $e) {
$this->addFlash('error', $this->translator->trans('Rule NOT deleted'));
}
return $this->redirectToRoute("qu_procmail");
}
/**
* @Route("/panel/procmail/disable/{id}", name="qu_procmail_disable")
*/
public function procmailDisable(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
try {
$rule = Api::getProcmailRule($id);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_procmail');
}
$this->denyAccessUnlessGranted('PROCMAIL', $rule);
if(Api::disableProcmailRule($id)) {
$this->logger->log('Procmail rule disabled', $request, ['rule' => $rule->getValue()]);
$this->addFlash('notice', $this->translator->trans('Rule disabled'));
$this->addFlash('rowsAffected', $id);
}
else {
$this->addFlash('error', $this->translator->trans('Rule NOT disabled'));
}
return $this->redirectToRoute("qu_procmail");
}
/**
* @Route("/panel/procmail/enable/{id}", name="qu_procmail_enable")
*/
public function procmailEnable(int $id, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
try {
$rule = Api::getProcmailRule($id);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_procmail');
}
$this->denyAccessUnlessGranted('PROCMAIL', $rule);
if(Api::enableProcmailRule($id)) {
$this->logger->log('Procmail rule disabled', $request, ['rule id' => $id]);
$this->addFlash('notice', $this->translator->trans('Rule enabled'));
$this->addFlash('rowsAffected', $id);
}
else {
$this->addFlash('error', $this->translator->trans('Rule NOT enabled'));
}
return $this->redirectToRoute("qu_procmail");
}
/**
* @Route("/panel/procmail/ruleup/{id}", name="qu_procmail_ruleup")
*/
public function procmailUp(int $id, Request $request)
{
return $this->_procmailMove($id, 'up', $request);
}
/**
* @Route("/panel/procmail/ruledown/{id}", name="qu_procmail_ruledown")
*/
public function procmailDown(int $id, Request $request)
{
return $this->_procmailMove($id, 'down', $request);
}
/**
*
*/
private function _procmailMove(int $id, string $direction, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('PROCMAIL', $account);
try {
$rule = Api::getProcmailRule($id);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_procmail');
}
$this->denyAccessUnlessGranted('PROCMAIL', $rule);
if($direction == 'up') {
if(Api::procmailRuleMoveUp($id)) {
$this->addFlash('notice', $this->translator->trans('Rule moved up'));
$this->addFlash('rowsAffected', $id);
}
else {
$this->addFlash('error', $this->translator->trans('Rule NOT moved up'));
}
}
else {
if(Api::procmailRuleMoveDown($id)) {
$this->addFlash('notice', $this->translator->trans('Rule moved down'));
$this->addFlash('rowsAffected', $id);
}
else {
$this->addFlash('error', $this->translator->trans('Rule NOT moved down'));
}
}
return $this->redirectToRoute("qu_procmail");
}
/**
* @Route("/panel/dirs", name="qu_imap")
*/
public function imapDirs(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('IMAP', $account);
$form = $this->createForm(Imap::class);
$form->get('path')->setData('delete');
$formMass = $this->createForm(ImapMass::class);
$form->handleRequest($request);
try {
$folders = Api::getImapDirs($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getImapDirs() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$imapUserDomainArr = $this->_getImapUserDomain($account);
try {
$subscribedFolders = Api::getImapSubscribedDirs($imapUserDomainArr[0], $imapUserDomainArr[1], AccountTools::decryptString($this->requestStack->getSession()->get('storedPassword')));
}
catch(\Exception $e) {
$this->logger->log('Api::getImapSubscribedDirs() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
usort($folders, '\App\Model\ImapDir::cmpObjects');
$inbox = new ImapDir();
$inbox->setName('INBOX');
try {
$inbox->setCount(Api::getImapCount($account, 'INBOX'));
}
catch(\Exception $e) {
$this->logger->log('Api::getImapCount() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
array_unshift($folders, $inbox);
$folders = AccountTools::dirsChildren($folders, "", 0);
if(!$form->isSubmitted()) {
$form->get('path')->setData('.');
}
if($form->isSubmitted() && $form->isValid()) {
$folderToAdd = mb_convert_encoding($form->get('folder')->getData(), 'UTF7-imap', 'utf8');
$path = mb_convert_encoding($form->get('path')->getData(), 'UTF7-imap', 'utf8');
if(strlen($path) > 0) {
if($path != '.') {
$folderToAdd = $path . '.' . $folderToAdd;
}
}
try {
Api::addImapDir($account, $folderToAdd);
}
catch(\Exception $e) {
if(strstr($e->getMessage(), 'already exists')) {
$this->addFlash('error', $this->translator->trans('Folder already exists. New folder NOT added.'));
}
else {
$this->logger->log('Api::addImapDir() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
}
return $this->redirectToRoute('qu_imap');
}
$this->logger->log('New folder added', $request, ['folder' => $form->get('folder')->getData()]);
$this->addFlash('notice', $this->translator->trans('New folder added'));
$this->addFlash('rowsAffected', $folderToAdd); // highlight the new one
return $this->redirectToRoute('qu_imap');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('New folder NOT added'));
}
return $this->render('skins/' . $this->skin . '/q_user/imap_dirs.html.twig', [
'form' => $form->createView(),
'formMass' => $formMass->createView(),
'folders' => $folders,
'subscribedFolders' => $subscribedFolders,
]);
}
/**
* @Route("/panel/dirs/mass", name="qu_imap_mass")
*/
public function imapDirsMassAction(Request $request) {
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('IMAP', $account);
$form = $this->createForm(ImapMass::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$selected = $request->request->get('foldersMassCheckbox');
$actionFailed = false;
foreach($selected as $dir) {
// we have to url-decode, than encode from UTF-8 to UTF-7
$dir = urldecode($dir);
$dir = mb_convert_encoding($dir, 'UTF7-imap', 'utf8');
if(Api::deleteImapDir($account, $dir)) {
$this->logger->log('Imap directory deleted', $request, ['dir' => urldecode($dir)]);
}
else {
$actionFailed = true;
}
}
if($actionFailed) {
$this->addFlash('error', $this->translator->trans('NOT ALL folders deleted'));
}
else {
$this->addFlash('notice', $this->translator->trans('All folders successfuly deleted'));
}
}
return $this->redirectToRoute("qu_imap");
}
/**
* @Route("/panel/dirs/del/{dir}", name="qu_imap_del")
*/
public function imapDirsDel(String $dir, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('IMAP', $account);
if($dir == 'INBOX') {
$this->logger->log('Try to delete INBOX', $request, ['dir' => urldecode($dir)], 'critical');
return $this->redirectToRoute("qu_imap");
}
$dir = urldecode($dir);
$dir = mb_convert_encoding($dir, 'UTF7-imap', 'utf8');
if(Api::deleteImapDir($account, $dir)) {
$this->logger->log('Imap directory deleted', $request, ['dir' => urldecode($dir)]);
$this->addFlash('notice', $this->translator->trans('Folder deleted'));
}
else {
$this->logger->log('Imap directory NOT deleted - error', $request, ['dir' => urldecode($dir)]);
$this->addFlash('error', $this->translator->trans('Folder NOT deleted'));
}
return $this->redirectToRoute("qu_imap");
}
/**
* @Route("/panel/dirs/edit/{dir}", name="qu_imap_edit")
*/
public function imapDirsEdit(String $dir, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('IMAP', $account);
if($dir == 'INBOX') {
$this->logger->log('Try to edit INBOX', $request, ['dir' => urldecode($dir)], 'critical');
return $this->redirectToRoute("qu_imap");
}
// we have to url-decode, than encode from UTF-8 to UTF-7 and url-encode again
$dir = urldecode($dir);
$form = $this->createForm(Imap::class);
$form->handleRequest($request);
$whitespaceWarning = false;
if(!$form->isSubmitted()) {
// we need to split $dir - last part is a folder name, previous part - path
$dirArr = explode('.', $dir);
$form->get('folder')->setData($dirArr[sizeof($dirArr) - 1]);
$folder = $form->get('folder')->getData();
if($folder != trim($folder)) {
$whitespaceWarning = true;
}
unset($dirArr[sizeof($dirArr) - 1]);
$path = implode('.', $dirArr);
if($path == "") {
$path = ".";
}
$form->get('path')->setData($path);
}
if($form->isSubmitted() && $form->isValid()) {
$from = mb_convert_encoding($dir, 'UTF7-imap', 'utf8');
$to = mb_convert_encoding($form->get('folder')->getData(), 'UTF7-imap', 'utf8');
$path = mb_convert_encoding($form->get('path')->getData(), 'UTF7-imap', 'utf8');
if(strlen($path) > 0) {
if($path != '.') {
$to = $path . '.' . $to;
}
}
if(Api::renameImapDir($account, $from, $to)) {
$this->logger->log('Imap directory renamed', $request, [
'dirOld' => $from, 'dirNew' => $to]);
$this->addFlash('notice', $this->translator->trans('Folder renamed'));
$this->addFlash('rowsAffected', $to);
return $this->redirectToRoute('qu_imap');
}
else {
$this->addFlash('error', $this->translator->trans('Folder NOT renamed'));
}
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Folder NOT renamed'));
}
return $this->render('skins/' . $this->skin . '/q_user/imap_dirs_edit.html.twig', [
'form' => $form->createView(),
'whitespaceWarning' => $whitespaceWarning,
]);
}
/**
* @Route("/panel/dirs/subscribe/{dir}", name="qu_imap_subscribe")
* dir in UTF7-imap, urlencoded
*/
public function imapDirsSubscribe(String $dir, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('IMAP', $account);
if($dir == 'INBOX') {
$this->logger->log('Try to subscribe INBOX', $request, ['dir' => urldecode($dir)], 'critical');
return $this->redirectToRoute("qu_imap");
}
$imapUserDomainArr = $this->_getImapUserDomain($account);
try {
Api::subscribeImapDir($imapUserDomainArr[0], $imapUserDomainArr[1], AccountTools::decryptString($this->requestStack->getSession()->get('storedPassword')), $dir);
}
catch(\Exception $e) {
$this->logger->log('Api::imapDirsSubscribe() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
}
return $this->redirectToRoute('qu_imap');
}
/**
* @Route("/panel/dirs/unsubscribe/{dir}", name="qu_imap_unsubscribe")
* dir in UTF7-imap, urlencoded
*/
public function imapDirsUnsubscribe(String $dir, Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('IMAP', $account);
if($dir == 'INBOX') {
$this->logger->log('Try to subscribe INBOX', $request, ['dir' => urldecode($dir)], 'critical');
return $this->redirectToRoute("qu_imap");
}
$imapUserDomainArr = $this->_getImapUserDomain($account);
try {
Api::unsubscribeImapDir($imapUserDomainArr[0], $imapUserDomainArr[1], AccountTools::decryptString($this->requestStack->getSession()->get('storedPassword')), $dir);
}
catch(\Exception $e) {
$this->logger->log('Api::imapDirsUnsubscribe() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
}
return $this->redirectToRoute('qu_imap');
}
/**
* @Route("/panel/noticesms", name="qu_noticesms")
*/
public function noticeSms(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('NOTICESMS', $account);
$form = $this->createForm(NoticeSMS::class);
$form->handleRequest($request);
try {
$rule = Api::getSMSRule($account);
}
catch(\Exception $e) {
$rule = new ProcmailRule();
$rule->setId(-1);
$rule->setType('sms');
$rule->setDest('NA');
$rule->setOwner($account->userAddress());
$rule->setNo(0);
$rule->setFinal(0);
}
try {
$localForwarding = Api::getForwardLocal($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getForwardLocal() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
if(!$form->isSubmitted()) {
if(strlen($rule->getValue()) > 0) {
$form->get('address')->setData($rule->getValue());
}
}
if($form->isSubmitted() && $form->isValid()) {
// check if given address is not user's address on alias pointing to it
// to prevent email loops
if(strcmp($form->get('address')->getData(), $account->userAddress()) == 0) {
$this->logger->log("noticeSMS - prevented saving user's own email address as a notification address", $request, ['accountName' => $account->userAddress()]);
$this->addFlash('error', $this->translator->trans('You cannot add your own email address as a notification address'));
return $this->render('skins/' . $this->skin . '/q_user/noticesms.html.twig', [
'form' => $form->createView(),
'localForwarding' => $localForwarding,
]);
}
$aliasFilter = [];
$aliasFilter['target_alias'] = $account->userAddress();
try {
$aliases = Api::listAliases($aliasFilter);
}
catch(\Exception $e) {
$this->logger->log('Api::listAliases() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_noticesms');
}
foreach($aliases as $alias) {
if(strcmp($alias->getSrc(), $form->get('address')->getData()) == 0) {
$this->logger->log("noticeSMS - prevented saving user's own alias as a notification address", $request, ['accountName' => $account->userAddress()]);
$this->addFlash('error', $this->translator->trans('You cannot add your own alias as a notification address'));
return $this->render('skins/' . $this->skin . '/q_user/noticesms.html.twig', [
'form' => $form->createView(),
'localForwarding' => $localForwarding,
]);
}
}
$rule->setValue($form->get('address')->getData());
if($rule->getId() != -1) {
try {
Api::saveProcmailRule($rule);
}
catch(\Exception $e) {
$this->logger->log('Api::saveProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_noticesms');
}
}
else {
try {
Api::addProcmailRule($rule);
}
catch(\Exception $e) {
$this->logger->log('Api::addProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_noticesms');
}
}
$this->addFlash('notice', $this->translator->trans('Mobile notification added'));
$this->logger->log('Mobile notification added', $request, ['address' => $rule->getValue()]);
return $this->redirectToRoute('qu_noticesms');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('SMS notice NOT set'));
}
return $this->render('skins/' . $this->skin . '/q_user/noticesms.html.twig', [
'form' => $form->createView(),
'localForwarding' => $localForwarding,
]);
}
/**
* @Route("/panel/noticesms/del", name="qu_noticesms_del")
*/
public function noticeSmsDel(Request $request)
{
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('NOTICESMS', $account);
try {
$rule = Api::getSMSRule($account);
}
catch(\Exception $e) {
$this->logger->log('trying to delete non-existante SMS notice', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'warning');
$this->addFlash('error', $this->translator->trans('Deleting SMS notification not possible.'));
return $this->redirectToRoute('qu_noticesms');
}
try {
if(Api::deleteProcmailRule($rule->getId())) {
$this->logger->log('Mobile notification deleted', $request);
$this->addFlash('notice', $this->translator->trans('Mobile notification deleted'));
}
}
catch(\Exception $e) {
$this->logger->log('Api::deleteProcmailRule() - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_noticesms');
}
return $this->redirectToRoute("qu_noticesms");
}
/**
* @Route("/panel/stats", name="qu_stats")
*/
public function stats(Request $request)
{
$stats = [];
$user = $this->security->getUser();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('STATS', $account);
$autoresponderStatus = '';
try {
$forwards = Api::getForwards($account);
$localForwarding = Api::getForwardLocal($account);
$folders = Api::getImapDirs($account);
$rules = Api::getProcmailRules($account);
$this->_getAutoresponderForUser($account, $autoresponderStatus);
$saStatus = Api::getSAProtection($account);
}
catch(\Exception $e) {
$this->logger->log('Api - get functions - exception from API', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
try {
$smsRule = Api::getSMSRule($account);
if($smsRule != null) {
$smsStatus = true;
}
}
catch(\Exception $e) {
$smsStatus = false;
}
$stats['forwards'] = sizeof($forwards);
$stats['folders'] = sizeof($folders);
$stats['filters'] = sizeof($rules);
$stats['autoresponderStatus'] = $autoresponderStatus; // string, because can have 3 different states
$stats['antispamStatus'] = $saStatus;
$stats['smsStatus'] = $smsStatus;
$stats['deliveryStatus'] = $localForwarding;
return $this->render('skins/' . $this->skin . '/q_user/user_stats.html.twig', [
'stats' => $stats,
]);
}
/**
* @Route("/panel/settings", name="qu_settings")
*/
public function settings(Request $request)
{
$user = $this->security->getUser();
$user->loadAccount();
$account = $user->getAccount();
$this->denyAccessUnlessGranted('SETTINGS', $account);
$twoFactorAllowed = false;
$twoFactorGoogleAllowed = false;
$twoFactorMethod = 'email';
$qrCodeDataUri = null;
$serviceDomain = $request->getHost();
if(isset($_SERVER['APP_2FA_ALLOWED'])) {
if($_SERVER['APP_2FA_ALLOWED'] == 'true') {
$twoFactorAllowed = true;
}
}
if(isset($_SERVER['APP_2FA_GOOGLE_ALLOWED'])) {
if($_SERVER['APP_2FA_GOOGLE_ALLOWED'] == 'true') {
$twoFactorGoogleAllowed = true;
}
}
try {
$d = Api::getDomain($account->getUserDomain());
}
catch(\Exception $e) {
$this->addFlash('error', $this->translator->trans('Domain settings not available'));
$this->logger->log('Error while getting domain ' . $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
return $this->redirectToRoute('qp_main');
}
$domainMaxForwards = $d->findOption('cfgMaxForwards') == null ? (isset($_SERVER['APP_DEFAULT_MAX_FORWARDS']) ? $_SERVER['APP_DEFAULT_MAX_FORWARDS'] : 10) : $d->findOption('cfgMaxForwards');
$domainMaxExternalForwards = $d->findOption('cfgMaxExternalForwards') == null ? 0 : $d->findOption('cfgMaxExternalForwards');
$form = $this->createForm(Settings::class);
$form->handleRequest($request);
$confirmKeys = ['Forward', 'Autoresponder', 'AutoresponderRcpt', 'SpamassassinReset',
'SpamassassinList', 'SpamassassinLangs', 'Imap', 'ImapMails', 'Procmail', 'Mobile'
];
$forceLoginTarget = false;
if(isset($_SERVER['APP_LOGIN_TARGET'])) {
$forceLoginTarget = true;
}
if(!$form->isSubmitted()) {
$sessionTime = $account->findSOption('cfgSessionTime') == null ? $this->params->get('session_max_idle_time') : $account->findSOption('cfgSessionTime');
$loginTarget = $account->findSOption('cfgLoginTarget') == null ? 'form' : $account->findSOption('cfgLoginTarget');
// pagination from user's config. If not set - from env. If not set - from Account const
$historyPagination = $account->findSOption('cfgUserHistoryPagination') == null ?
(isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
: $account->findSOption('cfgUserHistoryPagination');
// pagination from user's config. If not set - from env. If not set - from Account const
$pagination = $account->findSOption('cfgUserPagination') == null ?
(isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
: $account->findSOption('cfgUserPagination');
$saMaxScore = $account->findSOption('cfgSAMaxScore') == null ? UserPref::SA_MAX_SCORE : $account->findSOption('cfgSAMaxScore');
$forceWebmailLang = $account->findSOption('cfgForceWebmailLang') == null ? 'yes' : $account->findSOption('cfgForceWebmailLang');
$maxForwards = $account->findSOption('cfgMaxForwards') == null ? $domainMaxForwards : $account->findSOption('cfgMaxForwards');
$maxExternalForwards = $account->findSOption('cfgMaxExternalForwards') == null ? $domainMaxExternalForwards : $account->findSOption('cfgMaxExternalForwards');
$skin = $account->findSOption('cfgSkin') == null ? 'standard' : $account->findSOption('cfgSkin');
$emailForAuth = $account->findSOption('cfgEmailForAuth') == null ? '' : $account->findSOption('cfgEmailForAuth');
$twoFactorEnabled = $account->findSOption('cfgTwoFactorEnabled') == null ? false : ($account->findSOption('cfgTwoFactorEnabled') == '1' ? true : false);
$emailForAuthConfirmed = $account->findSOption('emailForAuthConfirmed') == null ? false : ($account->findSOption('emailForAuthConfirmed') == '1' ? true : false);
$twoFactorMethod = $account->findSOption('cfgTwoFactorMethod') == null ? 'email' : $account->findSOption('cfgTwoFactorMethod');
$confirms = [];
foreach($confirmKeys as $opt) {
if($account->findSOption('cfgDontConfirm' . $opt) == null) {
$confirms[] = $opt;
}
}
$form->get('sessionTime')->setData($sessionTime);
$form->get('loginTarget')->setData($loginTarget);
$form->get('confirms')->setData($confirms);
$form->get('historyPagination')->setData($historyPagination);
$form->get('pagination')->setData($pagination);
$form->get('saMaxScore')->setData($saMaxScore);
$form->get('forceWebmailLang')->setData($forceWebmailLang);
$form->get('maxForwards')->setData($maxForwards);
$form->get('maxExternalForwards')->setData($maxExternalForwards);
$form->get('skin')->setData($skin);
$form->get('emailForAuth')->setData($emailForAuth);
$form->get('twoFactorEnabled')->setData($twoFactorEnabled);
$form->get('twoFactorMethod')->setData($twoFactorMethod);
}
if($form->isSubmitted() && $form->isValid()) {
// wykrywanie zmiany metody 2FA na google
$prevTwoFactorMethod = $account->findSOption('cfgTwoFactorMethod') ?? 'email';
$prevTwoFactorEnabled = $account->findSOption('cfgTwoFactorEnabled') == '1';
$newTwoFactorMethod = $form->get('twoFactorMethod')->getData();
$newTwoFactorEnabled = $form->get('twoFactorEnabled')->getData();
if (
($prevTwoFactorMethod !== 'google' && $newTwoFactorMethod === 'google') ||
(!$prevTwoFactorEnabled && $newTwoFactorEnabled && $newTwoFactorMethod === 'google')
) {
$request->getSession()->set('showQrAfterSave', true);
}
$account->setSOption('cfgUserHistoryPagination', $form->get('historyPagination')->getData());
$account->setSOption('cfgUserPagination', $form->get('pagination')->getData());
$account->setSOption('cfgSAMaxScore', $form->get('saMaxScore')->getData());
$account->setSOption('cfgSessionTime', $form->get('sessionTime')->getData());
$account->setSOption('cfgLoginTarget', $form->get('loginTarget')->getData());
$account->setSOption('cfgForceWebmailLang', $form->get('forceWebmailLang')->getData());
$account->setSOption('cfgSkin', $form->get('skin')->getData());
$emailForAuth = $account->findSOption('cfgEmailForAuth') == null ? '' : $account->findSOption('cfgEmailForAuth');
$showInfoAbout2FA = false;
if($twoFactorAllowed) {
$saveEmailForAuth = true;
if($emailForAuth != $form->get('emailForAuth')->getData()) {
// new email address for auth confirmations
$account->setSOption('emailForAuthConfirmed', '');
$account->setSOption('cfgTwoFactorEnabled', '');
$showInfoAbout2FA = true;
$tf = new TwoFactor($this->translator);
$newAuthToken = $tf->generateNewAuthToken($account);
$emailText = $tf->createEmailForNewAuthConnection($newAuthToken, $this->generateUrl('check-two-factor', ['token' => $newAuthToken], UrlGeneratorInterface::ABSOLUTE_URL));
$from = $tf->getFromAddress();
$subject = $tf->getNewEmailForAuthSubject();
$emailTo = $form->get('emailForAuth')->getData();
if(!is_null($emailTo)) {
$email = (new Email())
->subject($subject)
->from($from)
->to($emailTo)
->text($emailText)
;
try {
$this->mailer->send($email);
}
catch(\Exception $e) {
$this->logger->log('Error while sending email for 2FA', $request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Error while sending email for 2FA'));
$showInfoAbout2FA = false;
$saveEmailForAuth = false;
}
}
else {
$showInfoAbout2FA = false;
}
}
else {
if($form->get('twoFactorEnabled')->getData()) {
$account->setSOption('cfgTwoFactorEnabled', '1');
}
else {
$account->setSOption('cfgTwoFactorEnabled', '');
}
}
// jeśli zmieniamy metodę 2FA, to ustawiamy cfgTwoFactorEnabled na false
if ($prevTwoFactorMethod !== $newTwoFactorMethod) {
$account->setSOption('cfgTwoFactorEnabled', '');
}
if($form->get('emailForAuth')->getData() == null) {
$account->setSOption('cfgEmailForAuth', '');
}
else {
if($saveEmailForAuth) {
$account->setSOption('cfgEmailForAuth', $form->get('emailForAuth')->getData());
}
}
// jeśli już jest secret w account, to nie tworzymy nowego
if($twoFactorGoogleAllowed) {
if ($form->get('twoFactorMethod')->getData() == 'google' && $account->findSOption('google2fa_secret') == null) {
$totp = TOTP::create();
$totp->setIssuer($serviceDomain);
$totp->setLabel($account->getUserName().'@'.$account->getUserDomain());
$secret = $totp->getSecret();
// secret do logu
$this->logger->log('Google Authenticator newly created secret: ' . $secret, $request);
$account->setSOption('google2fa_secret', $secret);
Api::saveAccountParameters($account);
//$qrContent = $totp->getProvisioningUri();
//$qrResult = Builder::create()->data($qrContent)->size(300)->build();
//$qrCodeDataUri = $qrResult->getDataUri();
$account->setSOption('cfgTwoFactorMethod', 'google');
Api::saveAccountParameters($account);
}
if ($request->get('google2fa_code')) {
$this->logger->log('Google Authenticator secret z account: ' . $account->findSOption('google2fa_secret'), $request);
$this->logger->log('Google Authenticator code: ' . $request->get('google2fa_code'), $request);
$totp = TOTP::create($account->findSOption('google2fa_secret'));
if ($totp->verify($request->get('google2fa_code'))) {
$account->setSOption('google2fa_confirmed', '1');
$account->setSOption('cfgTwoFactorEnabled', '1');
Api::saveAccountParameters($account);
$this->addFlash('notice', 'Google Authenticator activated!');
} else {
$this->addFlash('error', 'Incorrect Google Authenticator code');
$account->setSOption('cfgTwoFactorEnabled', '');
$request->getSession()->set('showQrAfterSave', true);
}
}
}
$account->setSOption('cfgTwoFactorMethod', $form->get('twoFactorMethod')->getData());
}
if($this->security->isGranted('IS_IMPERSONATOR')) {
$account->setSOption('cfgMaxForwards', $form->get('maxForwards')->getData());
$account->setSOption('cfgMaxExternalForwards', $form->get('maxExternalForwards')->getData());
}
$confirms = $form->get('confirms')->getData();
foreach($confirmKeys as $opt) {
if(!in_array($opt, $confirms)) {
$account->setSOption('cfgDontConfirm' . $opt, true);
}
else {
$account->deleteOption('cfgDontConfirm' . $opt);
}
}
if(Api::saveAccountParameters($account)) {
if($showInfoAbout2FA) {
$this->addFlash('notice', $this->translator->trans('Your additional address for 2FA was changed. Click on the link we\'ve just sent you to confirm the change.'));
}
else {
$this->addFlash('notice', $this->translator->trans('Settings saved'));
}
$this->logger->log('Settings for account saved', $request);
}
else {
$this->addFlash('error', $this->translator->trans('Settings NOT saved'));
$this->logger->log('Error while saving settings for account', $request);
}
return $this->redirectToRoute('qu_settings');
}
elseif($form->isSubmitted() && !$form->isValid()){
$this->addFlash('error', $this->translator->trans('Settings NOT saved'));
}
$showQr = false;
$qrCodeDataUri = null;
// wymuszenie wyświetlenia QR po zmianie metody lub włączeniu 2FA ---
if ($request->getSession()->has('showQrAfterSave')) {
$showQr = true;
$request->getSession()->remove('showQrAfterSave');
$secret = $account->findSOption('google2fa_secret');
if ($secret) {
$totp = TOTP::create($secret);
$totp->setIssuer($serviceDomain);
$totp->setLabel($account->getUserName().'@'.$account->getUserDomain());
$qrContent = $totp->getProvisioningUri();
$qrResult = Builder::create()->data($qrContent)->size(300)->build();
$qrCodeDataUri = $qrResult->getDataUri();
}
}
/*if ($form->get('twoFactorMethod')->getData() === 'google' && $account->findSOption('google2fa_confirmed') != '1') {
$this->logger->log('Google Authenticator secret z account przy wyświetlaniu: ' . $secret, $request);
}*/
return $this->render('skins/' . $this->skin . '/q_user/settings.html.twig', [
'form' => $form->createView(),
'forceLoginTarget' => $forceLoginTarget,
'emailForAuthConfirmed' => $emailForAuthConfirmed,
'twoFactorAllowed' => $twoFactorAllowed,
'twoFactorGoogleAllowed' => $twoFactorGoogleAllowed,
'qrCodeDataUri' => $showQr ? $qrCodeDataUri : null,
'showQr' => $showQr,
]);
}
/**
* @Route("/panel/login-history/{orderBy}/{orderDir}", defaults={"orderBy"="created_at", "orderDir"="desc"}, name="qu_login_history")
*/
public function loginHistory($orderBy, $orderDir, Request $request, PaginatorInterface $paginator)
{
$account = $this->security->getUser()->getAccount();
$this->denyAccessUnlessGranted('LOGIN_HISTORY', $account);
$form = $this->createForm(LoginHistory::class);
$form->handleRequest($request);
$filter = [];
$options = [];
$options["limit"] = Account::NUMBER_OF_LOGINS;
if($this->security->isGranted('IS_IMPERSONATOR')) {
// for user limitation is always on last Account::NUMBER_OF_LOGINS records
$options["orderBy"] = $orderBy;
$options["orderDir"] = $orderDir;
$options["limit"] = Account::NUMBER_OF_LOGINS * 100;
}
else {
$options["orderBy"] = "created_at";
$options["orderDir"] = "desc";
}
if($form->isSubmitted() && $form->isValid()) {
if($form->get('status')->getData() != '') {
$filter['success'] = (int)$form->get('status')->getData();
}
if($form->get('ip')->getData() != '') {
$filter['ip'] = $form->get('ip')->getData();
}
}
$loginData = Api::getLoginHistory($this->security->getUser()->getEmail(), $filter, $options);
$qpostmasterController = new QPostmasterController($this->logger, $this->translator, $this->security,
$this->params, $this->mailer, $this->requestStack, $this->appExtension);
$tagsArr = $qpostmasterController->loginHistoryTagsFromFilters($filter);
if(!$this->security->isGranted('IS_IMPERSONATOR')) {
// order data for non-impersonificated user
// possible value - created_at / ip / success
if($orderBy == 'created_at' || $orderBy == 'ip' || $orderBy == 'success') {
$this->session->set('app_user_lhistory_order_by', $orderBy);
$this->session->set('app_user_lhistory_order_dir', $orderDir);
}
if($orderBy == 'session') {
if($this->session->has('app_user_lhistory_order_by')) {
$orderBy = $this->session->get('app_user_lhistory_order_by');
$orderDir = $this->session->get('app_user_lhistory_order_dir');
}
else {
$orderBy = 'created_at';
$orderDir = 'desc';
}
}
switch($orderBy) {
case "created_at":
if($orderDir == "asc") {
usort($loginData, "App\Controller\QUserController::_sortByCreatedByAsc");
}
break;
case "ip":
if($orderDir == "asc") {
usort($loginData, "App\Controller\QUserController::_sortByIpAsc");
}
else {
usort($loginData, "App\Controller\QUserController::_sortByIpDesc");
}
break;
case "success":
if($orderDir == "asc") {
usort($loginData, "App\Controller\QUserController::_sortByStatusAsc");
}
else {
usort($loginData, "App\Controller\QUserController::_sortByStatusDesc");
}
break;
}
}
return $this->render('skins/' . $this->skin . '/q_user/login_history.html.twig', [
'form' => $form->createView(),
'loginData' => $paginator->paginate(
$loginData, $request->query->getInt('page', 1), Account::NUMBER_OF_LOGINS
),
'filterTags' => $tagsArr,
'orderDir' => $orderDir,
'orderBy' => $orderBy,
]);
}
/**
* @Route("/panel/loginhistorytag/del/{tag}", name="qu_loginhistorytag_del")
*/
public function loginHistoryTagDelete($tag, Request $request)
{
return $this->redirectToRoute('qu_login_history');
}
/**
* @Route("/panel/operation-history/{orderBy}/{orderDir}", defaults={"orderBy"="time", "orderDir"="desc"}, name="qu_operation_history")
*/
public function operationHistory($orderBy, $orderDir, Request $request, PaginatorInterface $paginator)
{
// $form = $this->createForm(OperationHistory::class);
// $form->handleRequest($request);
$account = $this->security->getUser()->getAccount();
$this->denyAccessUnlessGranted('OPERATION_HISTORY', $account);
$filter = [];
$limit = $account->findSOption('cfgUserHistoryPagination') == null ? Account::NUMBER_OF_OPERATIONS : $account->findSOption('cfgUserHistoryPagination');
$filter["limit"] = (int)$limit;
if($this->security->isGranted('IS_IMPERSONATOR')) {
// for user limitation is always on last Account::NUMBER_OF_LOGINS records
$filter["order"] = $orderBy;
$filter["order_dir"] = $orderDir;
$filter["limit"] = Account::NUMBER_OF_OPERATIONS * 100;
}
else {
$filter["order"] = "time";
$filter["order_dir"] = "desc";
}
$filter["module"] = 'qu_*';
$opDataPresent = true;
try {
$opData = Api::getOperationsHistory($this->security->getUser()->getEmail(), $filter);
}
catch(\Exception $ex) {
$opData = [];
$opDataPresent = false;
}
if($opDataPresent && (!$this->security->isGranted('IS_IMPERSONATOR'))) {
// echo "wewn previous"; exit();
// order data for non-impersonificated user
// possible value - time / msg
if($orderBy == 'time' || $orderBy == 'msg') {
$this->session->set('app_user_ohistory_order_by', $orderBy);
$this->session->set('app_user_ohistory_order_dir', $orderDir);
}
if($orderBy == 'session') {
if($this->session->has('app_user_ohistory_order_by')) {
$orderBy = $this->session->get('app_user_ohistory_order_by');
$orderDir = $this->session->get('app_user_ohistory_order_dir');
}
else {
$orderBy = 'time';
$orderDir = 'desc';
}
}
switch($orderBy) {
case "time":
if($orderDir == "asc") {
usort($opData, "App\Controller\QUserController::_sortByTimeAsc");
}
break;
case "msg":
if($orderDir == "asc") {
usort($opData, "App\Controller\QUserController::_sortByMsgAsc");
}
else {
usort($opData, "App\Controller\QUserController::_sortByMsgDesc");
}
break;
}
}
return $this->render('skins/' . $this->skin . '/q_user/operation_history.html.twig', [
'opData' => $paginator->paginate(
$opData, $request->query->getInt('page', 1), Account::NUMBER_OF_OPERATIONS
),
'orderDir' => $orderDir,
'orderBy' => $orderBy,
'opDataPresent' => $opDataPresent,
]);
}
/**
* @Route("/panel/panel-info", name="qu_panel_info")
*/
public function panelInfo()
{
$license = Api::getLicense();
$sys = [];
$sys['version'] = $this->params->get('app.version.postmaster');
$sys['apiVersion'] = Api::getVersion();
$sys['wrappersVersion'] = Api::getWrappersVersion();
$sys['apiVersionString'] = Api::getVersionString();
$sys['licensed'] = $license['company'];
$sys['expires'] = $license['expires'];
$sys['plan'] = $license['plan'];
return $this->render('skins/' . $this->skin . '/q_user/panel_info.html.twig', [
'sys' => $sys,
]);
}
/// mixing enabled and disabled forwards
// order - "asc" or "desc"
private static function _mixForwardsArrays($enabledForwardsArr, $disabledForwardsArr, $order)
{
$forwards = [];
foreach($enabledForwardsArr as $fw) {
$elem = [];
$elem['address'] = $fw;
$elem['enabled'] = true;
$forwards[] = $elem;
}
foreach($disabledForwardsArr as $fw) {
$elem = [];
$elem['address'] = $fw;
$elem['enabled'] = false;
$forwards[] = $elem;
}
if($order == "asc") {
usort($forwards, 'self::_forwardsComparator');
}
else {
usort($forwards, 'self::_forwardsComparatorRev');
}
return $forwards;
}
private static function _forwardsComparator($a, $b)
{
return strcmp($a["address"], $b["address"]);
}
private static function _forwardsComparatorRev($a, $b)
{
return strcmp($a["address"], $b["address"]) * -1;
}
private static function _sortByCreatedByAsc($a, $b) {
if($a["created_at"] == $b["created_at"]) {
return 0;
}
return ($a["created_at"] < $b["created_at"]) ? -1 : 1;
}
private static function _sortByTimeAsc($a, $b) {
if($a["time"] == $b["time"]) {
return 0;
}
return ($a["time"] < $b["time"]) ? -1 : 1;
}
private static function _sortByIpAsc($a, $b) {
return strcmp($a["ip"], $b["ip"]);
}
private static function _sortByIpDesc($a, $b) {
return strcmp($a["ip"], $b["ip"]) * -1;
}
private static function _sortByMsgAsc($a, $b) {
return strcmp($a["msg"], $b["msg"]);
}
private static function _sortByMsgDesc($a, $b) {
return strcmp($a["msg"], $b["msg"]) * -1;
}
private static function _sortByStatusAsc($a, $b) {
if($a["success"] == $b["success"]) {
return 0;
}
if($a["success"] == true && $b["success"] == false) {
return -1;
}
else {
return 1;
}
}
private static function _sortByStatusDesc($a, $b) {
return QUserController::_sortByStatusAsc($a, $b) * -1;
}
/**
* returns autoresponder of the user and its status in autoresponderStatus
* status can be 'no' if no autoresponder is defined, 'active' and 'inactive'
* @param Account $account
* @param String $autoresponderStatus
* @return \App\Model\Autoresponder
*/
private function _getAutoresponderForUser(Account $account, String &$autoresponderStatus)
{
$autoresponder = new Autoresponder();
$autoresponderStatus = 'no';
// check if user has the autoresponder
try {
$autoresponder = Api::getAutoresponder($account->getUserName(), $account->getUserDomain());
$autoresponder->setActive(true);
$autoresponderStatus = 'active';
}
catch(\Exception $e) {}
if($autoresponderStatus == 'no') {
try {
$autoresponder = Api::getAutoresponder(Autoresponder::NOT_ACTIVE_PREFIX . $account->getUserName(),
Autoresponder::NOT_ACTIVE_PREFIX . $account->getUserDomain());
$autoresponder->setActive(false);
$autoresponderStatus = 'inactive';
}
catch(\Exception $e) {}
}
return $autoresponder;
}
private function _isAntispamOn(Account $account)
{
return Api::getSAProtection($account);
}
/**
* checks if cookie accountReload is set and if so reload Account in User object
*/
private function _isReloadNeeded()
{
if(array_key_exists('accountReload', $_COOKIE) && $_COOKIE['accountReload'] == 1) {
$user = $this->security->getUser();
$user->loadAccount();
unset($_COOKIE['accountReload']);
setcookie('accountReload', null, -1, '/');
}
}
/**
* returns maximum allowed number of forwards or -1 if failed
*/
private function _maxForwards($account) : int
{
$maxForwards = isset($_SERVER['APP_DEFAULT_MAX_FORWARDS']) ? $_SERVER['APP_DEFAULT_MAX_FORWARDS'] : 10;
try {
$d = Api::getDomain($account->getUserDomain());
}
catch(\Exception $e) {
return -1;
}
if($account->findSOption('cfgMaxForwards') == null) {
if($d->findOption('cfgMaxForwards') != null) {
$maxForwards = $d->findOption('cfgMaxForwards');
}
}
else {
$maxForwards = $account->findSOption('cfgMaxForwards');
}
return $maxForwards;
}
/**
* returns maximum allowed number of external forwards or -1 if failed
*/
private function _maxExternalForwards($account) : int
{
$maxExternalForwards = 0;
try {
$d = Api::getDomain($account->getUserDomain());
}
catch(\Exception $e) {
return -1;
}
if($account->findSOption('cfgMaxExternalForwards') == null) {
if($d->findOption('cfgMaxExternalForwards') != null) {
$maxExternalForwards = $d->findOption('cfgMaxExternalForwards');
}
else {
$maxExternalForwards = isset($_SERVER['APP_DEFAULT_MAX_EXTERNAL_FORWARDS']) ? $_SERVER['APP_DEFAULT_MAX_EXTERNAL_FORWARDS'] : 3;
}
}
else {
$maxExternalForwards = $account->findSOption('cfgMaxExternalForwards');
}
return $maxExternalForwards;
}
/**
* counts number of external forwards
*/
private function _externalForwardsCount($forwards, $account)
{
$cnt = 0;
foreach($forwards as $f) {
if(AccountTools::isEmailExternal($f, [$account->getUserDomain()])) {
$cnt++;
}
}
return $cnt;
}
/**
* returns procmail rules that point to address email
* @param Account $account
* @return Array
*/
private function _procmailRulesEmail(Account $account)
{
try {
$rules = Api::getProcmailRules($account);
}
catch(\Exception $e) {
$this->logger->log('Api::getProcmailRules() - exception from API', null , ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
$this->addFlash('error', $this->translator->trans('Critical error, contact administrator.'));
return $this->redirectToRoute('qu_main');
}
$retArr = [];
foreach($rules as $r) {
if($r->isDestEmail()) {
$retArr[] = $r;
}
}
return $retArr;
}
/**
* returns number of procmail rules that point to address email
* @param Account $account
* @return int
*/
private function _numberProcmailRulesEmail(Account $account)
{
return count($this->_procmailRulesEmail($account));
}
/**
* returns number of procmail rules that point to address email that is external
* @param Account $account
* @return int
*/
private function _numberProcmailRulesEmailExternal(Account $account)
{
$num = 0;
foreach($this->_procmailRulesEmail($account) as $r) {
if(AccountTools::isEmailExternal($r->getDest(), [$account->getUserDomain()])) {
$num = $num + 1;
}
}
return $num;
}
/**
* get username and userdomain for imap
* @param Account $account
* @return array
*/
private function _getImapUserDomain(Account $account) : Array
{
$retArr = [];
if($this->isGranted('IS_IMPERSONATOR')) {
$token = $this->security->getToken();
if ($token instanceof SwitchUserToken) {
$impersonatorUser = $token->getOriginalToken()->getUser();
}
$retArr[0] = $this->security->getUser()->getUsername() . '*';
$userDomainArr = explode('@', $impersonatorUser->getUsername());
$retArr[0] .= $userDomainArr[0];
$retArr[1] = $userDomainArr[1];
}
else {
$retArr[0] = $account->getUserName();
$retArr[1] = $account->getUserdomain();
}
return $retArr;
}
/**
* returns array of directories only from given level
* @param array $dirs
* @param int $level
* @return array
*/
/* private function _dirsWithLevel(array $dirs, int $level) : array
{
$arr = [];
foreach($dirs as $d) {
if($d->getLevel() == $level) {
$arr[] = $d;
}
}
return $arr;
} */
/**
* arranges array of directories according to their parent-children connections
* @param array $dirs
* @param string $parent
* @param int $level
* @return array
*/
/* private function _dirsChildren(array $dirs, string $parent, int $level) : array
{
$dirsLev = $this->_dirsWithLevel($dirs, $level);
$arr = [];
foreach($dirsLev as $d) {
if($d->getParent() == $parent) {
$arr[] = $d;
$arr = array_merge($arr, $this->_dirsChildren($dirs, $d->getName(), $level + 1));
}
}
return $arr;
} */
}