src/Controller/QUserController.php line 120

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Knp\Component\Pager\PaginatorInterface;
  4. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  5. use Symfony\Component\Mailer\MailerInterface;
  6. use Symfony\Component\Routing\Annotation\Route;
  7. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Symfony\Component\HttpFoundation\Cookie;
  10. use Symfony\Component\HttpFoundation\RequestStack;
  11. use Symfony\Contracts\Translation\TranslatorInterface;
  12. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  13. use Symfony\Component\Security\Core\Security;
  14. use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
  15. use Symfony\Component\Validator\Constraints as Assert;
  16. use Symfony\Component\Validator\Validator\ValidatorInterface;
  17. use Symfony\Component\Mime\Email;
  18. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  19. use OTPHP\TOTP;
  20. use Endroid\QrCode\Builder\Builder;
  21. use App\Form\LoginHistory;
  22. use App\Form\QUser\AutoresponderForm;
  23. use App\Form\QUser\AutoresponderAdvRulesForm;
  24. use App\Form\QUser\ForwardMailEdit;
  25. use App\Form\QUser\ForwardsMass;
  26. use App\Form\QUser\Imap;
  27. use App\Form\QUser\ImapMass;
  28. use App\Form\QUser\NoticeSMS;
  29. use App\Form\QUser\PasswordChange;
  30. use App\Form\QUser\ForwardMail;
  31. use App\Form\QUser\Procmail;
  32. use App\Form\QUser\ProcmailMass;
  33. use App\Form\QUser\Settings;
  34. use App\Form\QUser\SpamAssassinLists;
  35. use App\Form\QUser\SpamAssassinScore;
  36. use App\Security\User;
  37. use App\Util\AccountTools;
  38. use App\Util\Api;
  39. use App\Util\AppLogger;
  40. use App\Util\TwoFactor;
  41. use App\Model\Autoresponder;
  42. use App\Model\Account;
  43. use App\Form\QUser\SpamAssassinLocales;
  44. use App\Model\LoginMessage;
  45. use App\Model\ProcmailRule;
  46. use App\Model\UserPref;
  47. use App\Model\Qs;
  48. use App\Model\ImapDir;
  49. use App\Form\QUser\SpamAssassinListsMass;
  50. use App\Form\QUser\AutomatedForward;
  51. use App\Twig\AppExtension;
  52. class QUserController extends AbstractController
  53. {
  54.     private $logger;
  55.     private $translator;
  56.     private $security;
  57.     private $params;
  58.     private $session;
  59.     private $mailer;
  60.     private $skin;
  61.     private $requestStack;
  62.     private $appExtension;
  63.     
  64.     public function __construct(AppLogger $loggerTranslatorInterface $translatorSecurity $security,
  65.         ParameterBagInterface $paramsMailerInterface $mailerRequestStack $requestStack,
  66.         AppExtension $appExtension)
  67.     {
  68.         $this->logger $logger;
  69.         $this->translator $translator;
  70.         $this->security $security;
  71.         $this->params $params;
  72.         $this->mailer $mailer;
  73.         $this->requestStack $requestStack;
  74.         $this->appExtension $appExtension;
  75.         $this->session $this->requestStack->getSession();
  76.         $this->_isReloadNeeded();
  77.         
  78.         $defaultSkin 'raw';
  79.         
  80.         if(isset($_SERVER['DEFAULT_SKIN'])) {
  81.             $defaultSkin $_SERVER['DEFAULT_SKIN'];
  82.         }
  83.         
  84.         $user $this->security->getUser();
  85.         $account $user $user->getAccount() : null;
  86.         
  87.         if(!is_null($account)) { // may be null for superadmin
  88.             $this->skin $account->findSOption('cfgSkin') == null $defaultSkin $account->findSOption('cfgSkin');
  89.         }
  90.         else {
  91.             $this->skin $defaultSkin;
  92.         }
  93.         
  94.         QUserController::overwriteEnvs();
  95.     }
  96.     
  97.     public static function overwriteEnvs()
  98.     {
  99.         // maybe we need to overwrite some envs
  100.         $license Api::getLicense();
  101.         if(array_key_exists('envs'$license) && (count($license['envs']) > 0)) {
  102.             foreach($license['envs'] as $e) {
  103.                 $eArr explode('='$e);
  104.                 
  105.                 if(count($eArr) != 2) {
  106.                     continue;
  107.                 }
  108.                 
  109.                 $_SERVER[$eArr[0]] = $eArr[1];
  110.             }
  111.         }
  112.     }
  113.     /**
  114.      * @Route("/panel", name="qu_main")
  115.      */
  116.     public function index(Request $request)
  117.     {
  118.         $locale $this->requestStack->getSession()->get(User::LOCALE_SESSION_NAME);
  119.         $account $this->security->getUser()->getAccount();
  120.         
  121.         try {
  122.             $version Api::getVersion();
  123.         }
  124.         catch(\Exception $e) {
  125.             $this->logger->log('Api::getVersion() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  126.             $this->addFlash('error'$this->translator->trans('Critical getting API version, contact administrator.'));
  127.             return $this->redirectToRoute("app_login");
  128.         }
  129.         
  130.         $modal null;
  131.         $showModal false;
  132.         
  133.         if(!$this->session->get('modalShown'false)) {
  134.             $msgs Api::listLoginMessages($account);
  135.             $this->session->set('modalShown'true);
  136.             
  137.             if(count($msgs) > 0) {
  138.                 $showModal true;
  139.                 $modal $msgs[0];
  140.                 // dismissing if must be shown only once
  141.                 if($modal->getMessageTrigger() == LoginMessage::MESSAGE_TRIGGER_AT_FIRST_LOGIN) {
  142.                     Api::loginMessageDismiss($account$modal->getId());
  143.                 }
  144.             }
  145.         }
  146.         
  147.         $showVersionWarning true;
  148.         
  149.         if(isset($_SERVER['APP_USERPANEL_SHOW_VERSION_WARNING']) && $_SERVER['APP_USERPANEL_SHOW_VERSION_WARNING'] == 'false') {
  150.             $showVersionWarning false;
  151.         }
  152.         
  153.         $response $this->render('skins/' $this->skin '/q_user/index.html.twig', [
  154.             'apiVersion' => $version,
  155.             'appVersion' => $this->params->get('app.version.panel'),
  156.             'showVersionWarning' => $showVersionWarning,
  157.             'showModal' => $showModal,
  158.             'modal' => $modal,
  159.         ]);
  160.                
  161.         if($locale != null && $locale != "") {
  162.             // save cookie with locales
  163.             $cookie Cookie::create(User::LOCALE_COOKIE_NAME$localetime() + 24*7*3600'/');
  164.             $response->headers->setCookie($cookie);
  165.         }
  166.         
  167.         return $response;
  168.     }
  169.     
  170.     /**
  171.      * password change
  172.      * @Route("/panel/password", name="qu_password")
  173.      */
  174.     public function password(Request $request)
  175.     {
  176.         $user $this->security->getUser();
  177.         $account $user->getAccount();
  178.         
  179.         // access to this module
  180.         $this->denyAccessUnlessGranted('PASSWORD_CHANGE'$account);
  181.         $this->denyAccessUnlessGranted('EDIT'$account);
  182.         
  183.         $form $this->createForm(PasswordChange::class);
  184.         $form->handleRequest($request);
  185.         
  186.         if($form->isSubmitted() && $form->isValid()) {
  187.             try {
  188.                 // check if provided password matches user current password
  189.                 if(!Api::checkPassword($user->getUserNamePart(), $user->getUserDomainPart(), $form->get('oldPassword')->getData())) {
  190.                     $this->addFlash('error'$this->translator->trans('Wrong current password. Password NOT changed'));
  191.                     
  192.                     return $this->render('skins/' $this->skin '/q_user/password.html.twig', [
  193.                         'form' => $form->createView(),
  194.                         'userEmail' => $user->getEmail(),
  195.                     ]);
  196.                 }
  197.                 
  198.                 // check if new password is different than the old one
  199.                 if($form->get('oldPassword')->getData() == $form->get('newPassword')->getData()) {
  200.                     $this->addFlash('error'$this->translator->trans('New password is the same as current password. Password NOT changed'));
  201.                     
  202.                     return $this->render('skins/' $this->skin '/q_user/password.html.twig', [
  203.                         'form' => $form->createView(),
  204.                         'userEmail' => $user->getEmail(),
  205.                     ]);
  206.                 }
  207.                         
  208.                 if(Api::changePassword($user->getUserNamePart(), $user->getUserDomainPart(), $form->get('newPassword')->getData())) {
  209.                     $this->addFlash('notice'$this->translator->trans('Password changed'));
  210.                     $this->logger->log('Password change'$request);
  211.                     //$request->getSession()->set('storedPassword', AccountTools::encryptString($form->get('newPassword')->getData()));
  212.                     $this->requestStack->getSession()->set('storedPassword'AccountTools::encryptString($form->get('newPassword')->getData()));
  213.                     
  214.                     if(!AccountTools::callExternalScript($user->getUserNamePart(), $user->getUserDomainPart(), 'quser''pwchange'$form->get('newPassword')->getData())) {
  215.                         $this->logger->log('Calling external script failed for changing password for an account'$request, ['accountName' => $user->getUserName()]);
  216.                     }
  217.                     return $this->redirectToRoute('qu_password');
  218.                 }
  219.                 else {
  220.                     $this->addFlash('error'$this->translator->trans('Password NOT changed - error'));
  221.                 }
  222.             }
  223.             catch(\Exception $e) {
  224.                 $this->logger->log('Api::changePassword() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  225.                 $this->addFlash('error'$this->translator->trans('Critical error changing password, contact administrator.'));
  226.                 return $this->redirectToRoute("qu_main");
  227.             }
  228.         }
  229.         elseif($form->isSubmitted() && !$form->isValid()){
  230.             $errorStr '';
  231.             $num 1;
  232.             $errorsCnt count($form->getErrors(true));
  233.             
  234.             foreach($form->getErrors(true) as $e) {
  235.                 $errorStr .= ($errorsCnt $num '. ' '') . lcfirst($e->getMessage()) . ' ';
  236.                 $num $num 1;
  237.             }
  238.             
  239.             $errorStr rtrim($errorStr);
  240.             
  241.             $this->addFlash('error'$this->translator->trans('Password NOT changed') . ': '.$errorStr,'');
  242.         }        
  243.             
  244.         return $this->render('skins/' $this->skin '/q_user/password.html.twig', [
  245.             'form' => $form->createView(),
  246.         ]);
  247.     }
  248.         
  249.     /**
  250.      * @Route("/panel/forward/{orderDir}", defaults={"orderDir"="asc"}, name="qu_forward", requirements={"orderDir"="asc|desc"})
  251.      */
  252.     public function forwarding($orderDirRequest $requestValidatorInterface $validatorPaginatorInterface $paginator)
  253.     {        
  254.         $user $this->security->getUser();
  255.         $account $user->getAccount();
  256.         $this->denyAccessUnlessGranted('FORWARD'$account);
  257.         $pagination $account->findSOption('cfgUserPagination') == null ?
  258.         (isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
  259.         : $account->findSOption('cfgUserPagination');
  260.         
  261.         $formMass $this->createForm(ForwardsMass::class);
  262.         $formAutomated $this->createForm(AutomatedForward::class);
  263.         $form $this->createForm(ForwardMail::class);
  264.         $form->handleRequest($request);
  265.         $forwardsErrors = [];
  266.         
  267.         try {
  268.             $forwards Api::getForwards($account);
  269.             $automated Api::listAutomatedForwards($account);
  270.             
  271.             if($orderDir == 'asc') {
  272.                 sort($forwards);
  273.             }
  274.             else {
  275.                 rsort($forwards);
  276.             }
  277.             
  278.             $localForwarding Api::getForwardLocal($account);
  279.         }
  280.         catch(\Exception $e) {
  281.             $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  282.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  283.             return $this->redirectToRoute('qu_main');
  284.         }
  285.              
  286.         try {
  287.             $disabledForwards Api::getDisabledForwards($account);
  288.             
  289.             if($orderDir == 'asc') {
  290.                 sort($forwards);
  291.             }
  292.             else {
  293.                 rsort($forwards);
  294.             }
  295.         }
  296.         catch(\Exception $e) {
  297.             $this->logger->log('Api::getDisabledForwards() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  298.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  299.             return $this->redirectToRoute('qu_main');
  300.         }
  301.         
  302.         $maxForwards $this->_maxForwards($account);
  303.         $maxExternalForwards $this->_maxExternalForwards($account);
  304.         
  305.         if(($maxForwards == -1) || ($maxExternalForwards == -1)) {
  306.             $this->addFlash('error'$this->translator->trans('Domain settings not available'));
  307.             $this->logger->log('Error while getting domain ' $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
  308.             return $this->redirectToRoute('qp_main');
  309.         }
  310.         
  311.         $procmailRulesCnt $this->_numberProcmailRulesEmail($account);
  312.         $procmailRulesExternalCnt $this->_numberProcmailRulesEmailExternal($account);
  313.         
  314.         if($form->isSubmitted() && $form->isValid()) {
  315.             $alreadyExists false;
  316.             $loopDetected false;
  317.             
  318.             $addresses explode(','$form->get('address')->getData());
  319.             $added false;
  320.             $affected = [];
  321.             $faultyAddresses = [];
  322.             
  323.             // first - checking existance & loops
  324.             foreach(array_unique($addresses) as $adr) {
  325.                 $adr trim($adr);
  326.                 
  327.                 foreach($forwards as $f) {
  328.                     if($adr == $f) {
  329.                         $alreadyExists true;
  330.                         $forwardsErrors[] = $this->translator->trans('Already exists');
  331.                         $faultyAddresses[] = $adr;
  332.                     }
  333.                 }
  334.                 
  335.                 if(!$alreadyExists) {
  336.                     if($adr == $user->getEmail()) {
  337.                         $loopDetected true;
  338.                         $forwardsErrors[] = $this->translator->trans('Loop detected');
  339.                         $faultyAddresses[] = $adr;
  340.                     }
  341.                     else {
  342.                         $forwardsErrors[] = '';
  343.                     }
  344.                 }                
  345.             }
  346.                 
  347.             if($alreadyExists || $loopDetected) {
  348.                 if($alreadyExists) {
  349.                     $this->addFlash('error'$this->translator->trans('Forwarding NOT set - already exists') . ': ' implode(', '$faultyAddresses));
  350.                 }
  351.                 else {
  352.                     $this->addFlash('error'$this->translator->trans('Forwarding NOT set - loop detected') . ': ' implode(', '$faultyAddresses));
  353.                 }
  354.                 
  355.                 $mixedForwardsArr self::_mixForwardsArrays($forwards$disabledForwards$orderDir);
  356.                 
  357.                 return $this->_showForwardingTemplate($request$form$formMass$formAutomated,
  358.                     $paginator$mixedForwardsArr$pagination$automated$forwards$procmailRulesCnt,
  359.                     $localForwarding$forwardsErrors$orderDir$maxForwards);
  360.             }
  361.                         
  362.             // check if limit of forwards is not exceeded
  363.             if((count($forwards) + count(array_unique($addresses)) + $procmailRulesCnt) > $maxForwards) {
  364.                 $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));
  365.                 
  366.                 $mixedForwardsArr self::_mixForwardsArrays($forwards$disabledForwards$orderDir);
  367.                 
  368.                 return $this->_showForwardingTemplate($request$form$formMass$formAutomated,
  369.                     $paginator$mixedForwardsArr$pagination$automated$forwards$procmailRulesCnt,
  370.                     $localForwarding$forwardsErrors$orderDir$maxForwards);
  371.             }
  372.             
  373.             // check if limit of external forwards is not exceeded
  374.             $externalForwardsCnt $this->_externalForwardsCount($forwards$user->getAccount());
  375.             $externalForwardsCurrentCnt $externalForwardsCnt;
  376.                         
  377.             foreach(array_unique($addresses) as $adr) {
  378.                 if(AccountTools::isEmailExternal($adr, [$user->getAccount()->getUserDomain()])) {
  379.                     $externalForwardsCurrentCnt++;
  380.                 }
  381.             }
  382.             
  383.             if(($externalForwardsCurrentCnt $procmailRulesExternalCnt) > $maxExternalForwards) {
  384.                 $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);
  385.                 
  386.                 $mixedForwardsArr self::_mixForwardsArrays($forwards$disabledForwards$orderDir);
  387.                 
  388.                 return $this->_showForwardingTemplate($request$form$formMass$formAutomated,
  389.                     $paginator$mixedForwardsArr$pagination$automated$forwards$procmailRulesCnt,
  390.                     $localForwarding$forwardsErrors$orderDir$maxForwards);
  391.             }
  392.             
  393.             foreach(array_unique($addresses) as $adr) {
  394.                 $adr trim($adr);    
  395.                 
  396.                 if(Api::addForward($account$adr)) {
  397.                     $added true;
  398.                     $affected[] = $adr;
  399.                 }
  400.             }
  401.             
  402.             if($added) {
  403.                 $this->addFlash('notice'$this->translator->trans('Forwarding set'));
  404.                 $this->addFlash('rowsAffected'implode(':'$affected)); // highlight the last one
  405.                 $this->logger->log('New forward(s) added'$request, ['forward' => implode(', '$affected)]);
  406.             }
  407.             else {
  408.                 $this->addFlash('error'$this->translator->trans('Forwarding NOT set'));
  409.             }
  410.             
  411.             return $this->redirectToRoute('qu_forward');
  412.         }
  413.         elseif($form->isSubmitted() && !$form->isValid()) {
  414.             $errors $form['address']->getErrors();
  415.             
  416.             // there are errors in address field
  417.             // check which one is problematic
  418.             if(count($errors)) {
  419.                 $checkAccount = new Account();
  420.                 
  421.                 foreach(explode(','$form->get('address')->getData()) as $usernameDomain) {
  422.                     $nameDomainArr explode('@'$usernameDomain);
  423.                     if(count($nameDomainArr) == 1) {
  424.                         // no domain
  425.                         $forwardsErrors[] = $this->translator->trans("No domain");
  426.                     }
  427.                     else {
  428.                         // check against validator
  429.                         $checkAccount->setUserName($nameDomainArr[0]);
  430.                         $checkAccount->setUserDomain($nameDomainArr[1]);
  431.                         
  432.                         // allow 1 character usernames
  433.                         if(strlen($nameDomainArr[0]) == 1) {
  434.                             $checkAccount->setUserName($nameDomainArr[0] . $nameDomainArr[0]);
  435.                         }
  436.                         
  437.                         $validationErrors $validator->validate($checkAccount);
  438.                         
  439.                         // check existance
  440.                         $alreadyExists false;
  441.                         
  442.                         foreach($forwards as $f) {
  443.                             if($usernameDomain == $f) {
  444.                                 $alreadyExists true;
  445.                             }
  446.                         }
  447.                         
  448.                         if(count($validationErrors)) {
  449.                             $veStr '';
  450.                             
  451.                             foreach($validationErrors as $ve) {
  452.                                 $veStr .= $ve->getMessage() . ' | ';
  453.                             }
  454.                             
  455.                             if($alreadyExists) {
  456.                                 $veStr .= $this->translator->trans(' | Already exists');
  457.                             }
  458.                             
  459.                             $forwardsErrors[] = rtrim($veStr' | ');
  460.                         }
  461.                         else {
  462.                             if($alreadyExists) {
  463.                                 $forwardsErrors[] = $this->translator->trans("Already exists");
  464.                             }
  465.                             else {
  466.                                 $forwardsErrors[] = "";
  467.                             }
  468.                         }
  469.                     }
  470.                 }
  471.             }
  472.             
  473.             $this->addFlash('error'$this->translator->trans('Forwarding NOT set'));
  474.         }   
  475.         
  476.         $mixedForwardsArr self::_mixForwardsArrays($forwards$disabledForwards$orderDir);
  477.                 
  478.         return $this->_showForwardingTemplate($request$form$formMass$formAutomated,
  479.             $paginator$mixedForwardsArr$pagination$automated$forwards$procmailRulesCnt,
  480.             $localForwarding$forwardsErrors$orderDir$maxForwards);
  481.     }
  482.     
  483.     private function _showForwardingTemplate($request$form$formMass$formAutomated,
  484.         $paginator$mixedForwardsArr$pagination$automated$forwards$procmailRulesCnt,
  485.         $localForwarding$forwardsErrors$orderDir$maxForwards)
  486.     {
  487.         return $this->render('skins/' $this->skin '/q_user/forward.html.twig', [
  488.             'form' => $form->createView(),
  489.             'formMass' => $formMass->createView(),
  490.             'formAutomated' => $formAutomated->createView(),
  491.             'forwards' => $paginator->paginate(
  492.                 $mixedForwardsArr$request->query->getInt('page'1), $pagination
  493.                 ),
  494.             'automatedForwards' => $automated,
  495.             'forwardsCount' => count($forwards) + $procmailRulesCnt,
  496.             'localForwarding' => $localForwarding,
  497.             'forwardsErrors' => $forwardsErrors,
  498.             'orderDir' => $orderDir,
  499.             'maxForwards' => $maxForwards,
  500.         ]); 
  501.     }
  502.     /**
  503.      * @Route("/panel/forward/mass", name="qu_forwards_mass")
  504.      */
  505.     public function forwardingMassAction(Request $request) {
  506.         $user $this->security->getUser();
  507.         $account $user->getAccount();
  508.         $this->denyAccessUnlessGranted('FORWARD'$account);
  509.         $form $this->createForm(ForwardsMass::class);
  510.         $form->handleRequest($request);
  511.             
  512.         if($form->isSubmitted() && $form->isValid()) {
  513.             $selected $request->request->get('forwardMassCheckbox');
  514.             $actionFailed false;
  515.                 
  516.             foreach($selected as $forward) {
  517.                 if(!Api::deleteForward($account$forward)) {
  518.                     $actionFailed true;
  519.                 }
  520.             }
  521.             
  522.             if($actionFailed) {
  523.                 $this->addFlash('error'$this->translator->trans('Forwards NOT deleted'));
  524.                 $this->logger->log('Error while deleting forward(s) (mass action)'$request, ['forward' => implode(', '$selected)]);
  525.             }
  526.             else {
  527.                 $this->addFlash('notice'$this->translator->trans('All forwards successfuly deleted'));
  528.                 $this->logger->log('Forward(s) deleted (mass action)'$request, ['forward' => implode(', '$selected)]);
  529.             }
  530.             
  531.             try {
  532.                 $forwards Api::getForwards($account);
  533.             }
  534.             catch(\Exception $e) {
  535.                 $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  536.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  537.                 return $this->redirectToRoute('qu_main');
  538.             }
  539.             
  540.             if(count($forwards) == 0) {
  541.                 $this->logger->log('All forwards deleted, local delivery activated'$request);
  542.                 $this->addFlash('notice'$this->translator->trans("You've removed all forwards, local delivery activated"));
  543.             }
  544.         }
  545.         
  546.         return $this->redirectToRoute("qu_forward");
  547.     }
  548.     
  549.     /**
  550.      * @Route("/panel/forward/automated", name="qu_forwards_automated")
  551.      */
  552.     public function automatedForwardingAction(Request $request) {
  553.         $user $this->security->getUser();
  554.         $account $user->getAccount();
  555.         $this->denyAccessUnlessGranted('FORWARD'$account);
  556.         $form $this->createForm(AutomatedForward::class);
  557.         $form->handleRequest($request);
  558.         
  559.         if($form->isSubmitted() && $form->isValid()) {
  560.             $activeFrom $form->get('activeFrom')->getData();
  561.             $activeFromHour $form->get('activeFromHour')->getData();
  562.             $activeFromMinute $form->get('activeFromMinute')->getData();
  563.             
  564.             $activeTo $form->get('activeTo')->getData();
  565.             $activeToHour $form->get('activeToHour')->getData();
  566.             $activeToMinute $form->get('activeToMinute')->getData();
  567.             
  568.             $tsFrom $activeFrom->getTimestamp() + $activeFromHour 3600 $activeFromMinute 60;
  569.             $tsTo $activeTo->getTimestamp() + $activeToHour 3600 $activeToMinute 60;
  570.             $address $form->get('address')->getData();
  571.             $activeOrDisabled $form->get('settingActiveOrDisabled')->getData();
  572.             $ret false;
  573.             
  574.             if($activeOrDisabled == 'D') {
  575.                 $ret Api::addAutomatedForward($account$address00$tsFrom$tsTo);
  576.             }
  577.             else {
  578.                 $ret Api::addAutomatedForward($account$address$tsFrom$tsTo00);
  579.             }
  580.             
  581.                         
  582.             if($ret == false) {
  583.                 $this->addFlash('error'$this->translator->trans('Unknown error - automatic forward NOT set'));
  584.                 $this->logger->log('Error while saving automated forward'$request, ['forward' => $address]);
  585.             }
  586.             else {
  587.                 $this->addFlash('notice'$this->translator->trans('Automatic forward successfuly set'));
  588.                 $this->logger->log('Automatic forward set'$request, ['forward' => $address]);
  589.             }
  590.         }
  591.         elseif($form->isSubmitted() && !$form->isValid()) {
  592.             $errors $form['activeTo']->getErrors();
  593.             $msg '';
  594.             
  595.             foreach($errors as $e) {
  596.                 $msg .= $e->getMessage();
  597.                 $msg .= ' ';
  598.             }
  599.             
  600.             $this->addFlash('error'$this->translator->trans('Automatic forward NOT set') . ': ' $msg);
  601.         }
  602.         
  603.         return $this->redirectToRoute("qu_forward");
  604.     }
  605.     
  606.     /**
  607.      * @Route("/panel/forward/edit/{forward}/{page}", defaults={"page"=1}, name="qu_forward_edit")
  608.      */
  609.     public function forwardEdit($forwardRequest $requestint $page)
  610.     {
  611.         $user $this->security->getUser();
  612.         $account $user->getAccount();
  613.         $this->denyAccessUnlessGranted('FORWARD'$account);
  614.         $form $this->createForm(ForwardMailEdit::class);
  615.         $form->handleRequest($request);
  616.         
  617.         if(!$form->isSubmitted()) {
  618.             $form->get('address')->setData($forward);
  619.         }
  620.         
  621.         try {
  622.             $forwards Api::getForwards($account);
  623.         }
  624.         catch(\Exception $e) {
  625.             $this->logger->log('Api::getForwards() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  626.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  627.             return $this->redirectToRoute('qu_main');
  628.         }
  629.         
  630.         if($form->isSubmitted() && $form->isValid()) {
  631.             $alreadyExists false;
  632.             $loopDetected false;
  633.             
  634.             if($forward == $form->get('address')->getData()) {
  635.                 $this->addFlash('notice'$this->translator->trans('Forwarding not changed'));
  636.                 return $this->redirectToRoute('qu_forward', ['page' => $page]);
  637.             }
  638.             
  639.             foreach($forwards as $f) {
  640.                 if($form->get('address')->getData() == $f) {
  641.                     $alreadyExists true;
  642.                 }
  643.             }
  644.             
  645.             if($alreadyExists) {
  646.                 $this->addFlash('error'$this->translator->trans('Forwarding NOT changed - already exists'));
  647.             }
  648.             
  649.             if($form->get('address')->getData() == $user->getEmail()) {
  650.                 $this->addFlash('error'$this->translator->trans('Forwarding NOT set - loop detected'));
  651.                 $loopDetected true;
  652.             }
  653.             
  654.             // check if limit of external forwards is not exceeded (if edit is from internal to external)
  655.             if(AccountTools::isEmailExternal($form->get('address')->getData(), [$account->getUserDomain()]) &&
  656.                 !AccountTools::isEmailExternal($forward, [$account->getUserDomain()])
  657.                 ) {
  658.                 $maxExternalForwards $this->_maxExternalForwards($account);
  659.                 
  660.                 if($maxExternalForwards == -1) {
  661.                     $this->addFlash('error'$this->translator->trans('Domain settings not available'));
  662.                     $this->logger->log('Error while getting domain ' $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
  663.                     return $this->redirectToRoute('qp_main');
  664.                 }
  665.                 
  666.                 try {
  667.                     $forwards Api::getForwards($account);                    
  668.                 }
  669.                 catch(\Exception $e) {
  670.                     $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  671.                     $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  672.                     return $this->redirectToRoute('qu_main');
  673.                 }
  674.                 
  675.                 $externalForwardsCnt $this->_externalForwardsCount($forwards$account);
  676.                 $externalRulesCnt $this->_numberProcmailRulesEmailExternal($account);
  677.                 
  678.                 if(($externalForwardsCnt $externalRulesCnt) >= $maxExternalForwards) {
  679.                     $this->addFlash('error'$this->translator->trans('Forwarding NOT changed - limit of maximum external forwards exceeded') . ' ('  $maxExternalForwards ')');
  680.                     
  681.                     return $this->render('skins/' $this->skin '/q_user/forward_edit.html.twig', [
  682.                         'form' => $form->createView(),
  683.                         'page' => $page,
  684.                     ]);
  685.                 }
  686.             }
  687.             
  688.             if(!$alreadyExists && !$loopDetected) {
  689.                 if(Api::addForward($account$form->get('address')->getData())) {
  690.                     if(!Api::deleteForward($account$forward)) {
  691.                         $this->logger->log('error while deleting old forward'$request, ['forward' => urldecode($forward)]);
  692.                         $this->addFlash('error'$this->translator->trans('Forward NOT deleted'));
  693.                     }
  694.                     
  695.                     $this->logger->log('Forward edited'$request, ['forwardOld' => urldecode($forward), 'forwardNew' => $form->get('address')->getData()]);
  696.                     $this->addFlash('notice'$this->translator->trans('Forwarding changed'));
  697.                     $this->addFlash('rowsAffected'$form->get('address')->getData());
  698.                     return $this->redirectToRoute('qu_forward', ['page' => $page]);
  699.                 }
  700.                 else {
  701.                     $this->addFlash('error'$this->translator->trans('Forwarding NOT changed'));
  702.                 }
  703.             }
  704.         }
  705.         elseif($form->isSubmitted() && !$form->isValid()){
  706.             $this->addFlash('error'$this->translator->trans('Forwarding NOT changed'));
  707.         }
  708.         
  709.         return $this->render('skins/' $this->skin '/q_user/forward_edit.html.twig', [
  710.             'form' => $form->createView(),
  711.             'page' => $page,
  712.         ]);
  713.     }
  714.     
  715.     /**
  716.      * @Route("/panel/forward/del/{forward}", name="qu_forward_del")
  717.      */
  718.     public function forwardDel($forwardRequest $request)
  719.     {
  720.         $user $this->security->getUser();
  721.         $account $user->getAccount();
  722.         $this->denyAccessUnlessGranted('FORWARD'$account);
  723.         
  724.         // first enable it to remove from disabled forwards table
  725.         Api::enableForward($account$forward);
  726.         
  727.         if(Api::deleteForward($account$forward)) {
  728.             $this->logger->log('Forward deleted'$request, ['forward' => urldecode($forward)]);
  729.             $this->addFlash('notice'$this->translator->trans('Forward deleted'));
  730.         }
  731.         else {
  732.             $this->logger->log('Error while deleting forward'$request, ['forward' => urldecode($forward)]);
  733.             $this->addFlash('error'$this->translator->trans('Forward NOT deleted'));
  734.         }
  735.         
  736.         if(!Api::deleteAutomatedForwardByAddress($account$forward)) {
  737.             $this->logger->log('Error while deleting automated forwards'$request, ['forward' => urldecode($forward)]);
  738.         }
  739.         
  740.         try {
  741.             $forwards Api::getForwards($account);
  742.         }
  743.         catch(\Exception $e) {
  744.             $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  745.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  746.             return $this->redirectToRoute('qu_main');
  747.         }
  748.         
  749.         if(count($forwards) == 0) {
  750.             $this->logger->log('Last forward deleted, local delivery activated'$request);
  751.             $this->addFlash('notice'$this->translator->trans("You've removed last existing forward, local delivery activated"));
  752.         }
  753.         
  754.         return $this->redirectToRoute("qu_forward");
  755.     }
  756.     
  757.     /**
  758.      * @Route("/panel/automatedforward/del/{id}", name="qu_automatedforward_del")
  759.      */
  760.     public function automatedForwardDel($idRequest $request)
  761.     {
  762.         $user $this->security->getUser();
  763.         $account $user->getAccount();
  764.         $this->denyAccessUnlessGranted('FORWARD'$account);
  765.         
  766.         if(Api::deleteAutomatedForward($account$id)) {
  767.             $this->logger->log('Automated forward rule deleted'$request, ['id' => $id]);
  768.             $this->addFlash('notice'$this->translator->trans('Automated forward rule deleted'));
  769.         }
  770.         else {
  771.             $this->logger->log('Error while deleting automated forward'$request, ['id' => $id]);
  772.             $this->addFlash('error'$this->translator->trans('Automated forward rule NOT deleted'));
  773.         }
  774.         
  775.         return $this->redirectToRoute("qu_forward");
  776.     }
  777.     
  778.     /**
  779.      * @Route("/panel/forward/disable/{forward}", name="qu_forward_disable")
  780.      */
  781.     public function forwardDisable($forwardRequest $request)
  782.     {
  783.         $user $this->security->getUser();
  784.         $account $user->getAccount();
  785.         $this->denyAccessUnlessGranted('FORWARD'$account);
  786.         
  787.         if(Api::disableForward($account$forward)) {
  788.             $this->logger->log('Forward disabled'$request, ['forward' => urldecode($forward)]);
  789.             $this->addFlash('notice'$this->translator->trans('Forward disabled'));
  790.         }
  791.         else {
  792.             $this->logger->log('Error while disabling forward'$request, ['forward' => urldecode($forward)]);
  793.             $this->addFlash('error'$this->translator->trans('Forward NOT disabled'));
  794.         }
  795.         
  796.         try {
  797.             $forwards Api::getForwards($account);
  798.         }
  799.         catch(\Exception $e) {
  800.             $this->logger->log('Api::getForwardsl() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  801.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  802.             return $this->redirectToRoute('qu_main');
  803.         }
  804.         
  805.         if(count($forwards) == 0) {
  806.             $this->logger->log('Last forward disabled, local delivery activated'$request);
  807.             $this->addFlash('notice'$this->translator->trans("You've removed last existing forward, local delivery activated"));
  808.         }
  809.         
  810.         return $this->redirectToRoute("qu_forward");
  811.     }
  812.     
  813.     /**
  814.      * @Route("/panel/forward/enable/{forward}", name="qu_forward_enable")
  815.      */
  816.     public function forwardEnable($forwardRequest $request)
  817.     {
  818.         $user $this->security->getUser();
  819.         $account $user->getAccount();
  820.         $this->denyAccessUnlessGranted('FORWARD'$account);
  821.         
  822.         // check limit
  823.         
  824.         try {
  825.             $forwards Api::getForwards($account);
  826.         }
  827.         catch(\Exception $e) {
  828.             $this->logger->log('Api::forwards() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  829.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  830.             return $this->redirectToRoute('qu_main');
  831.         }
  832.         
  833.         $maxForwards $this->_maxForwards($account);
  834.         $maxExternalForwards $this->_maxExternalForwards($account);
  835.         
  836.         if(($maxForwards == -1) || ($maxExternalForwards == -1)) {
  837.             $this->addFlash('error'$this->translator->trans('Domain settings not available'));
  838.             $this->logger->log('Error while getting domain ' $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
  839.             return $this->redirectToRoute('qp_main');
  840.         }
  841.         
  842.         $procmailRulesCnt $this->_numberProcmailRulesEmail($account);
  843.         
  844.         if((count($forwards) + $procmailRulesCnt) > $maxForwards) {
  845.             $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));
  846.             return $this->redirectToRoute('qu_forward');
  847.         }
  848.         
  849.         if(Api::enableForward($account$forward)) {
  850.             $this->logger->log('Forward enabled'$request, ['forward' => urldecode($forward)]);
  851.             $this->addFlash('notice'$this->translator->trans('Forward enabled'));
  852.         }
  853.         else {
  854.             $this->logger->log('Error while enabling forward'$request, ['forward' => urldecode($forward)]);
  855.             $this->addFlash('error'$this->translator->trans('Forward NOT enabled'));
  856.         }
  857.         
  858.         return $this->redirectToRoute("qu_forward");
  859.     }
  860.     
  861.     /**
  862.      * @Route("/panel/forward/localon", name="qu_forward_local_on")
  863.      */
  864.     public function forwardLocalOn(Request $request)
  865.     {
  866.         $user $this->security->getUser();
  867.         $account $user->getAccount();
  868.         $this->denyAccessUnlessGranted('FORWARD'$account);
  869.         
  870.         if(Api::forwardLocal($accounttrue)) {
  871.             $this->logger->log('Local forward activated'$request);
  872.             $this->addFlash('notice'$this->translator->trans('Local forward activated'));
  873.         }
  874.         else {
  875.             $this->addFlash('error'$this->translator->trans('Local forward NOT activated'));
  876.         }
  877.         
  878.         // redirect to spamassassin main page or to a specific subpage
  879.         $referer $request->headers->get('referer');
  880.         
  881.         if(strlen($referer))
  882.             return $this->redirect($referer);
  883.             
  884.         return $this->redirectToRoute("qu_forward");
  885.     }
  886.     
  887.     /**
  888.      * @Route("/panel/forward/localoff", name="qu_forward_local_off")
  889.      */
  890.     public function forwardLocalOff(Request $request)
  891.     {
  892.         $user $this->security->getUser();
  893.         $account $user->getAccount();
  894.         $this->denyAccessUnlessGranted('FORWARD'$account);
  895.         
  896.         if(Api::forwardLocal($accountfalse)) {
  897.             $this->logger->log('Local forward desactivated'$request);
  898.             $this->addFlash('notice'$this->translator->trans('Local forward desactivated'));
  899.         }
  900.         else {
  901.             $this->addFlash('error'$this->translator->trans('Local forward NOT desactivated'));
  902.         }
  903.         
  904.         return $this->redirectToRoute("qu_forward");
  905.     }
  906.     
  907.     /**
  908.      * @Route("/panel/autoresponder", name="qu_autoresponder")
  909.      */
  910.     public function autoresponder(Request $request)
  911.     {
  912.         $areAdvancedRulesAllowed false;
  913.         if(isset($_SERVER['APP_ADV_AUTORESP_ALLOWED']) && ($_SERVER['APP_ADV_AUTORESP_ALLOWED'] == 'true')) {
  914.             $areAdvancedRulesAllowed true;
  915.         }
  916.         $user $this->security->getUser();
  917.         $account $user->getAccount();
  918.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  919.         $autoresponderStatus '';
  920.         $autoresponder $this->_getAutoresponderForUser($account$autoresponderStatus);
  921.         $advancedRulesNumber 0;
  922.         if($areAdvancedRulesAllowed) {
  923.             if($autoresponderStatus != 'no') {
  924.                 $rules Api::getAutoresponderAdvRules($autoresponder->getId(), false);
  925.                 $advancedRulesNumber count($rules);
  926.             }
  927.         }
  928.         if($autoresponderStatus != 'no') {
  929.             $autorespFromRule Api::isAutoresponderFromRule($autoresponder->getUserName(), $autoresponder->getUserDomain());
  930.         }
  931.         else {
  932.             $autorespFromRule false;
  933.         }
  934.         
  935.         
  936.         $form $this->createForm(AutoresponderForm::class, $autoresponder);
  937.         $form->handleRequest($request);
  938.         $needSetOwnPrefix false// do we need to show user's own subject input field
  939.                 
  940.         if(!$form->isSubmitted()) {
  941.             if($autoresponderStatus == 'no') {
  942.                 if(isset($_SERVER['APP_AUTOOPT_TIMELIMIT'])) {
  943.                     $timeLimit = (int)$_SERVER['APP_AUTOOPT_TIMELIMIT'];
  944.                 }
  945.                 else {
  946.                     $timeLimit 24 3600// tydzieÅ„
  947.                 }
  948.                 $timeLimitArr Autoresponder::timelimitSplit($timeLimit);
  949.                 $form->get('periodWeeks')->setData($timeLimitArr['weeks']);
  950.                 $form->get('periodDays')->setData($timeLimitArr['days']);
  951.                 $form->get('periodHours')->setData($timeLimitArr['hours']);
  952.                 $form->get('messagesLimit')->setData(isset($_SERVER['APP_AUTOOPT_MSGLIMIT']) ? $_SERVER['APP_AUTOOPT_MSGLIMIT'] : 1);
  953.                 $form->get('copyLines')->setData(isset($_SERVER['APP_AUTOOPT_NUMLINES']) ? $_SERVER['APP_AUTOOPT_NUMLINES'] : 5);
  954.                 
  955.                 if(isset($_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'])) {
  956.                     // if it doesn't end with space, we need to add it to have a match with the form
  957.                     if(substr($_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'], -1) == ' ') {
  958.                         $prefixToSet $_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'];
  959.                     }
  960.                     else {
  961.                         $prefixToSet $_SERVER['APP_AUTOOPT_SUBJECT_PREFIX'] . ' ';
  962.                     }
  963.                     
  964.                     $form->get('subject')->setData($prefixToSet);
  965.                 }
  966.                 
  967.             }
  968.             
  969.             // dd($autoresponder);
  970.             // user's subject and prefix are kept in the same field in GUI (ownSubject) but not in Autoresponder object
  971.             // own subject is in Autoresponder::ownSubject field, own prefix in Autoresponder::subject
  972.             //
  973.             // if subject is empty it means user has his own subject - we have to manually change state of the select in GUI
  974.             if($autoresponder->getSubject() == '' && strlen($autoresponder->getOwnSubject()) > 0) {
  975.                 $form->get('subject')->setData('own');
  976.                 $needSetOwnPrefix true;
  977.             }
  978.             elseif($autoresponder->getSubject() != '') {
  979.                 $needSetOwnPrefix true;
  980.                 
  981.                 // if user has his own prefix we have to detect it and manually change state of the select in GUI
  982.                 // so if the object's subject is not one of the choices it must be own prefix 
  983.                 foreach(AutoresponderForm::getSubjectChoices() as $v) {
  984.                     if($autoresponder->getSubject() == $this->translator->trans($v)) {
  985.                         $needSetOwnPrefix false;
  986.                         break;
  987.                     }
  988.                 }
  989.                 
  990.                 if($needSetOwnPrefix) {
  991.                     $form->get('ownSubject')->setData($autoresponder->getSubject());
  992.                     $form->get('subject')->setData('ownPrefix');
  993.                 }
  994.             }
  995.         }
  996.         
  997.         if($form->isSubmitted() && $form->isValid()) {
  998.             $autoresponder->setUserName($account->getUserName());
  999.             $autoresponder->setUserDomain($account->getUserDomain());
  1000.             
  1001.             if(Api::addAutoresponder($autoresponder)) {
  1002.                 if($autoresponderStatus == 'no') {
  1003.                     $this->logger->log('New autoresponder added'$request);
  1004.                 }
  1005.                 else {
  1006.                     $this->logger->log('Autoresponder changed'$request);
  1007.                 }
  1008.                 $this->addFlash('notice'$this->translator->trans('Autoresponder set'));
  1009.                 
  1010.                 if($autoresponder->getActivationType() == 'auto') {
  1011.                     $now = new \DateTime("now");
  1012.                     //$now->setTime(0, 0, 0);
  1013.                                         
  1014.                     if(($autoresponderStatus == 'inactive' || $autoresponderStatus == 'no') && 
  1015.                         ($autoresponder->getActiveFromWithMinutes() <= $now) && ($autoresponder->getActiveToWithMinutes() >= $now)) {
  1016.                         return $this->redirectToRoute('qu_autoresponder_activate');
  1017.                     }
  1018.                     
  1019.                     if(($autoresponderStatus == 'active') &&
  1020.                         (($autoresponder->getActiveFromWithMinutes() > $now) || ($autoresponder->getActiveToWithMinutes() < $now))) {
  1021.                         return $this->redirectToRoute('qu_autoresponder_desactivate');
  1022.                     }
  1023.                 }
  1024.                 
  1025.                 return $this->redirectToRoute('qu_autoresponder');
  1026.             }
  1027.             else {
  1028.                 $this->addFlash('error'$this->translator->trans('Autoresponder NOT set'));
  1029.             }
  1030.             
  1031.             return $this->redirectToRoute('qu_autoresponder');
  1032.         }
  1033.         elseif($form->isSubmitted() && !$form->isValid()){
  1034.             if(count($form['ownSubject']->getErrors()) > 0) {
  1035.                 $needSetOwnPrefix true;
  1036.             }
  1037.             $this->addFlash('error'$this->translator->trans('Autoresponder NOT set'));
  1038.         }
  1039.         
  1040.         return $this->render('skins/' $this->skin '/q_user/autoresponder.html.twig', [
  1041.             'form' => $form->createView(),
  1042.             'autoresponderStatus' => $autoresponderStatus,
  1043.             'autoresponder' => $autoresponder,
  1044.             'setOwnPrefix' => $needSetOwnPrefix,
  1045.             'autoresponderFromRule' => $autorespFromRule,
  1046.             'advancedRulesNumber' => $advancedRulesNumber,
  1047.         ]);
  1048.         
  1049.     }
  1050.     
  1051.     /**
  1052.      * @Route("/panel/autoresponder/activate", name="qu_autoresponder_activate")
  1053.      */
  1054.     public function autoresponderActivate(Request $request)
  1055.     {
  1056.         $user $this->security->getUser();
  1057.         $account $user->getAccount();
  1058.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  1059.                 
  1060.         try {
  1061.             $autoresponder Api::getAutoresponder(Autoresponder::NOT_ACTIVE_PREFIX $account->getUserName(),
  1062.                 Autoresponder::NOT_ACTIVE_PREFIX $account->getUserDomain());
  1063.         }
  1064.         catch(\Exception $e) {
  1065.             $this->logger->log('Trying to set active not existing autoresponder'$request);
  1066.             $this->addFlash('error'$this->translator->trans('Autoresponder NOT set active'));
  1067.             return $this->redirectToRoute('qu_autoresponder');
  1068.         }
  1069.         try {
  1070.             Api::activateAutoresponder($autoresponder);
  1071.             $this->logger->log('Autoresponder activated'$request);
  1072.         }
  1073.         catch(\Exception $e) {
  1074.             $this->logger->log('Error while setting autoresponder active'$request);
  1075.             $this->addFlash('error'$this->translator->trans('Autoresponder NOT set active'));
  1076.             return $this->redirectToRoute('qu_autoresponder');
  1077.         }
  1078.         
  1079.         $this->addFlash('notice'$this->translator->trans('Autoresponder set active'));
  1080.         return $this->redirectToRoute('qu_autoresponder');
  1081.     }
  1082.     /**
  1083.      * @Route("/panel/autoresponder/desactivate", name="qu_autoresponder_desactivate")
  1084.      */
  1085.     public function autoresponderDesactivate(Request $request)
  1086.     {
  1087.         $user $this->security->getUser();
  1088.         $account $user->getAccount();
  1089.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  1090.         
  1091.         try {
  1092.             $autoresponder Api::getAutoresponder($account->getUserName(), $account->getUserDomain());
  1093.         }
  1094.         catch(\Exception $e) {
  1095.             $this->logger->log('Trying to set inactive not existing autoresponder'$request);
  1096.             $this->addFlash('error'$this->translator->trans('Autoresponder NOT set inactive'));
  1097.             return $this->redirectToRoute('qu_autoresponder');
  1098.         }
  1099.         
  1100.         try {
  1101.             Api::desactivateAutoresponder($autoresponder);
  1102.             $this->logger->log('Autoresponder desactivated'$request);
  1103.         }
  1104.         catch(\Exception $e) {
  1105.             $this->logger->log('Error while setting autoresponder inactive'$request);
  1106.             $this->addFlash('error'$this->translator->trans('Autoresponder NOT set inactive'));
  1107.             return $this->redirectToRoute('qu_autoresponder');
  1108.         }
  1109.         
  1110.         $this->addFlash('notice'$this->translator->trans('Autoresponder set inactive'));
  1111.         return $this->redirectToRoute('qu_autoresponder');
  1112.     }
  1113.     
  1114.     /**
  1115.      * @Route("/panel/autoresponder/del", name="qu_autoresponder_del")
  1116.      */
  1117.     public function autoresponderDelete(Request $request)
  1118.     {
  1119.         $user $this->security->getUser();
  1120.         $account $user->getAccount();
  1121.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  1122.         $autoresponderStatus 'no';
  1123.         
  1124.         $autoresponder $this->_getAutoresponderForUser($account$autoresponderStatus);
  1125.         
  1126.         if($autoresponderStatus == 'active') {
  1127.             // we should first make the autoresponder inactive
  1128.         
  1129.             if(!Api::desactivateAutoresponder($autoresponder)) {
  1130.                 $this->logger->log('Error while trying to delete autoresponder - deactivation failed'$request, [], 'critical');
  1131.                 $this->addFlash('error'$this->translator->trans('Autoresponder NOT deleted'));
  1132.                 return $this->redirectToRoute('qu_autoresponder');
  1133.             }
  1134.         }
  1135.          
  1136.         if($autoresponderStatus != 'no') {
  1137.             if(Api::deleteAutoresponder($account)) {
  1138.                 $this->logger->log('Autoresponder deleted'$request);
  1139.                 // delete also advanced rules
  1140.                 Api::deleteAutoresponderAdvRulesForUser($account);
  1141.                 // delete copy of the autoresponder
  1142.                 Api::deleteAutoresponderCopy($account);
  1143.                 $this->addFlash('notice'$this->translator->trans('Autoresponder deleted'));
  1144.             }
  1145.             else {
  1146.                 $this->logger->log('Error while trying to delete autoresponder'$request, [], 'critical');
  1147.                 $this->addFlash('error'$this->translator->trans('Autoresponder NOT deleted'));
  1148.             }
  1149.         }
  1150.         else {
  1151.             $this->logger->log('Error while trying to delete not existing autoresponder'$request, [], 'critical');
  1152.             $this->addFlash('error'$this->translator->trans('Autoresponder NOT deleted'));
  1153.         }
  1154.         
  1155.         return $this->redirectToRoute('qu_autoresponder');
  1156.     }
  1157.     /**
  1158.      * @Route("/panel/autoresponder/recipients", name="qu_autoresponder_recipients")
  1159.      */
  1160.     public function autoresponderRecipients(Request $request)
  1161.     {
  1162.         $user $this->security->getUser();
  1163.         $account $user->getAccount();
  1164.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  1165.         
  1166.         $autoresponderStatus '';
  1167.         $autoresponder $this->_getAutoresponderForUser($account$autoresponderStatus);
  1168.         
  1169.         $recipients = [];
  1170.             
  1171.         if($autoresponderStatus != 'no') {
  1172.             try {
  1173.                 $recipients Api::getAutoresponderRecipients($autoresponder->getId(), $autoresponder->timeLimit());
  1174.             }
  1175.             catch(\Exception $e) {
  1176.                 $this->logger->log('Error while getting autoresponder recipients'$request);
  1177.                 $this->addFlash('error'$this->translator->trans('Error while loading autoresponder recipients'));
  1178.                 return $this->redirectToRoute('qu_autoresponder');
  1179.             }
  1180.         }
  1181.         
  1182.         return $this->render('skins/' $this->skin '/q_user/autoresponder_recipients.html.twig', [
  1183.             'recipients' => $recipients,
  1184.             'autoresponder' => $autoresponder,
  1185.         ]);
  1186.     }
  1187.     
  1188.     /**
  1189.      * @Route("/panel/autoresponder/delrcpt/{rcpt}", name="qu_autoresponder_del_rcpt")
  1190.      */
  1191.     public function autoresponderDeleteRecipient(String $rcptRequest $request)
  1192.     {
  1193.         $user $this->security->getUser();
  1194.         $account $user->getAccount();
  1195.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  1196.         $autoresponderStatus '';
  1197.         $autoresponder $this->_getAutoresponderForUser($account$autoresponderStatus);
  1198.         
  1199.         if($autoresponderStatus == 'no') {
  1200.             $this->logger->log('Error while getting autoresponder for deleting recipient'$request, ['rcpt' => $rcpt]);
  1201.             $this->addFlash('error'$this->translator->trans('Error while loading autoresponder'));
  1202.             return $this->redirectToRoute('qu_autoresponder');
  1203.         }
  1204.         
  1205.         if(Api::deleteAutoresponderRecipients($autoresponder->getId(), $rcpt)) {
  1206.             $this->logger->log('Autoresponder recipient deleted'$request, ['rcpt' => $rcpt]);
  1207.             $this->addFlash('notice'$this->translator->trans('Autoresponder\'s recipient deleted'));
  1208.         }
  1209.         else {
  1210.             $this->logger->log('Error while trying to delete autoresponder\'s recipient'$request, ['rcpt' => $rcpt], 'critical');
  1211.             $this->addFlash('error'$this->translator->trans('Autoresponder\'s recipient NOT deleted'));
  1212.         }
  1213.         
  1214.         return $this->redirectToRoute('qu_autoresponder_recipients');
  1215.     }
  1216.     
  1217.     /**
  1218.      * @Route("/panel/autoresponder/advrules", name="qu_autoresponder_adv_rules")
  1219.      */
  1220.     public function autoresponderAdvancedRules(Request $request)
  1221.     {
  1222.         if(!isset($_SERVER['APP_ADV_AUTORESP_ALLOWED'])) {
  1223.             exit;
  1224.         }
  1225.         if(isset($_SERVER['APP_ADV_AUTORESP_ALLOWED']) && ($_SERVER['APP_ADV_AUTORESP_ALLOWED'] == 'false')) {
  1226.             exit;
  1227.         }
  1228.         
  1229.         $user $this->security->getUser();
  1230.         $account $user->getAccount();
  1231.         $this->denyAccessUnlessGranted('AUTORESPONDER'$account);
  1232.         $autoresponderStatus '';
  1233.         $autoresponder $this->_getAutoresponderForUser($account$autoresponderStatus);
  1234.         if($autoresponderStatus == 'no') {
  1235.             return $this->redirectToRoute('qu_autoresponder');
  1236.         }
  1237.         
  1238.         $needSetOwnPrefix false// do we need to show user's own subject input field
  1239.         $needSetOwnPrefixes = [];
  1240.         $form $this->createForm(AutoresponderAdvRulesForm::class, $autoresponder);
  1241.         $form->handleRequest($request);                
  1242.         if(!$form->isSubmitted()) {
  1243.             $rules Api::getAutoresponderAdvRules($autoresponder->getId(), false);
  1244.             $form->get('advRules')->setData($rules);
  1245.             // now own subject / own prefix for each rule
  1246.             foreach($rules as $rIdx => $r) {
  1247.                 // user's subject and prefix are kept in the same field in GUI (ownSubject) but not in Autoresponder object
  1248.                 // own subject is in Autoresponder::ownSubject field, own prefix in Autoresponder::subject
  1249.                 //
  1250.                 // if subject is empty it means user has his own subject - we have to manually change state of the select in GUI
  1251.                 if($r['subject'] == '' && strlen($r['ownSubject']) > 0) {
  1252.                     foreach($form->get('advRules')->all() as $childName => $childForm) {
  1253.                         if($childName == $rIdx) {
  1254.                             $childForm->get('subject')->setData('own');
  1255.                         }    
  1256.                     }
  1257.                     
  1258.                     $needSetOwnPrefix true;
  1259.                 }
  1260.                 elseif($r['subject'] != '') {
  1261.                     $needSetOwnPrefix true;
  1262.                     
  1263.                     // if user has his own prefix we have to detect it and manually change state of the select in GUI
  1264.                     // so if the object's subject is not one of the choices it must be own prefix 
  1265.                     foreach(AutoresponderForm::getSubjectChoices() as $v) {
  1266.                         if($r['subject'] == $this->translator->trans($v)) {
  1267.                             $needSetOwnPrefix false;
  1268.                             break;
  1269.                         }
  1270.                     }
  1271.                     if($needSetOwnPrefix) {
  1272.                         foreach($form->get('advRules')->all() as $childName => $childForm) {
  1273.                             if($childName == $rIdx) {
  1274.                                 $childForm->get('ownSubject')->setData($r['subject']);
  1275.                                 $childForm->get('subject')->setData('ownPrefix');
  1276.                             }    
  1277.                         }
  1278.                     }
  1279.                 }
  1280.                 $needSetOwnPrefixes[$rIdx] = $needSetOwnPrefix;
  1281.             }
  1282.         }
  1283.         else {
  1284.             if($form->isValid()) {
  1285.                 $autoresponder->setUserName($account->getUserName());
  1286.                 $autoresponder->setUserDomain($account->getUserDomain());
  1287.                 // delete rules that are no longer in form
  1288.                 $formData $form->get('advRules')->getData();
  1289.                 $formDataIds = [];
  1290.                 
  1291.                 foreach($formData as $row) {
  1292.                     $formDataIds[] = $row['id'];
  1293.                 }
  1294.                 $rules Api::getAutoresponderAdvRules($autoresponder->getId(), false);
  1295.                 foreach($rules as $rule) {
  1296.                     if(!in_array($rule['id'], $formDataIds)) {
  1297.                         Api::deleteAutoresponderRule($rule['id']);
  1298.                     }
  1299.                 }
  1300.                 if(Api::addAutoresponderRules($autoresponder$form->get('advRules')->getData())) {
  1301.                     if($autoresponderStatus == 'no') {
  1302.                         $this->logger->log('New autoresponder rule(s) added'$request);
  1303.                     }
  1304.                     else {
  1305.                         $this->logger->log('Autoresponder rule(s) changed'$request);
  1306.                     }
  1307.                     $this->addFlash('notice'$this->translator->trans('Autoresponder rules set'));
  1308.                     // check if there is no conflict in rules
  1309.                     $rules Api::getAutoresponderAdvRules($autoresponder->getId(), false);
  1310.                     $activationTimeArr = [];
  1311.                     
  1312.                     for($i 0$i count($rules); $i++) {
  1313.                         if($rules[$i]['activeOnceConsumed']) {
  1314.                             continue;
  1315.                         }
  1316.                         $activationTime $rules[$i]['activationHour'] * 60 $rules[$i]['activationMinute'];
  1317.                         foreach($activationTimeArr as $k => $v) {
  1318.                             if($activationTime == $v) {
  1319.                                 // time is the same
  1320.                                 // now check the date
  1321.                                 $theSameDay false;
  1322.                                 if(!$rules[$i]['activeOnce']) {
  1323.                                     if($rules[$k]['activeOnce']) {
  1324.                                         $dayOfWeekNumeric $rules[$k]['activeOnceDate']->format('w');
  1325.                                         // dd($dayOfWeekNumeric);
  1326.                                         
  1327.                                         $activeDayVar 'activeDay' $dayOfWeekNumeric;
  1328.                                         if($rules[$i][$activeDayVar] == true) {
  1329.                                             $theSameDay true;
  1330.                                         }
  1331.                                     }
  1332.                                     else {
  1333.                                         for($j 1$j 8$j++) {
  1334.                                             $activeDayVar 'activeDay' $j;
  1335.         
  1336.                                             if(($rules[$i][$activeDayVar] == true) && ($rules[$k][$activeDayVar] == true)) {
  1337.                                                 $theSameDay true;
  1338.                                             }
  1339.                                         }
  1340.                                     }
  1341.                                 }
  1342.                                 else {
  1343.                                     // previous rule is activeOnce, checking one day of week
  1344.                                     if($rules[$k]['activeOnce']) {
  1345.                                         // is the same date?
  1346.                                         if ($rules[$i]['activeOnceDate']->format('Y-m-d') === $rules[$k]['activeOnceDate']->format('Y-m-d')) {
  1347.                                             $theSameDay true;
  1348.                                         }
  1349.                                     }
  1350.                                     else { // previous rule is not activeOnce
  1351.                                         $dayOfWeekNumeric $rules[$i]['activeOnceDate']->format('w');
  1352.                                         $activeDayVar 'activeDay' $dayOfWeekNumeric;
  1353.                                         if($rules[$k][$activeDayVar] == true) {
  1354.                                             $theSameDay true;
  1355.                                         }
  1356.                                     }
  1357.                                 }
  1358.                                 if($theSameDay) {
  1359.                                     $this->addFlash('error'$this->translator->trans('Warning! Rules conflict. Rule number') . ' ' . ($i 1) . ' ' $this->translator->trans('with rule number') . ' ' . ($k 1));
  1360.                                     break;
  1361.                                 }                                
  1362.                             }
  1363.                         
  1364.                         }
  1365.                         $activationTimeArr[$i] = $activationTime;
  1366.                     }
  1367.                     
  1368.                     return $this->redirectToRoute('qu_autoresponder_adv_rules');
  1369.                 }
  1370.                 else {
  1371.                     $this->addFlash('error'$this->translator->trans('Autoresponder NOT set'));
  1372.                 }
  1373.                 
  1374.                 return $this->redirectToRoute('qu_autoresponder_adv_rules');
  1375.             }
  1376.             else {
  1377.                 echo "not valid"; exit;
  1378.             }
  1379.             
  1380.         }
  1381.         
  1382.         return $this->render('skins/' $this->skin '/q_user/autoresponder_adv_rules.html.twig', [
  1383.             'form' => $form->createView(),
  1384.             'autoresponderStatus' => $autoresponderStatus,
  1385.             'autoresponder' => $autoresponder,
  1386.             'setOwnPrefixes' => $needSetOwnPrefixes,
  1387.             // 'rules' -> $rules,
  1388.         ]);
  1389.         
  1390.     }
  1391.     /**
  1392.      * @Route("/panel/spamassassin", name="qu_sa")
  1393.      */
  1394.     public function spamAssassin(Request $request)
  1395.     {        
  1396.         $user $this->security->getUser();
  1397.         $account $user->getAccount();
  1398.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1399.         $antispamOn $this->_isAntispamOn($account);
  1400.         
  1401.         return $this->render('skins/' $this->skin '/q_user/spamassassin.html.twig', [
  1402.             'antispamOn' => $antispamOn,
  1403.         ]);
  1404.         
  1405.     }
  1406.     /**
  1407.      * @Route("/panel/spamassassin/change_activity", name="qu_sa_change_activity")
  1408.      */
  1409.     public function spamAssassinChangeActivity(Request $request)
  1410.     {
  1411.         $user $this->security->getUser();
  1412.         $account $user->getAccount();
  1413.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1414.         
  1415.         if(Api::getSAProtection($account)) {
  1416.             Api::saProtection($accountfalse);
  1417.             $this->logger->log('Antispam protection desactivated'$request);
  1418.         }
  1419.         else {
  1420.             Api::saProtection($accounttrue);
  1421.             $this->logger->log('Antispam protection activated'$request);
  1422.         }
  1423.         
  1424.         // redirect to spamassassin main page or to a specific subpage
  1425.         $referer $request->headers->get('referer');
  1426.         
  1427.         if(strlen($referer))
  1428.             return $this->redirect($referer);
  1429.         
  1430.         return $this->redirectToRoute('qu_sa');
  1431.     }
  1432.     
  1433.     /**
  1434.      * @Route("/panel/spamassassin/score", name="qu_sa_score")
  1435.      */
  1436.     public function spamAssassinScore(Request $request)
  1437.     {
  1438.         $user $this->security->getUser();
  1439.         $account $user->getAccount();
  1440.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1441.         
  1442.         $antispamOn $this->_isAntispamOn($account);
  1443.         
  1444.         $form $this->createForm(SpamAssassinScore::class);
  1445.         $form->handleRequest($request);
  1446.         
  1447.         $saPref null;
  1448.         $qsPref null;
  1449.         
  1450.         try {
  1451.             foreach(Api::getSAPrefVal($account'required_score') as $pref) {
  1452.                 $saPref $pref;
  1453.                 break;
  1454.             }
  1455.             
  1456.             foreach(Api::getQS($account) as $pref) {
  1457.                 $qsPref $pref;
  1458.                 break;
  1459.             }
  1460.         }
  1461.         catch(\Exception $e) {}
  1462.         
  1463.         if($saPref) {
  1464.             $sliderRangeScoreVal $saPref->getValue();
  1465.         }
  1466.         else {
  1467.             $sliderRangeScoreVal UserPref::DEFAULT_SPAM_SCORE;
  1468.         }
  1469.         
  1470.         $saMaxScore $account->findSOption('cfgSAMaxScore') == null UserPref::SA_MAX_SCORE $account->findSOption('cfgSAMaxScore');
  1471.         
  1472.         $neverDelete false;
  1473.         
  1474.         if($qsPref) {
  1475.             // these values are stored as delta - we have to add them to user's "score" value
  1476.             $sliderRangeValMin $qsPref->getQuarantine() + $sliderRangeScoreVal;
  1477.             $prefix $qsPref->getSubject();
  1478.             
  1479.             // if getDel() is 0, it means "never delete" is enabled
  1480.             if($qsPref->getDel() == 0) {
  1481.                 $neverDelete true;
  1482.                 // don't set sliderRangeValMax, use max value instead
  1483.                 $sliderRangeValMax $saMaxScore;
  1484.             }
  1485.             else {
  1486.                 $sliderRangeValMax $qsPref->getDel() + $sliderRangeScoreVal;
  1487.             }
  1488.             
  1489.             // if given value is exactly less by 0.05 it means it is 0 but was written to the database this way
  1490.             // because setting 0 switches off given funcionality completely
  1491.             if($sliderRangeValMin 0.05 == $sliderRangeScoreVal) {
  1492.                 $sliderRangeValMin $sliderRangeScoreVal;
  1493.             }
  1494.             
  1495.             if(!$neverDelete && $sliderRangeValMax 0.05 == $sliderRangeScoreVal) {
  1496.                 $sliderRangeValMax $sliderRangeScoreVal;
  1497.             }            
  1498.         }
  1499.         else {
  1500.             $sliderRangeValMin UserPref::DEFAULT_QUARANTINE_THRESHOLD $sliderRangeScoreVal;
  1501.             $sliderRangeValMax UserPref::DEFAULT_DELETE_THRESHOLD $sliderRangeScoreVal;
  1502.             $prefix null;
  1503.         }
  1504.          
  1505.         if(!$form->isSubmitted()) {
  1506.             $form->get('score')->setData($sliderRangeScoreVal);
  1507.             $form->get('ok')->setData($sliderRangeScoreVal ' - ' $sliderRangeValMin);
  1508.             $form->get('quarantine')->setData($sliderRangeValMin ' - ' $sliderRangeValMax);
  1509.             $neverDeleteText $this->translator->trans('NIGDY');
  1510.             $form->get('delete')->setData($neverDelete $neverDeleteText $sliderRangeValMax);
  1511.             $form->get('neverDelete')->setData($neverDelete);
  1512.             
  1513.             if($prefix != null) {
  1514.                 $form->get('prefix')->setData($prefix);
  1515.             }
  1516.         }
  1517.         
  1518.         if($form->isSubmitted() && $form->isValid()) {
  1519.             if($saPref == null) {
  1520.                 $saPref = new UserPref();
  1521.             }
  1522.             
  1523.             $saPref->setUsername($account->userAddress());
  1524.             $saPref->setPreference('required_score');
  1525.             $saPref->setValue($form->get('score')->getData());
  1526.             
  1527.             try {
  1528.                 Api::saveUserPref($saPref);
  1529.             }
  1530.             catch(\Exception $e) {
  1531.                 $this->logger->log('Api::saveUserPref() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  1532.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1533.                 return $this->redirectToRoute('qu_sa_score');
  1534.             }
  1535.             
  1536.             if($qsPref == null) {
  1537.                 $qsPref = new Qs();
  1538.             }
  1539.             
  1540.             $qsPref->setAddress($account->userAddress());
  1541.             $valOK explode(' - '$form->get('ok')->getData());
  1542.             $qsPref->setQuarantine($valOK[1] - $form->get('score')->getData());
  1543.             
  1544.             // if "never delete" checkbox is checked, set del to 0
  1545.             if($form->get('neverDelete')->getData()) {
  1546.                 $qsPref->setDel(0);
  1547.             }
  1548.             else {
  1549.                 $deleteValue $form->get('delete')->getData();
  1550.                 $neverDeleteText $this->translator->trans('NIGDY');
  1551.                 // if delete value is "NIGDY" (translated) or not numeric, use max value
  1552.                 if($deleteValue === $neverDeleteText || !is_numeric($deleteValue)) {
  1553.                     $deleteValue $saMaxScore;
  1554.                 }
  1555.                 $qsPref->setDel($deleteValue $form->get('score')->getData());
  1556.             }
  1557.             
  1558.             if($form->get('prefix')->getData() == null) {
  1559.                 $qsPref->setSubject('');
  1560.             }
  1561.             else {
  1562.                 $qsPref->setSubject($form->get('prefix')->getData());
  1563.             }
  1564.             
  1565.             // Qs default values
  1566.             $scanners 'clamdscan_scanner,sa,perlscan_scanner';
  1567.             
  1568.             if(isset($_SERVER['APP_QS_SCANNERS'])) {
  1569.                 $scanners $_SERVER['APP_QS_SCANNERS'];
  1570.             }
  1571.             
  1572.             $qsPref->setScanners($scanners);
  1573.             $qsPref->setDelta(0);
  1574.             $qsPref->setReject(0);
  1575.             $qsPref->setForward('none');
  1576.             $qsPref->setForwardVerbose(0);
  1577.             $qsPref->setHdrReport(0);
  1578.             $qsPref->setSpamdir('spam');
  1579.             
  1580.             try {
  1581.                 Api::saveQs($qsPref);
  1582.             }
  1583.             catch(\Exception $e) {
  1584.                 $this->logger->log('Api::saveQs() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  1585.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1586.                 return $this->redirectToRoute('qu_sa_score');
  1587.             }
  1588.             
  1589.             $this->addFlash('notice'$this->translator->trans('Antispam score saved'));
  1590.             $this->logger->log('Autoresponder score settings saved'$request, ['prefix' => $form->get('prefix')->getData(),
  1591.                 'spam_threshold' => $form->get('score')->getData(), 'inbox_deliver_threshold' => $form->get('ok')->getData(),
  1592.                 'delete_threshold' => $form->get('delete')->getData()]);
  1593.             return $this->redirectToRoute('qu_sa_score');
  1594.         }
  1595.         elseif($form->isSubmitted() && !$form->isValid()){
  1596.             $this->addFlash('error'$this->translator->trans('Antispam score NOT saved'));
  1597.         }
  1598.         
  1599.         $neverDeleteText $this->translator->trans('NIGDY');
  1600.         
  1601.         return $this->render('skins/' $this->skin '/q_user/spamassassin_score.html.twig', [
  1602.             'form' => $form->createView(),
  1603.             'antispamOn' => $antispamOn,
  1604.             'sliderRangeScoreVal' => $sliderRangeScoreVal,
  1605.             'sliderRangeValMin' => $sliderRangeValMin,
  1606.             'sliderRangeValMax' => $sliderRangeValMax,
  1607.             'sliderMaxConfig' => $saMaxScore,
  1608.             'neverDelete' => $neverDelete,
  1609.             'neverDeleteText' => $neverDeleteText,
  1610.         ]);
  1611.         
  1612.     }
  1613.     /**
  1614.      * @Route("/panel/spamassassin/bwlists/{orderBy}/{orderDir}", defaults={"orderBy"="listType", "orderDir"="asc"}, name="qu_sa_bwlists", requirements={"orderBy"="listType|enableStatus|address|session"})
  1615.      */
  1616.     public function spamAssassinLists($orderBy$orderDirRequest $requestPaginatorInterface $paginator)
  1617.     {
  1618.         $user $this->security->getUser();
  1619.         $account $user->getAccount();
  1620.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1621.         $antispamOn $this->_isAntispamOn($account);
  1622.         $pagination $account->findSOption('cfgUserPagination') == null ?
  1623.         (isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
  1624.         : $account->findSOption('cfgUserPagination');
  1625.         
  1626.         $form $this->createForm(SpamAssassinLists::class);
  1627.         $formMass $this->createForm(SpamAssassinListsMass::class,
  1628.             null, [
  1629.                 'action' => $this->generateUrl('qu_sa_bwlists_mass'),
  1630.         ]);
  1631.             
  1632.         $form->handleRequest($request);
  1633.         $prefs = [];
  1634.         
  1635.         try {
  1636.             foreach(Api::getSAPrefVal($account'whitelist_from') as $pref) {
  1637.                 $prefs[$pref->getPrefid()] = $pref;
  1638.             }
  1639.             
  1640.             foreach(Api::getSAPrefVal($account'_NA_whitelist_from') as $pref) {
  1641.                 $prefs[$pref->getPrefid()] = $pref;
  1642.             }
  1643.             
  1644.             foreach(Api::getSAPrefVal($account'blacklist_from') as $pref) {
  1645.                 $prefs[$pref->getPrefid()] = $pref;
  1646.             }
  1647.             
  1648.             foreach(Api::getSAPrefVal($account'_NA_blacklist_from') as $pref) {
  1649.                 $prefs[$pref->getPrefid()] = $pref;
  1650.             }
  1651.         }
  1652.         catch(\Exception $e) {}
  1653.         if($orderBy == 'listType' || $orderBy == 'enableStatus' || $orderBy == 'address') {
  1654.             $this->session->set('app_user_sa_lists_order_by'$orderBy);
  1655.             $this->session->set('app_user_sa_lists_order_dir'$orderDir);
  1656.         }
  1657.         
  1658.         if($orderBy == 'session') {
  1659.             if($this->session->has('app_user_sa_lists_order_by')) {
  1660.                 $orderBy $this->session->get('app_user_sa_lists_order_by');
  1661.                 $orderDir $this->session->get('app_user_sa_lists_order_dir');
  1662.             }
  1663.             else {
  1664.                 $orderBy 'listType';
  1665.                 $orderDir 'asc';
  1666.             }
  1667.         }
  1668.         
  1669.         if($orderBy == 'listType') {
  1670.             if($orderDir == 'asc') {
  1671.                 uasort($prefs'\App\Model\UserPref::cmpObjectsByPreference');
  1672.             }
  1673.             else {
  1674.                 uasort($prefs'\App\Model\UserPref::cmpObjectsByPreferenceDesc');
  1675.             }
  1676.         }
  1677.         else if($orderBy == 'enableStatus'){
  1678.             if($orderDir == 'asc') {
  1679.                 uasort($prefs'\App\Model\UserPref::cmpObjectsByEnableStatus');
  1680.             }
  1681.             else {
  1682.                 uasort($prefs'\App\Model\UserPref::cmpObjectsByEnableStatusDesc');
  1683.             }
  1684.         }
  1685.         else {
  1686.             if($orderDir == 'asc') {
  1687.                 uasort($prefs'\App\Model\UserPref::cmpObjectsByVal');
  1688.             }
  1689.             else {
  1690.                 uasort($prefs'\App\Model\UserPref::cmpObjectsByValDesc');
  1691.             }
  1692.         }
  1693.         
  1694.         
  1695.         if($form->isSubmitted() && $form->isValid()) {
  1696.             // check if this entry 
  1697.             
  1698.             $saPref = new UserPref();
  1699.             $saPref->setUsername($account->userAddress());
  1700.             
  1701.             if($form->get('type')->getData() == 'w') {
  1702.                 $saPref->setPreference('whitelist_from');    
  1703.             }
  1704.             else {
  1705.                 $saPref->setPreference('blacklist_from');
  1706.             }
  1707.             
  1708.             $saPref->setValue($form->get('address')->getData());
  1709.             
  1710.             try {
  1711.                 if(Api::checkListExists($saPref)) {
  1712.                     $this->addFlash('error'$this->translator->trans('List item NOT added - already exists'));
  1713.                     
  1714.                     return $this->render('skins/' $this->skin '/q_user/spamassassin_bwlists.html.twig', [
  1715.                         'form' => $form->createView(),
  1716.                         'formMass' => $formMass->createView(),
  1717.                         'antispamOn' => $antispamOn,
  1718.                         'prefs' => $prefs,
  1719.                         'orderDir' => $orderDir,
  1720.                         'orderBy' => $orderBy,
  1721.                         /*'prefs' => $paginator->paginate(
  1722.                             $prefs, $request->query->getInt('page', 1), $pagination
  1723.                             ),*/
  1724.                     ]);
  1725.                 }
  1726.             }
  1727.             catch(\Exception $e) {
  1728.                 $this->logger->log('Api::checkListExists() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  1729.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1730.             }
  1731.             
  1732.             try {
  1733.                 Api::saveUserPref($saPref);
  1734.             }
  1735.             catch(\Exception $e) {
  1736.                 $this->logger->log('Api::saveUserPref() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  1737.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1738.                 return $this->redirectToRoute('qu_sa_bwlists');
  1739.             }
  1740.             
  1741.             if($form->get('type')->getData() == 'w') {
  1742.                 $this->logger->log('Whitelist added '$request, ['value' => $saPref->getValue()]);
  1743.             }
  1744.             else {
  1745.                 $this->logger->log('Blacklist added '$request, ['value' => $saPref->getValue()]);
  1746.             }
  1747.             
  1748.             $this->addFlash('notice'$this->translator->trans('List item added'));
  1749.             $this->addFlash('rowsAffected', -1); // highlight the last one
  1750.             return $this->redirectToRoute('qu_sa_bwlists');
  1751.         }
  1752.         elseif($form->isSubmitted() && !$form->isValid()){
  1753.             $this->addFlash('error'$this->translator->trans('List item NOT added'));
  1754.         }
  1755.             
  1756.         return $this->render('skins/' $this->skin '/q_user/spamassassin_bwlists.html.twig', [
  1757.             'form' => $form->createView(),
  1758.             'formMass' => $formMass->createView(),
  1759.             'antispamOn' => $antispamOn,
  1760.             'prefs' => 
  1761.                 $prefs,
  1762.             'orderDir' => $orderDir,
  1763.             'orderBy' => $orderBy,
  1764.             /*'prefs' => $paginator->paginate(
  1765.                 $prefs, $request->query->getInt('page', 1), $pagination
  1766.                 ),*/
  1767.         ]);
  1768.     }
  1769.     
  1770.     /**
  1771.      * @Route("/panel/spamassassin/massbwlists", name="qu_sa_bwlists_mass")
  1772.      */
  1773.     public function spamAssassinListsMassAction(Request $request) {
  1774.         $user $this->security->getUser();
  1775.         $account $user->getAccount();
  1776.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1777.         $form $this->createForm(SpamAssassinListsMass::class,
  1778.             null, [
  1779.                 'action' => $this->generateUrl('qu_sa_bwlists_mass'),
  1780.         ]);
  1781.         
  1782.         $form->handleRequest($request);
  1783.         
  1784.         if($form->isSubmitted() && $form->isValid()) {
  1785.             $actionType $form->get('actionType')->getData();
  1786.             $selected $request->request->get('listsMassCheckbox');
  1787.             $actionFailed false;
  1788.             
  1789.             $affectedArr = [];
  1790.             
  1791.             foreach($selected as $id) {
  1792.                 try {
  1793.                     $pref Api::getSAPrefById($id);
  1794.                 }
  1795.                 catch(\Exception $e) {
  1796.                     $this->logger->log('Error while trying to delete not existent SA list entry'$request, ['id' => $id], 'critical');
  1797.                     $actionFailed true;
  1798.                     continue;
  1799.                 }
  1800.                 
  1801.                 $this->denyAccessUnlessGranted('SPAMASSASSIN'$pref);
  1802.                 
  1803.                 switch($actionType) {
  1804.                     case 'delete':
  1805.                         if(Api::deleteSAPref($pref->getPrefid())) {
  1806.                             $this->logger->log('Deleted SA list entry'$request, ['value' => $pref->getValue()]);
  1807.                         }
  1808.                         else {
  1809.                             $this->logger->log('Error while trying to delete SA list entry'$request, [], 'critical');
  1810.                             $actionFailed true;
  1811.                         }
  1812.                         break;
  1813.                         
  1814.                     case 'towhite':
  1815.                         if($pref->isEnabled()) {
  1816.                             $pref->setPreference('whitelist_from');
  1817.                         }
  1818.                         else {
  1819.                             $pref->setPreference('_NA_whitelist_from');
  1820.                         }
  1821.                         break;
  1822.                         
  1823.                     case 'toblack':
  1824.                         if($pref->isEnabled()) {
  1825.                             $pref->setPreference('blacklist_from');
  1826.                         }
  1827.                         else {
  1828.                             $pref->setPreference('_NA_blacklist_from');
  1829.                         }
  1830.                         break;
  1831.                         
  1832.                     case 'disable':
  1833.                         if(Api::disableSAPref($pref->getPrefid())) {
  1834.                             $this->logger->log('Disabled SA list entry'$request, ['value' => $pref->getValue()]);
  1835.                         }
  1836.                         else {
  1837.                             $this->logger->log('Error while trying to disable SA list entry'$request, [], 'critical');
  1838.                             $actionFailed true;
  1839.                         }
  1840.                         break;
  1841.                     case 'enable':
  1842.                         if(Api::enableSAPref($pref->getPrefid())) {
  1843.                             $this->logger->log('Enabled SA list entry'$request, ['value' => $pref->getValue()]);
  1844.                         }
  1845.                         else {
  1846.                             $this->logger->log('Error while trying to enable SA list entry'$request, [], 'critical');
  1847.                             $actionFailed true;
  1848.                         }
  1849.                         break;
  1850.                 }
  1851.                 
  1852.                 if($actionType == 'towhite' || $actionType == 'toblack') {
  1853.                     try {
  1854.                         Api::saveUserPref($pref);
  1855.                         
  1856.                         if($actionType == 'towhite') {
  1857.                             $this->logger->log('Changed SA list entry to whitelist'$request, ['value' => $pref->getValue()]);
  1858.                         }
  1859.                         else {
  1860.                             $this->logger->log('Changed SA list entry to blacklist'$request, ['value' => $pref->getValue()]);
  1861.                         }
  1862.                     }
  1863.                     catch(\Exception $e) {
  1864.                         $this->logger->log('Api::saveUserPref() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  1865.                         $actionFailed true;
  1866.                     }
  1867.                 }
  1868.                 
  1869.                 $affectedArr[] = $id;
  1870.             }
  1871.             
  1872.             switch($actionType) {
  1873.                 case 'delete':
  1874.                     if($actionFailed) {
  1875.                         $this->addFlash('error'$this->translator->trans('NOT ALL entries deleted'));
  1876.                     }
  1877.                     else {
  1878.                         $this->addFlash('notice'$this->translator->trans('All entries successfuly deleted'));
  1879.                     }
  1880.                     break;
  1881.                     
  1882.                 case 'towhite':
  1883.                 case 'toblack':
  1884.                     if($actionFailed) {
  1885.                         $this->addFlash('error'$this->translator->trans('NOT ALL entries changed'));
  1886.                     }
  1887.                     else {
  1888.                         $this->addFlash('notice'$this->translator->trans('All entries successfuly changed'));
  1889.                     }
  1890.                     break;
  1891.                 case 'enable':
  1892.                     if($actionFailed) {
  1893.                         $this->addFlash('error'$this->translator->trans('NOT ALL entries enabled'));
  1894.                     }
  1895.                     else {
  1896.                         $this->addFlash('notice'$this->translator->trans('All entries successfuly enabled'));
  1897.                     }
  1898.                     break;
  1899.                 case 'disable':
  1900.                     if($actionFailed) {
  1901.                         $this->addFlash('error'$this->translator->trans('NOT ALL entries disabled'));
  1902.                     }
  1903.                     else {
  1904.                         $this->addFlash('notice'$this->translator->trans('All entries successfuly disabled'));
  1905.                     }
  1906.                     break;
  1907.             }
  1908.             
  1909.             $this->addFlash('rowsAffected'implode(':'$affectedArr));
  1910.         }
  1911.         
  1912.         return $this->redirectToRoute("qu_sa_bwlists");
  1913.     }
  1914.     
  1915.     /**
  1916.      * @Route("/panel/spamassassin/bwlists/del/{id}", name="qu_sa_bwlists_del")
  1917.      */
  1918.     public function spamassassinListsDelete(int $idRequest $request)
  1919.     {
  1920.         $user $this->security->getUser();
  1921.         $account $user->getAccount();
  1922.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1923.         
  1924.         try {
  1925.             $pref Api::getSAPrefById($id);
  1926.         }
  1927.         catch(\Exception $e) {
  1928.             $this->logger->log('Error while trying to delete not existent SA list entry'$request, ['id' => $id], 'critical');
  1929.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1930.             return $this->redirectToRoute('qu_sa_bwlists');
  1931.         }
  1932.         
  1933.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$pref);
  1934.         
  1935.         if(Api::deleteSAPref($pref->getPrefid())) {
  1936.             $this->logger->log('Deleted SA list entry'$request, ['value' => $pref->getValue(), 'type' => $pref->getPreference()]);
  1937.             $this->addFlash('notice'$this->translator->trans('List item deleted'));
  1938.         }
  1939.         else {
  1940.             $this->logger->log('Error while trying to delete SA list entry'$request, [], 'critical');
  1941.             $this->addFlash('error'$this->translator->trans('List item NOT deleted'));
  1942.         }
  1943.         
  1944.         return $this->redirectToRoute('qu_sa_bwlists');
  1945.     }
  1946.     
  1947.     /**
  1948.      * @Route("/panel/spamassassin/bwlists/enable/{id}", name="qu_sa_bwlists_enable")
  1949.      */
  1950.     public function spamassassinListsEnable(int $idRequest $request)
  1951.     {
  1952.         $user $this->security->getUser();
  1953.         $account $user->getAccount();
  1954.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1955.         
  1956.         try {
  1957.             $pref Api::getSAPrefById($id);
  1958.         }
  1959.         catch(\Exception $e) {
  1960.             $this->logger->log('Error while trying to enable not existent SA list entry'$request, ['id' => $id], 'critical');
  1961.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1962.             return $this->redirectToRoute('qu_sa_bwlists');
  1963.         }
  1964.         
  1965.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$pref);
  1966.         
  1967.         if(Api::enableSAPref($pref->getPrefid())) {
  1968.             $this->logger->log('Enabled SA list entry'$request, ['value' => $pref->getValue(), 'type' => $pref->getPreference()]);
  1969.             $this->addFlash('notice'$this->translator->trans('List item enabled'));
  1970.             $this->addFlash('rowsAffected'$pref->getPrefid());
  1971.         }
  1972.         else {
  1973.             $this->logger->log('Error while trying to enable SA list entry'$request, [], 'critical');
  1974.             $this->addFlash('error'$this->translator->trans('List item NOT enabled'));
  1975.         }
  1976.         
  1977.         return $this->redirectToRoute('qu_sa_bwlists');
  1978.     }
  1979.     
  1980.     
  1981.     /**
  1982.      * @Route("/panel/spamassassin/bwlists/disable/{id}", name="qu_sa_bwlists_disable")
  1983.      */
  1984.     public function spamassassinListsDisable(int $idRequest $request)
  1985.     {
  1986.         $user $this->security->getUser();
  1987.         $account $user->getAccount();
  1988.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  1989.         
  1990.         try {
  1991.             $pref Api::getSAPrefById($id);
  1992.         }
  1993.         catch(\Exception $e) {
  1994.             $this->logger->log('Error while trying to disable not existent SA list entry'$request, ['id' => $id], 'critical');
  1995.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  1996.             return $this->redirectToRoute('qu_sa_bwlists');
  1997.         }
  1998.         
  1999.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$pref);
  2000.         
  2001.         if(Api::disableSAPref($pref->getPrefid())) {
  2002.             $this->logger->log('Disabled SA list entry'$request, ['value' => $pref->getValue(), 'type' => $pref->getPreference()]);
  2003.             $this->addFlash('notice'$this->translator->trans('List item disabled'));
  2004.             $this->addFlash('rowsAffected'$pref->getPrefid());
  2005.         }
  2006.         else {
  2007.             $this->logger->log('Error while trying to disable SA list entry'$request, [], 'critical');
  2008.             $this->addFlash('error'$this->translator->trans('List item NOT disabled'));
  2009.         }
  2010.         
  2011.         return $this->redirectToRoute('qu_sa_bwlists');
  2012.     }
  2013.     
  2014.     /**
  2015.      * @Route("/panel/spamassassin/bwlists/edit/{id}/{page}/{orderBy}/{orderDir}", defaults={"page"=1, "orderBy"="listType", "orderDir"="asc"}, name="qu_sa_bwlists_edit")
  2016.      */
  2017.     public function spamassassinListsEdit(int $idRequest $requestint $page$orderBy$orderDir)
  2018.     {
  2019.         $user $this->security->getUser();
  2020.         $account $user->getAccount();
  2021.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  2022.         
  2023.         $form $this->createForm(SpamAssassinLists::class);
  2024.         $form->handleRequest($request);
  2025.         
  2026.         try {
  2027.             $pref Api::getSAPrefById($id);
  2028.         }
  2029.         catch(\Exception $e) {
  2030.             $this->logger->log('Error while trying to edit not existent SA list entry'$request, ['id' => $id], 'critical');
  2031.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2032.             return $this->redirectToRoute('qu_sa_bwlists');
  2033.         }
  2034.         
  2035.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$pref);
  2036.         
  2037.         if(!$form->isSubmitted()) {
  2038.             if($pref->getPreference() == 'whitelist_from') {
  2039.                 $form->get('type')->setData('w');
  2040.             }
  2041.             else {
  2042.                 $form->get('type')->setData('b');
  2043.             }
  2044.             
  2045.             $form->get('address')->setData($pref->getValue());
  2046.         }
  2047.                
  2048.         if($form->isSubmitted() && $form->isValid()) {
  2049.             $pref->setValue($form->get('address')->getData());
  2050.             $pref->setPreference(($form->get('type')->getData() == 'w') ? 'whitelist_from' 'blacklist_from');
  2051.             
  2052.             try {
  2053.                 Api::saveUserPref($pref);
  2054.             }
  2055.             catch(\Exception $e) {
  2056.                 $this->logger->log('Api::saveUserPref() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2057.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2058.                 return $this->redirectToRoute('qu_sa_bwlists');
  2059.             }
  2060.                         
  2061.             $this->addFlash('notice'$this->translator->trans('List item edited successfully'));
  2062.             $this->addFlash('rowsAffected'$pref->getPrefid());
  2063.             return $this->redirectToRoute('qu_sa_bwlists', ['page' => $page'orderBy' => $orderBy'orderDir' => $orderDir]);            
  2064.         }
  2065.         elseif($form->isSubmitted() && !$form->isValid()){
  2066.             $this->addFlash('error'$this->translator->trans('Procmail rule NOT saved'));
  2067.         }
  2068.         
  2069.         return $this->render('skins/' $this->skin '/q_user/spamassassin_bwlists_edit.html.twig', [
  2070.             'form' => $form->createView(),
  2071.             'page' => $page,
  2072.             'orderBy' => $orderBy,
  2073.             'orderDir' => $orderDir,
  2074.         ]);
  2075.     }
  2076.     
  2077.     /**
  2078.      * @Route("/panel/spamassassin/langs", name="qu_sa_langs")
  2079.      */
  2080.     public function spamAssassinLangs(Request $request)
  2081.     {
  2082.         $user $this->security->getUser();
  2083.         $account $user->getAccount();
  2084.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  2085.         
  2086.         $antispamOn $this->_isAntispamOn($account);
  2087.         
  2088.         $form $this->createForm(SpamAssassinLocales::class);
  2089.         $form->handleRequest($request);
  2090.         $saPref = new UserPref();
  2091.         $saPref->setPreference('ok_locales');
  2092.         $saPref->setUsername($account->useraddress());
  2093.         
  2094.         try {
  2095.             foreach(Api::getSAPrefVal($account'ok_locales') as $pref) {
  2096.                 $saPref $pref;
  2097.                 break;
  2098.             }
  2099.         }
  2100.         catch(\Exception $e) {}
  2101.         
  2102.         if(!$form->isSubmitted()) {
  2103.             if($saPref->getPrefid() == || strpos($saPref->getValue(), 'all') !== false) {
  2104.                 $form->get('locale')->setData(['l_all''l_en''l_ja''l_ru''l_ko''l_th''l_zh']);
  2105.             }
  2106.             else {
  2107.                 $localeArr = [];
  2108.                 
  2109.                 if(strpos($saPref->getValue(), 'en') !== false) {
  2110.                     $localeArr[] = 'l_en';
  2111.                 }
  2112.                 
  2113.                 if(strpos($saPref->getValue(), 'ja') !== false) {
  2114.                     $localeArr[] = 'l_ja';
  2115.                 }
  2116.                 
  2117.                 if(strpos($saPref->getValue(), 'ru') !== false) {
  2118.                     $localeArr[] = 'l_ru';
  2119.                 }
  2120.                 
  2121.                 if(strpos($saPref->getValue(), 'ko') !== false) {
  2122.                     $localeArr[] = 'l_ko';
  2123.                 }
  2124.                 
  2125.                 if(strpos($saPref->getValue(), 'th') !== false) {
  2126.                     $localeArr[] = 'l_th';
  2127.                 }
  2128.                 
  2129.                 if(strpos($saPref->getValue(), 'zh') !== false) {
  2130.                     $localeArr[] = 'l_zh';
  2131.                 }
  2132.                 
  2133.                 $form->get('locale')->setData($localeArr);
  2134.             }
  2135.         }
  2136.         
  2137.         if($form->isSubmitted() && $form->isValid()) {
  2138.             $localeStr '';
  2139.             
  2140.             foreach($form->get('locale')->getData() as $l) {
  2141.                 $localeStr .= str_replace('l_'''$l) . ' ';
  2142.             }
  2143.             
  2144.             $localeStr trim($localeStr);
  2145.             
  2146.             if(strpos($localeStr'all') !== false) {
  2147.                 $localeStr 'all';
  2148.             }
  2149.             
  2150.             $saPref->setValue($localeStr);
  2151.             
  2152.             try {
  2153.                 Api::saveUserPref($saPref);
  2154.             }
  2155.             catch(\Exception $e) {
  2156.                 $this->logger->log('Api::saveUserPref() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2157.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2158.                 return $this->redirectToRoute('qu_sa_langs');
  2159.             }
  2160.             
  2161.             $this->logger->log('Spamassassin languages set'$request, []);
  2162.             $this->addFlash('notice'$this->translator->trans('Antispam languages set'));
  2163.             return $this->redirectToRoute('qu_sa_langs');            
  2164.         }
  2165.         elseif($form->isSubmitted() && !$form->isValid()){
  2166.             $this->addFlash('error'$this->translator->trans('Antispam languages NOT set'));
  2167.         }
  2168.         
  2169.         return $this->render('skins/' $this->skin '/q_user/spamassassin_langs.html.twig', [
  2170.             'form' => $form->createView(),
  2171.             'antispamOn' => $antispamOn,
  2172.         ]);
  2173.         
  2174.     }
  2175.     
  2176.     /**
  2177.      * @Route("/panel/spamassassin/setdefaults/{type}", name="qu_sa_set_defaults", requirements={"type"="^(lang|score)$"})
  2178.      * @param type - lang or score
  2179.      */
  2180.     public function spamAssassinSetDefaults(String $typeRequest $request)
  2181.     {
  2182.         $user $this->security->getUser();
  2183.         $account $user->getAccount();
  2184.         $this->denyAccessUnlessGranted('SPAMASSASSIN'$account);
  2185.         
  2186.         $saPref null;
  2187.         $qsPref null;
  2188.         
  2189.         if($type == "lang") {
  2190.             try {
  2191.                 foreach(Api::getSAPrefVal($account'ok_locales') as $pref) {
  2192.                     $saPref $pref;
  2193.                     break;
  2194.                 }
  2195.             }
  2196.             catch(\Exception $e) {}
  2197.         }
  2198.         else {            
  2199.             try {
  2200.                 foreach(Api::getSAPrefVal($account'required_score') as $pref) {
  2201.                     $saPref $pref;
  2202.                     break;
  2203.                 }
  2204.                 
  2205.                 foreach(Api::getQS($account) as $pref) {
  2206.                     $qsPref $pref;
  2207.                     break;
  2208.                 }
  2209.             }
  2210.             catch(\Exception $e) {}
  2211.         }
  2212.         
  2213.         
  2214.         if(is_null($saPref) || Api::deleteSAPref($saPref->getPrefid())) {
  2215.             $this->logger->log('Antispam/Antispam ' $type ' - default settings set'$request);
  2216.             $this->addFlash('notice'$this->translator->trans('Default settings set'));
  2217.         }
  2218.         else {
  2219.             $this->logger->log('Error while trying to set default settings'$request, [], 'critical');
  2220.             $this->addFlash('error'$this->translator->trans('Default settings NOT set'));
  2221.         }
  2222.         
  2223.         if($qsPref != null) {
  2224.             Api::deleteQs($qsPref->getId());
  2225.         }
  2226.         
  2227.         // redirect to spamassassin main page or to a specific subpage
  2228.         $referer $request->headers->get('referer');
  2229.         
  2230.         if(strlen($referer)) {
  2231.             return $this->redirect($referer);
  2232.         }
  2233.         
  2234.         return $this->redirectToRoute('qu_sa');
  2235.     }
  2236.     
  2237.     /**
  2238.      * @Route("/panel/procmail", name="qu_procmail")
  2239.      */
  2240.     public function procmail(Request $request)
  2241.     {
  2242.         $user $this->security->getUser();
  2243.         $account $user->getAccount();
  2244.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2245.         $headers ProcmailRule::mailHeaders();
  2246.         
  2247.         $form $this->createForm(Procmail::class);
  2248.         $formMass $this->createForm(ProcmailMass::class);
  2249.         $form->handleRequest($request);
  2250.         
  2251.         try {
  2252.             $rules Api::getProcmailRules($account);
  2253.             $localForwarding Api::getForwardLocal($account);
  2254.         }
  2255.         catch(\Exception $e) {
  2256.             $this->logger->log('Api::getProcmailRules() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2257.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2258.             return $this->redirectToRoute('qu_main');
  2259.         }
  2260.         
  2261.         foreach($rules as &$r) {
  2262.             if(!$r->isDestEmail()) {
  2263.                 $r->setDestExist(Api::checkImapDir($accountmb_convert_encoding($r->getDest(), 'UTF7-imap''utf8')));
  2264.             }
  2265.         }
  2266.         
  2267.         if($form->isSubmitted() && $form->isValid()) {
  2268.             $rule = new ProcmailRule();
  2269.             $rule->setOwner($account->userAddress());
  2270.             $rule->setNo(-1);
  2271.             $rule->setType($form->get('src')->getData());
  2272.             
  2273.             // if src is "header" we need to set header-type
  2274.             if($rule->getType() == 'header') {
  2275.                 $rule->setHeaderType($form->get('headerTypeVal')->getData());
  2276.                 //$pattern = $form->get('header_type_val')->getData() . ': ' . $pattern;
  2277.             }
  2278.             
  2279.             $rule->setValue($form->get('pattern')->getData());
  2280.             
  2281.             $dest $form->get('dest')->getData();
  2282.             
  2283.             // if dest is '...email' save value of destEmail 
  2284.             if($dest == '...email') {
  2285.                 $dest '...' str_replace(' '''$form->get('destEmail')->getData());
  2286.                 
  2287.                 // check if number of forwards is not exceeded
  2288.                 try {
  2289.                     $forwards Api::getForwards($account);                    
  2290.                 }
  2291.                 catch(\Exception $e) {
  2292.                     $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2293.                     $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2294.                     return $this->redirectToRoute('qu_main');
  2295.                 }
  2296.                 
  2297.                 $maxForwards $this->_maxForwards($account);
  2298.                 $maxExternalForwards $this->_maxExternalForwards($account);
  2299.                 
  2300.                 $forwardsCnt count($forwards);
  2301.                 $externalForwardsCnt $this->_externalForwardsCount($forwards$user->getAccount());
  2302.                 $externalRulesCnt $this->_numberProcmailRulesEmailExternal($account);
  2303.                 $rulesCnt $this->_numberProcmailRulesEmail($account);
  2304.                 
  2305.                 if(($forwardsCnt $rulesCnt 1) > $maxForwards) {
  2306.                     $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);
  2307.                     
  2308.                     return $this->render('skins/' $this->skin '/q_user/procmail.html.twig', [
  2309.                         'form' => $form->createView(),
  2310.                         'formMass' => $formMass->createView(),
  2311.                         'rules' => $rules,
  2312.                         'headers' => $headers,
  2313.                         'localForwarding' => $localForwarding,
  2314.                     ]); 
  2315.                 }
  2316.                 
  2317.                 // check if limit of external forwards is not exceeded
  2318.                 $externalForwardsCnt $this->_externalForwardsCount($forwards$user->getAccount());
  2319.                 $currentExternalRules 0;
  2320.                 
  2321.                 if(AccountTools::isEmailExternal($form->get('destEmail')->getData(), [$user->getAccount()->getUserDomain()])) {
  2322.                     $currentExternalRules 1;
  2323.                 }
  2324.                 
  2325.                 if(($externalForwardsCnt $externalRulesCnt $currentExternalRules) > $maxExternalForwards) {
  2326.                     $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);
  2327.                     
  2328.                     return $this->render('skins/' $this->skin '/q_user/procmail.html.twig', [
  2329.                         'form' => $form->createView(),
  2330.                         'formMass' => $formMass->createView(),
  2331.                         'rules' => $rules,
  2332.                         'headers' => $headers,
  2333.                         'localForwarding' => $localForwarding,
  2334.                     ]);
  2335.                 }
  2336.             }
  2337.             else {
  2338.                 $dest mb_convert_encoding(urldecode($dest), 'UTF7-imap''utf8');
  2339.             }
  2340.             
  2341.             
  2342.             $rule->setDest($dest);
  2343.             $rule->setFinal($form->get('last')->getData());
  2344.             
  2345.             
  2346.             try {
  2347.                 Api::addProcmailRule($rule);
  2348.             }
  2349.             catch(\Exception $e) {
  2350.                 $this->logger->log('Api::addProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2351.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2352.             }
  2353.             
  2354.             $this->logger->log('New rule added'$request, ['rule' => $rule->getValue()]);
  2355.             $this->addFlash('notice'$this->translator->trans('Rule added'));
  2356.             $this->addFlash('rowsAffected', -1); // highlight the last one
  2357.             return $this->redirectToRoute('qu_procmail');            
  2358.         }
  2359.         elseif($form->isSubmitted() && !$form->isValid()){
  2360.             $dest $form->get('dest')->getData();
  2361.             $this->addFlash('error'$this->translator->trans('Procmail rule NOT added'));
  2362.         }
  2363.         
  2364.         return $this->render('skins/' $this->skin '/q_user/procmail.html.twig', [
  2365.             'form' => $form->createView(),
  2366.             'formMass' => $formMass->createView(),
  2367.             'rules' => $rules,
  2368.             'headers' => $headers,
  2369.             'localForwarding' => $localForwarding,
  2370.         ]);
  2371.         
  2372.     }
  2373.     
  2374.     /**
  2375.      * @Route("/panel/procmail/mass", name="qu_procmail_mass")
  2376.      */
  2377.     public function procmailMassAction(Request $request) {
  2378.         $user $this->security->getUser();
  2379.         $account $user->getAccount();
  2380.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2381.         $form $this->createForm(ProcmailMass::class);
  2382.         $form->handleRequest($request);
  2383.         
  2384.         if($form->isSubmitted() && $form->isValid()) {
  2385.             $actionType $form->get('actionType')->getData();
  2386.             $selected $request->request->get('rulesMassCheckbox');
  2387.             $actionFailed false;
  2388.             $affected = [];
  2389.             
  2390.             foreach($selected as $id) {
  2391.                 try {
  2392.                     $rule Api::getProcmailRule($id);
  2393.                 }
  2394.                 catch(\Exception $e) {
  2395.                     $this->logger->log('Api::getProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2396.                     $actionFailed true;
  2397.                     continue;
  2398.                 }
  2399.                 
  2400.                 $this->denyAccessUnlessGranted('PROCMAIL'$rule);
  2401.                 
  2402.                 switch($actionType) {
  2403.                     case 'delete':
  2404.                         try {
  2405.                             if(Api::deleteProcmailRule($id)) {
  2406.                                 $this->logger->log('Procmail rule deleted'$request, ['rule' => $rule->getValue()]);
  2407.                             }
  2408.                             else {
  2409.                                 $this->logger->log('Error deleting procmail rule, id = ' $id$request, ['rule' => $rule->getValue()]);
  2410.                                 $actionFailed true;
  2411.                             }
  2412.                         }
  2413.                         catch(\Exception $e) {
  2414.                             $this->logger->log('Api::deleteProcmailRule() - exception from API, id = ' $id$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2415.                             $actionFailed true;
  2416.                         }
  2417.                         break;
  2418.                         
  2419.                     case 'enable':
  2420.                         if(Api::enableProcmailRule($id)) {
  2421.                             $this->logger->log('Procmail rule enabled'$request, ['rule' => $rule->getValue()]);
  2422.                             $affected[] = $id;
  2423.                         }
  2424.                         else {
  2425.                             $this->logger->log('Error enabling procmail rule'$request, ['rule' => $rule->getValue()]);
  2426.                             $actionFailed true;
  2427.                         }
  2428.                         break;
  2429.                         
  2430.                     case 'disable':
  2431.                         if(Api::disableProcmailRule($id)) {
  2432.                             $this->logger->log('Procmail rule disabled'$request, ['rule' => $rule->getValue()]);
  2433.                             $affected[] = $id;
  2434.                         }
  2435.                         else {
  2436.                             $this->logger->log('Error disabling procmail rule'$request, ['rule' => $rule->getValue()]);
  2437.                             $actionFailed true;
  2438.                         }
  2439.                         break;
  2440.                 }
  2441.             }
  2442.             
  2443.             switch($actionType) {
  2444.                 case 'delete':
  2445.                     if($actionFailed) {
  2446.                         $this->addFlash('error'$this->translator->trans('NOT ALL rules deleted'));
  2447.                     }
  2448.                     else {
  2449.                         $this->addFlash('notice'$this->translator->trans('All rules successfuly deleted'));
  2450.                     }
  2451.                     break;
  2452.                     
  2453.                 case 'enable':
  2454.                     if($actionFailed) {
  2455.                         $this->addFlash('error'$this->translator->trans('NOT ALL rules enabled'));
  2456.                     }
  2457.                     else {
  2458.                         $this->addFlash('notice'$this->translator->trans('All rules successfuly enabled'));
  2459.                     }
  2460.                     break;
  2461.                     
  2462.                     
  2463.                 case 'disable':
  2464.                     if($actionFailed) {
  2465.                         $this->addFlash('error'$this->translator->trans('NOT ALL rules disabled'));
  2466.                     }
  2467.                     else {
  2468.                         $this->addFlash('notice'$this->translator->trans('All rules successfuly disabled'));
  2469.                     }
  2470.                     break;
  2471.             }
  2472.          
  2473.             $this->addFlash('rowsAffected'implode(':'$affected));
  2474.         }
  2475.         
  2476.         return $this->redirectToRoute("qu_procmail");
  2477.     }
  2478.     
  2479.     /**
  2480.      * @Route("/panel/procmail/edit/{id}", name="qu_procmail_edit")
  2481.      */
  2482.     public function procmailEdit(int $idRequest $request)
  2483.     {
  2484.         $user $this->security->getUser();
  2485.         $account $user->getAccount();
  2486.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2487.         $headers ProcmailRule::mailHeaders();
  2488.         
  2489.         $form $this->createForm(Procmail::class);
  2490.         $form->handleRequest($request);
  2491.         
  2492.         $rule Api::getProcmailRule($id);
  2493.         
  2494.         $this->denyAccessUnlessGranted('PROCMAIL'$rule);
  2495.         
  2496.         if(!$form->isSubmitted()) {
  2497.             $form->get('src')->setData($rule->getType());
  2498.             
  2499.             if($rule->getType() == 'header') {
  2500.                 $form->get('headerType')->setData($rule->getHeaderType());
  2501.                 $form->get('headerTypeVal')->setData($rule->getHeaderType());
  2502.             }
  2503.             
  2504.             $form->get('pattern')->setData($rule->getValue());
  2505.             $dest $rule->getDest();
  2506.             
  2507.             if(substr($dest03) == '...') {
  2508.                 $form->get('dest')->setData('...email');
  2509.                 $form->get('destEmail')->setData(substr($dest3));                
  2510.             }
  2511.             else {
  2512.                 $form->get('dest')->setData(urlencode($dest));
  2513.             }
  2514.             
  2515.             $form->get('last')->setData($rule->getFinal());
  2516.         }
  2517.         
  2518.         
  2519.         if($form->isSubmitted() && $form->isValid()) {
  2520.             $newRule = new ProcmailRule();
  2521.             $newRule->setId($rule->getId());
  2522.             $newRule->setOwner($account->userAddress());
  2523.             $newRule->setNo($rule->getNo());
  2524.             $newRule->setType($form->get('src')->getData());
  2525.             
  2526.             
  2527.             if($newRule->getType() == 'header') {
  2528.                 $newRule->setHeaderType($form->get('headerTypeVal')->getData());
  2529.             }
  2530.             
  2531.             $newRule->setValue($form->get('pattern')->getData());
  2532.             
  2533.             $dest $form->get('dest')->getData();
  2534.             
  2535.             // if dest is '...email' save value of destEmail
  2536.             if($dest == '...email') {
  2537.                 $dest '...' str_replace(' '''$form->get('destEmail')->getData());
  2538.                 
  2539.                 // check if we don't exceed limits of forwards
  2540.                 try {
  2541.                     $forwards Api::getForwards($account);
  2542.                 }
  2543.                 catch(\Exception $e) {
  2544.                     $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2545.                     $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2546.                     return $this->redirectToRoute('qu_main');
  2547.                 }
  2548.                 
  2549.                 $maxForwards $this->_maxForwards($account);
  2550.                 $maxExternalForwards $this->_maxExternalForwards($account);
  2551.                 
  2552.                 $forwardsCnt count($forwards);
  2553.                 $externalForwardsCnt $this->_externalForwardsCount($forwards$user->getAccount());
  2554.                 $externalRulesCnt $this->_numberProcmailRulesEmailExternal($account);
  2555.                 $rulesCnt $this->_numberProcmailRulesEmail($account);
  2556.                 
  2557.                 if(($forwardsCnt $rulesCnt 1) > $maxForwards) {
  2558.                     $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);
  2559.                     
  2560.                     return $this->render('skins/' $this->skin '/q_user/procmail_edit.html.twig', [
  2561.                         'form' => $form->createView(),
  2562.                         'headers' => $headers,
  2563.                     ]);
  2564.                 }
  2565.                 
  2566.                 // check if limit of external forwards is not exceeded
  2567.                 $externalForwardsCnt $this->_externalForwardsCount($forwards$user->getAccount());
  2568.                 $currentExternalRules 0;
  2569.                 
  2570.                 if(AccountTools::isEmailExternal($form->get('destEmail')->getData(), [$user->getAccount()->getUserDomain()])) {
  2571.                     $currentExternalRules 1;
  2572.                 }
  2573.                 
  2574.                 if(($externalForwardsCnt $externalRulesCnt $currentExternalRules) > $maxExternalForwards) {
  2575.                     $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);
  2576.                     
  2577.                     return $this->render('skins/' $this->skin '/q_user/procmail_edit.html.twig', [
  2578.                         'form' => $form->createView(),
  2579.                         'headers' => $headers,
  2580.                     ]);
  2581.                 }
  2582.             }
  2583.             else {
  2584.                 $dest mb_convert_encoding(urldecode($dest), 'UTF7-imap''utf8');
  2585.             }
  2586.             
  2587.             $newRule->setDest($dest);
  2588.             $newRule->setFinal($form->get('last')->getData());
  2589.             
  2590.             try {
  2591.                 Api::saveProcmailRule($newRule);
  2592.             }
  2593.             catch(\Exception $e) {
  2594.                 $this->logger->log('Api::saveProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2595.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2596.                 
  2597.             }
  2598.             
  2599.             $this->addFlash('notice'$this->translator->trans('Rule saved'));
  2600.             $this->addFlash('rowsAffected'$rule->getId());
  2601.             return $this->redirectToRoute('qu_procmail');
  2602.         }
  2603.         elseif($form->isSubmitted() && !$form->isValid()){
  2604.             $this->addFlash('error'$this->translator->trans('Procmail rule NOT saved'));
  2605.         }
  2606.         
  2607.         return $this->render('skins/' $this->skin '/q_user/procmail_edit.html.twig', [
  2608.             'form' => $form->createView(),
  2609.             'headers' => $headers,
  2610.         ]);
  2611.         
  2612.     }
  2613.     
  2614.     /**
  2615.      * @Route("/panel/procmail/del/{id}", name="qu_procmail_del")
  2616.      */
  2617.     public function procmailDel(int $idRequest $request)
  2618.     {
  2619.         $user $this->security->getUser();
  2620.         $account $user->getAccount();
  2621.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2622.         
  2623.         try {
  2624.             $rule Api::getProcmailRule($id);
  2625.         }
  2626.         catch(\Exception $e) {
  2627.             $this->logger->log('Api::getProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2628.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2629.             return $this->redirectToRoute('qu_procmail');
  2630.         }
  2631.         
  2632.         $this->denyAccessUnlessGranted('PROCMAIL'$rule);
  2633.         
  2634.         try {
  2635.             if(Api::deleteProcmailRule($id)) {
  2636.                 $this->logger->log('Procmail rule deleted'$request, ['rule' => $rule->getValue()]);
  2637.                 $this->addFlash('notice'$this->translator->trans('Rule deleted'));
  2638.             }
  2639.         }
  2640.         catch(\Exception $e) {
  2641.             $this->addFlash('error'$this->translator->trans('Rule NOT deleted'));
  2642.         }
  2643.         
  2644.         return $this->redirectToRoute("qu_procmail");
  2645.     }
  2646.     
  2647.     /**
  2648.      * @Route("/panel/procmail/disable/{id}", name="qu_procmail_disable")
  2649.      */
  2650.     public function procmailDisable(int $idRequest $request)
  2651.     {
  2652.         $user $this->security->getUser();
  2653.         $account $user->getAccount();
  2654.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2655.         
  2656.         try {
  2657.             $rule Api::getProcmailRule($id);
  2658.         }
  2659.         catch(\Exception $e) {
  2660.             $this->logger->log('Api::getProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2661.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2662.             return $this->redirectToRoute('qu_procmail');
  2663.         }
  2664.         
  2665.         $this->denyAccessUnlessGranted('PROCMAIL'$rule);
  2666.         
  2667.         if(Api::disableProcmailRule($id)) {
  2668.             $this->logger->log('Procmail rule disabled'$request, ['rule' => $rule->getValue()]);
  2669.             $this->addFlash('notice'$this->translator->trans('Rule disabled'));
  2670.             $this->addFlash('rowsAffected'$id);
  2671.         }
  2672.         else {
  2673.             $this->addFlash('error'$this->translator->trans('Rule NOT disabled'));
  2674.         }
  2675.         
  2676.         return $this->redirectToRoute("qu_procmail");
  2677.     }
  2678.     
  2679.     /**
  2680.      * @Route("/panel/procmail/enable/{id}", name="qu_procmail_enable")
  2681.      */
  2682.     public function procmailEnable(int $idRequest $request)
  2683.     {
  2684.         $user $this->security->getUser();
  2685.         $account $user->getAccount();
  2686.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2687.         
  2688.         try {
  2689.             $rule Api::getProcmailRule($id);
  2690.         }
  2691.         catch(\Exception $e) {
  2692.             $this->logger->log('Api::getProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2693.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2694.             return $this->redirectToRoute('qu_procmail');
  2695.         }
  2696.         
  2697.         $this->denyAccessUnlessGranted('PROCMAIL'$rule);
  2698.             
  2699.         if(Api::enableProcmailRule($id)) {
  2700.             $this->logger->log('Procmail rule disabled'$request, ['rule id' => $id]);
  2701.             $this->addFlash('notice'$this->translator->trans('Rule enabled'));
  2702.             $this->addFlash('rowsAffected'$id);
  2703.         }
  2704.         else {
  2705.             $this->addFlash('error'$this->translator->trans('Rule NOT enabled'));
  2706.         }
  2707.         
  2708.         return $this->redirectToRoute("qu_procmail");
  2709.     }    
  2710.     
  2711.     /**
  2712.      * @Route("/panel/procmail/ruleup/{id}", name="qu_procmail_ruleup")
  2713.      */
  2714.     public function procmailUp(int $idRequest $request)
  2715.     {
  2716.        return $this->_procmailMove($id'up'$request); 
  2717.     }
  2718.     
  2719.     /**
  2720.      * @Route("/panel/procmail/ruledown/{id}", name="qu_procmail_ruledown")
  2721.      */
  2722.     public function procmailDown(int $idRequest $request)
  2723.     {
  2724.         return $this->_procmailMove($id'down'$request);
  2725.     }
  2726.        
  2727.     /**
  2728.      * 
  2729.      */
  2730.     private function _procmailMove(int $idstring $directionRequest $request)
  2731.     {
  2732.         $user $this->security->getUser();
  2733.         $account $user->getAccount();
  2734.         $this->denyAccessUnlessGranted('PROCMAIL'$account);
  2735.         
  2736.         try {
  2737.             $rule Api::getProcmailRule($id);
  2738.         }
  2739.         catch(\Exception $e) {
  2740.             $this->logger->log('Api::getProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2741.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2742.             return $this->redirectToRoute('qu_procmail');
  2743.         }
  2744.         
  2745.         $this->denyAccessUnlessGranted('PROCMAIL'$rule);
  2746.         
  2747.         if($direction == 'up') {
  2748.             if(Api::procmailRuleMoveUp($id)) {
  2749.                 $this->addFlash('notice'$this->translator->trans('Rule moved up'));
  2750.                 $this->addFlash('rowsAffected'$id);
  2751.             }
  2752.             else {
  2753.                 $this->addFlash('error'$this->translator->trans('Rule NOT moved up'));
  2754.             }
  2755.         }
  2756.         else {
  2757.             if(Api::procmailRuleMoveDown($id)) {
  2758.                 $this->addFlash('notice'$this->translator->trans('Rule moved down'));
  2759.                 $this->addFlash('rowsAffected'$id);
  2760.             }
  2761.             else {
  2762.                 $this->addFlash('error'$this->translator->trans('Rule NOT moved down'));
  2763.             }
  2764.         }
  2765.             
  2766.         return $this->redirectToRoute("qu_procmail");
  2767.     }
  2768.     
  2769.     
  2770.     /**
  2771.      * @Route("/panel/dirs", name="qu_imap")
  2772.      */
  2773.     public function imapDirs(Request $request)
  2774.     {        
  2775.         $user $this->security->getUser();
  2776.         $account $user->getAccount();
  2777.         $this->denyAccessUnlessGranted('IMAP'$account);
  2778.         
  2779.         $form $this->createForm(Imap::class);
  2780.         $form->get('path')->setData('delete');
  2781.         
  2782.         $formMass $this->createForm(ImapMass::class);
  2783.         $form->handleRequest($request);
  2784.         
  2785.         try {
  2786.             $folders Api::getImapDirs($account);
  2787.         }
  2788.         catch(\Exception $e) {
  2789.             $this->logger->log('Api::getImapDirs() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2790.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2791.             return $this->redirectToRoute('qu_main');
  2792.         }
  2793.         
  2794.         $imapUserDomainArr $this->_getImapUserDomain($account);
  2795.         
  2796.         try {
  2797.             $subscribedFolders Api::getImapSubscribedDirs($imapUserDomainArr[0], $imapUserDomainArr[1], AccountTools::decryptString($this->requestStack->getSession()->get('storedPassword')));
  2798.         }
  2799.         catch(\Exception $e) {
  2800.             $this->logger->log('Api::getImapSubscribedDirs() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2801.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2802.             return $this->redirectToRoute('qu_main');
  2803.         }
  2804.         
  2805.         usort($folders'\App\Model\ImapDir::cmpObjects');
  2806.         $inbox = new ImapDir();
  2807.         $inbox->setName('INBOX');
  2808.         
  2809.         try {
  2810.             $inbox->setCount(Api::getImapCount($account'INBOX'));
  2811.         }
  2812.         catch(\Exception $e) {
  2813.             $this->logger->log('Api::getImapCount() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2814.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2815.             return $this->redirectToRoute('qu_main');
  2816.         }
  2817.             
  2818.         array_unshift($folders$inbox);
  2819.         $folders AccountTools::dirsChildren($folders""0);        
  2820.         
  2821.         if(!$form->isSubmitted()) {
  2822.             $form->get('path')->setData('.');
  2823.         }
  2824.         
  2825.         if($form->isSubmitted() && $form->isValid()) {
  2826.             $folderToAdd mb_convert_encoding($form->get('folder')->getData(), 'UTF7-imap''utf8');
  2827.             $path mb_convert_encoding($form->get('path')->getData(), 'UTF7-imap''utf8');
  2828.              
  2829.             if(strlen($path) > 0) {
  2830.                 if($path != '.') {
  2831.                     $folderToAdd $path '.' $folderToAdd;
  2832.                 }
  2833.             }
  2834.             
  2835.             try {    
  2836.                 Api::addImapDir($account$folderToAdd);
  2837.             }
  2838.             catch(\Exception $e) {
  2839.                 if(strstr($e->getMessage(), 'already exists')) {
  2840.                     $this->addFlash('error'$this->translator->trans('Folder already exists. New folder NOT added.'));
  2841.                 }
  2842.                 else {
  2843.                     $this->logger->log('Api::addImapDir() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  2844.                     $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  2845.                 }
  2846.                 
  2847.                 return $this->redirectToRoute('qu_imap');
  2848.             }
  2849.             
  2850.              $this->logger->log('New folder added'$request, ['folder' => $form->get('folder')->getData()]);
  2851.              $this->addFlash('notice'$this->translator->trans('New folder added'));
  2852.              $this->addFlash('rowsAffected'$folderToAdd); // highlight the new one
  2853.              return $this->redirectToRoute('qu_imap');
  2854.         }
  2855.         elseif($form->isSubmitted() && !$form->isValid()){
  2856.             $this->addFlash('error'$this->translator->trans('New folder NOT added'));
  2857.         }
  2858.         
  2859.         return $this->render('skins/' $this->skin '/q_user/imap_dirs.html.twig', [
  2860.             'form' => $form->createView(),
  2861.             'formMass' => $formMass->createView(),
  2862.             'folders' => $folders,
  2863.             'subscribedFolders' => $subscribedFolders,
  2864.         ]);
  2865.         
  2866.     }
  2867.     
  2868.     /**
  2869.      * @Route("/panel/dirs/mass", name="qu_imap_mass")
  2870.      */
  2871.     public function imapDirsMassAction(Request $request) {
  2872.         $user $this->security->getUser();
  2873.         $account $user->getAccount();
  2874.         $this->denyAccessUnlessGranted('IMAP'$account);
  2875.         $form $this->createForm(ImapMass::class);
  2876.         $form->handleRequest($request);
  2877.         
  2878.         if($form->isSubmitted() && $form->isValid()) {
  2879.             $selected $request->request->get('foldersMassCheckbox');
  2880.             $actionFailed false;
  2881.             
  2882.             foreach($selected as $dir) {
  2883.                 // we have to url-decode, than encode from UTF-8 to UTF-7
  2884.                 $dir urldecode($dir);
  2885.                 $dir mb_convert_encoding($dir'UTF7-imap''utf8');
  2886.                 
  2887.                 if(Api::deleteImapDir($account$dir)) {
  2888.                     $this->logger->log('Imap directory deleted'$request, ['dir' => urldecode($dir)]);
  2889.                 }
  2890.                 else {
  2891.                     $actionFailed true;
  2892.                 }
  2893.             }
  2894.             
  2895.             if($actionFailed) {
  2896.                 $this->addFlash('error'$this->translator->trans('NOT ALL folders deleted'));
  2897.             }
  2898.             else {
  2899.                 $this->addFlash('notice'$this->translator->trans('All folders successfuly deleted'));
  2900.             }
  2901.         }
  2902.         
  2903.         return $this->redirectToRoute("qu_imap");
  2904.     }
  2905.     
  2906.     
  2907.     /**
  2908.      * @Route("/panel/dirs/del/{dir}", name="qu_imap_del")
  2909.      */
  2910.     public function imapDirsDel(String $dirRequest $request)
  2911.     {
  2912.         $user $this->security->getUser();
  2913.         $account $user->getAccount();
  2914.         $this->denyAccessUnlessGranted('IMAP'$account);
  2915.         
  2916.         if($dir == 'INBOX') {
  2917.             $this->logger->log('Try to delete INBOX'$request, ['dir' => urldecode($dir)], 'critical');
  2918.             return $this->redirectToRoute("qu_imap");
  2919.         }
  2920.         
  2921.         $dir urldecode($dir);
  2922.         $dir mb_convert_encoding($dir'UTF7-imap''utf8');
  2923.         
  2924.         if(Api::deleteImapDir($account$dir)) {
  2925.             $this->logger->log('Imap directory deleted'$request, ['dir' => urldecode($dir)]);
  2926.             $this->addFlash('notice'$this->translator->trans('Folder deleted'));
  2927.         }
  2928.         else {
  2929.             $this->logger->log('Imap directory NOT deleted - error'$request, ['dir' => urldecode($dir)]);
  2930.             $this->addFlash('error'$this->translator->trans('Folder NOT deleted'));
  2931.         }
  2932.         
  2933.         return $this->redirectToRoute("qu_imap");
  2934.     }
  2935.     
  2936.     /**
  2937.      * @Route("/panel/dirs/edit/{dir}", name="qu_imap_edit")
  2938.      */
  2939.     public function imapDirsEdit(String $dirRequest $request)
  2940.     {
  2941.         $user $this->security->getUser();
  2942.         $account $user->getAccount();
  2943.         $this->denyAccessUnlessGranted('IMAP'$account);
  2944.         
  2945.         if($dir == 'INBOX') {
  2946.             $this->logger->log('Try to edit INBOX'$request, ['dir' => urldecode($dir)], 'critical');
  2947.             return $this->redirectToRoute("qu_imap");
  2948.         }
  2949.         
  2950.         // we have to url-decode, than encode from UTF-8 to UTF-7 and url-encode again
  2951.         $dir urldecode($dir);
  2952.         
  2953.         $form $this->createForm(Imap::class);
  2954.         $form->handleRequest($request);
  2955.         $whitespaceWarning false;
  2956.         
  2957.         if(!$form->isSubmitted()) {
  2958.             // we need to split $dir - last part is a folder name, previous part - path
  2959.             $dirArr explode('.'$dir);
  2960.             $form->get('folder')->setData($dirArr[sizeof($dirArr) -  1]);
  2961.             $folder $form->get('folder')->getData();
  2962.             
  2963.             if($folder != trim($folder)) {
  2964.                 $whitespaceWarning true;
  2965.             }
  2966.             
  2967.             unset($dirArr[sizeof($dirArr) -  1]);
  2968.             $path implode('.'$dirArr);
  2969.             
  2970.             if($path == "") {
  2971.                 $path ".";
  2972.             }
  2973.             
  2974.             $form->get('path')->setData($path);
  2975.         }
  2976.         
  2977.         if($form->isSubmitted() && $form->isValid()) {
  2978.             $from mb_convert_encoding($dir'UTF7-imap''utf8');
  2979.             $to mb_convert_encoding($form->get('folder')->getData(), 'UTF7-imap''utf8');
  2980.             $path mb_convert_encoding($form->get('path')->getData(), 'UTF7-imap''utf8');
  2981.             
  2982.             if(strlen($path) > 0) {
  2983.                 if($path != '.') {
  2984.                     $to $path '.' $to;
  2985.                 }
  2986.             }
  2987.                         
  2988.             if(Api::renameImapDir($account$from$to)) {
  2989.                 $this->logger->log('Imap directory renamed'$request, [
  2990.                         'dirOld' => $from'dirNew' => $to]);
  2991.                 $this->addFlash('notice'$this->translator->trans('Folder renamed'));
  2992.                 $this->addFlash('rowsAffected'$to);
  2993.                 return $this->redirectToRoute('qu_imap');
  2994.             }
  2995.             else {
  2996.                 $this->addFlash('error'$this->translator->trans('Folder NOT renamed'));
  2997.             }
  2998.         }
  2999.         elseif($form->isSubmitted() && !$form->isValid()){
  3000.             $this->addFlash('error'$this->translator->trans('Folder NOT renamed'));
  3001.         }
  3002.         
  3003.         return $this->render('skins/' $this->skin '/q_user/imap_dirs_edit.html.twig', [
  3004.             'form' => $form->createView(),
  3005.             'whitespaceWarning' => $whitespaceWarning,
  3006.         ]);
  3007.     }
  3008.     
  3009.     /**
  3010.      * @Route("/panel/dirs/subscribe/{dir}", name="qu_imap_subscribe")
  3011.      * dir in UTF7-imap, urlencoded
  3012.      */
  3013.     public function imapDirsSubscribe(String $dirRequest $request)
  3014.     {
  3015.         $user $this->security->getUser();
  3016.         $account $user->getAccount();
  3017.         $this->denyAccessUnlessGranted('IMAP'$account);
  3018.         
  3019.         if($dir == 'INBOX') {
  3020.             $this->logger->log('Try to subscribe INBOX'$request, ['dir' => urldecode($dir)], 'critical');
  3021.             return $this->redirectToRoute("qu_imap");
  3022.         }
  3023.         
  3024.         $imapUserDomainArr $this->_getImapUserDomain($account);
  3025.         
  3026.         try {
  3027.             Api::subscribeImapDir($imapUserDomainArr[0], $imapUserDomainArr[1], AccountTools::decryptString($this->requestStack->getSession()->get('storedPassword')), $dir);
  3028.         }
  3029.         catch(\Exception $e) {
  3030.             $this->logger->log('Api::imapDirsSubscribe() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3031.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3032.         }
  3033.         return $this->redirectToRoute('qu_imap');
  3034.     }
  3035.     
  3036.     /**
  3037.      * @Route("/panel/dirs/unsubscribe/{dir}", name="qu_imap_unsubscribe")
  3038.      * dir in UTF7-imap, urlencoded
  3039.      */
  3040.     public function imapDirsUnsubscribe(String $dirRequest $request)
  3041.     {
  3042.         $user $this->security->getUser();
  3043.         $account $user->getAccount();
  3044.         $this->denyAccessUnlessGranted('IMAP'$account);
  3045.         
  3046.         if($dir == 'INBOX') {
  3047.             $this->logger->log('Try to subscribe INBOX'$request, ['dir' => urldecode($dir)], 'critical');
  3048.             return $this->redirectToRoute("qu_imap");
  3049.         }
  3050.         
  3051.         $imapUserDomainArr $this->_getImapUserDomain($account);
  3052.         
  3053.         try {
  3054.             Api::unsubscribeImapDir($imapUserDomainArr[0], $imapUserDomainArr[1], AccountTools::decryptString($this->requestStack->getSession()->get('storedPassword')), $dir);
  3055.         }
  3056.         catch(\Exception $e) {
  3057.             $this->logger->log('Api::imapDirsUnsubscribe() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3058.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3059.         }
  3060.         
  3061.         return $this->redirectToRoute('qu_imap');
  3062.     }
  3063.     
  3064.     /**
  3065.      * @Route("/panel/noticesms", name="qu_noticesms")
  3066.      */
  3067.     public function noticeSms(Request $request)
  3068.     {        
  3069.         $user $this->security->getUser();
  3070.         $account $user->getAccount();
  3071.         $this->denyAccessUnlessGranted('NOTICESMS'$account);
  3072.         
  3073.         $form $this->createForm(NoticeSMS::class);
  3074.         $form->handleRequest($request);
  3075.         
  3076.         try {
  3077.             $rule Api::getSMSRule($account);
  3078.         }
  3079.         catch(\Exception $e) { 
  3080.             $rule = new ProcmailRule();
  3081.             $rule->setId(-1);
  3082.             $rule->setType('sms');
  3083.             $rule->setDest('NA');
  3084.             $rule->setOwner($account->userAddress());
  3085.             $rule->setNo(0);
  3086.             $rule->setFinal(0);
  3087.         }
  3088.         
  3089.         try {
  3090.             $localForwarding Api::getForwardLocal($account);
  3091.         }
  3092.         catch(\Exception $e) {
  3093.             $this->logger->log('Api::getForwardLocal() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3094.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3095.             return $this->redirectToRoute('qu_main');
  3096.         }
  3097.                 
  3098.         if(!$form->isSubmitted()) {
  3099.             if(strlen($rule->getValue()) > 0) {
  3100.                 $form->get('address')->setData($rule->getValue());
  3101.             }
  3102.         }
  3103.         
  3104.         if($form->isSubmitted() && $form->isValid()) {
  3105.             // check if given address is not user's address on alias pointing to it
  3106.             // to prevent email loops
  3107.             if(strcmp($form->get('address')->getData(), $account->userAddress()) == 0) {
  3108.                 $this->logger->log("noticeSMS - prevented saving user's own email address as a notification address"$request, ['accountName' => $account->userAddress()]);
  3109.                 $this->addFlash('error'$this->translator->trans('You cannot add your own email address as a notification address'));
  3110.                 
  3111.                 return $this->render('skins/' $this->skin '/q_user/noticesms.html.twig', [
  3112.                     'form' => $form->createView(),
  3113.                     'localForwarding' => $localForwarding,
  3114.                 ]);
  3115.             }
  3116.             
  3117.             $aliasFilter = [];
  3118.             $aliasFilter['target_alias'] = $account->userAddress();
  3119.             
  3120.             try {
  3121.                 $aliases Api::listAliases($aliasFilter);
  3122.             }
  3123.             catch(\Exception $e) {
  3124.                 $this->logger->log('Api::listAliases() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3125.                 $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3126.                 return $this->redirectToRoute('qu_noticesms');
  3127.             }
  3128.             
  3129.             foreach($aliases as $alias) {
  3130.                 if(strcmp($alias->getSrc(), $form->get('address')->getData()) == 0) {
  3131.                     $this->logger->log("noticeSMS - prevented saving user's own alias as a notification address"$request, ['accountName' => $account->userAddress()]);
  3132.                     $this->addFlash('error'$this->translator->trans('You cannot add your own alias as a notification address'));
  3133.                     
  3134.                     return $this->render('skins/' $this->skin '/q_user/noticesms.html.twig', [
  3135.                         'form' => $form->createView(),
  3136.                         'localForwarding' => $localForwarding,
  3137.                     ]);
  3138.                 }
  3139.             }
  3140.             
  3141.             $rule->setValue($form->get('address')->getData());
  3142.             
  3143.             if($rule->getId() != -1) {
  3144.                 try {
  3145.                     Api::saveProcmailRule($rule);
  3146.                 }
  3147.                 catch(\Exception $e) {
  3148.                     $this->logger->log('Api::saveProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3149.                     $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3150.                     return $this->redirectToRoute('qu_noticesms');
  3151.                 }
  3152.             }
  3153.             else {
  3154.                 try {
  3155.                     Api::addProcmailRule($rule);
  3156.                 }
  3157.                 catch(\Exception $e) {
  3158.                     $this->logger->log('Api::addProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3159.                     $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3160.                     return $this->redirectToRoute('qu_noticesms');
  3161.                 }
  3162.             }
  3163.             
  3164.             $this->addFlash('notice'$this->translator->trans('Mobile notification added'));
  3165.             $this->logger->log('Mobile notification added'$request, ['address' => $rule->getValue()]);
  3166.             return $this->redirectToRoute('qu_noticesms');
  3167.         }
  3168.         elseif($form->isSubmitted() && !$form->isValid()){
  3169.             $this->addFlash('error'$this->translator->trans('SMS notice NOT set'));
  3170.         }
  3171.         
  3172.         return $this->render('skins/' $this->skin '/q_user/noticesms.html.twig', [
  3173.             'form' => $form->createView(),
  3174.             'localForwarding' => $localForwarding,
  3175.         ]);
  3176.         
  3177.     }
  3178.     
  3179.     /**
  3180.      * @Route("/panel/noticesms/del", name="qu_noticesms_del")
  3181.      */
  3182.     public function noticeSmsDel(Request $request)
  3183.     {
  3184.         $user $this->security->getUser();
  3185.         $account $user->getAccount();
  3186.         $this->denyAccessUnlessGranted('NOTICESMS'$account);
  3187.         
  3188.         try {
  3189.             $rule Api::getSMSRule($account);
  3190.         }
  3191.         catch(\Exception $e) {
  3192.             $this->logger->log('trying to delete non-existante SMS notice'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'warning');
  3193.             $this->addFlash('error'$this->translator->trans('Deleting SMS notification not possible.'));
  3194.             return $this->redirectToRoute('qu_noticesms');
  3195.         }
  3196.         
  3197.         try {
  3198.             if(Api::deleteProcmailRule($rule->getId())) {
  3199.                 $this->logger->log('Mobile notification deleted'$request);
  3200.                 $this->addFlash('notice'$this->translator->trans('Mobile notification deleted'));
  3201.             }
  3202.         }
  3203.         catch(\Exception $e) {
  3204.             $this->logger->log('Api::deleteProcmailRule() - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3205.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3206.             return $this->redirectToRoute('qu_noticesms');
  3207.         }
  3208.         
  3209.         return $this->redirectToRoute("qu_noticesms");
  3210.     }
  3211.     
  3212.     
  3213.     /**
  3214.      * @Route("/panel/stats", name="qu_stats")
  3215.      */
  3216.     public function stats(Request $request)
  3217.     {
  3218.         $stats = [];
  3219.         
  3220.         $user $this->security->getUser();
  3221.         $account $user->getAccount();
  3222.         $this->denyAccessUnlessGranted('STATS'$account);
  3223.         $autoresponderStatus '';
  3224.         
  3225.         try {
  3226.             $forwards Api::getForwards($account);
  3227.             $localForwarding Api::getForwardLocal($account);
  3228.             $folders Api::getImapDirs($account);
  3229.             $rules Api::getProcmailRules($account);
  3230.             $this->_getAutoresponderForUser($account$autoresponderStatus);
  3231.             $saStatus Api::getSAProtection($account);
  3232.         }
  3233.         catch(\Exception $e) {
  3234.             $this->logger->log('Api - get functions - exception from API'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3235.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3236.             return $this->redirectToRoute('qu_main');
  3237.         }
  3238.         
  3239.         try {
  3240.             $smsRule Api::getSMSRule($account);
  3241.             
  3242.             if($smsRule != null) {
  3243.                 $smsStatus true;
  3244.             }
  3245.         }
  3246.         catch(\Exception $e) {
  3247.             $smsStatus false;
  3248.         }
  3249.             
  3250.         
  3251.         $stats['forwards'] = sizeof($forwards);
  3252.         $stats['folders'] = sizeof($folders);
  3253.         $stats['filters'] = sizeof($rules);
  3254.         $stats['autoresponderStatus'] = $autoresponderStatus// string, because can have 3 different states
  3255.         $stats['antispamStatus'] = $saStatus;
  3256.         $stats['smsStatus'] = $smsStatus;
  3257.         $stats['deliveryStatus'] = $localForwarding;
  3258.         
  3259.         return $this->render('skins/' $this->skin '/q_user/user_stats.html.twig', [
  3260.             'stats' => $stats,
  3261.         ]);
  3262.     }
  3263.     
  3264.     /**
  3265.      * @Route("/panel/settings", name="qu_settings")
  3266.      */
  3267.     public function settings(Request $request)
  3268.     {
  3269.         $user $this->security->getUser();
  3270.         $user->loadAccount();
  3271.         $account $user->getAccount();
  3272.         $this->denyAccessUnlessGranted('SETTINGS'$account);
  3273.         $twoFactorAllowed false;
  3274.         $twoFactorGoogleAllowed false;
  3275.         $twoFactorMethod 'email';
  3276.         $qrCodeDataUri null;
  3277.         $serviceDomain $request->getHost();
  3278.         if(isset($_SERVER['APP_2FA_ALLOWED'])) {
  3279.             if($_SERVER['APP_2FA_ALLOWED'] == 'true') {
  3280.                 $twoFactorAllowed true;
  3281.             }
  3282.         }
  3283.         if(isset($_SERVER['APP_2FA_GOOGLE_ALLOWED'])) {
  3284.             if($_SERVER['APP_2FA_GOOGLE_ALLOWED'] == 'true') {
  3285.                 $twoFactorGoogleAllowed true;
  3286.             }
  3287.         }
  3288.         try {
  3289.             $d Api::getDomain($account->getUserDomain());
  3290.         }
  3291.         catch(\Exception $e) {
  3292.             $this->addFlash('error'$this->translator->trans('Domain settings not available'));
  3293.             $this->logger->log('Error while getting domain ' $account->getUserDomain(), $request, ['accountName' => $account->getUsername()]);
  3294.             return $this->redirectToRoute('qp_main');
  3295.         }
  3296.         
  3297.         $domainMaxForwards $d->findOption('cfgMaxForwards') == null ? (isset($_SERVER['APP_DEFAULT_MAX_FORWARDS']) ? $_SERVER['APP_DEFAULT_MAX_FORWARDS'] : 10) : $d->findOption('cfgMaxForwards');
  3298.         $domainMaxExternalForwards $d->findOption('cfgMaxExternalForwards') == null $d->findOption('cfgMaxExternalForwards');
  3299.         $form $this->createForm(Settings::class);
  3300.         $form->handleRequest($request);
  3301.         
  3302.         $confirmKeys = ['Forward''Autoresponder''AutoresponderRcpt''SpamassassinReset',
  3303.             'SpamassassinList''SpamassassinLangs''Imap''ImapMails''Procmail''Mobile' 
  3304.         ];
  3305.         
  3306.         $forceLoginTarget false;
  3307.         
  3308.         if(isset($_SERVER['APP_LOGIN_TARGET'])) {
  3309.             $forceLoginTarget true;
  3310.         }
  3311.         
  3312.         if(!$form->isSubmitted()) {
  3313.             $sessionTime $account->findSOption('cfgSessionTime') == null $this->params->get('session_max_idle_time') : $account->findSOption('cfgSessionTime');
  3314.             $loginTarget $account->findSOption('cfgLoginTarget') == null 'form' $account->findSOption('cfgLoginTarget');
  3315.             
  3316.             // pagination from user's config. If not set - from env. If not set - from Account const
  3317.             $historyPagination $account->findSOption('cfgUserHistoryPagination') == null ?
  3318.             (isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
  3319.             : $account->findSOption('cfgUserHistoryPagination');
  3320.             
  3321.             // pagination from user's config. If not set - from env. If not set - from Account const
  3322.             $pagination $account->findSOption('cfgUserPagination') == null ?
  3323.             (isset($_SERVER['APP_DEFAULT_PER_PAGE']) ? $_SERVER['APP_DEFAULT_PER_PAGE'] : Account::NUMBER_OF_ITEMS)
  3324.             : $account->findSOption('cfgUserPagination');
  3325.             
  3326.             $saMaxScore $account->findSOption('cfgSAMaxScore') == null UserPref::SA_MAX_SCORE $account->findSOption('cfgSAMaxScore');
  3327.             $forceWebmailLang $account->findSOption('cfgForceWebmailLang') == null 'yes' $account->findSOption('cfgForceWebmailLang');
  3328.             $maxForwards $account->findSOption('cfgMaxForwards') == null $domainMaxForwards $account->findSOption('cfgMaxForwards');
  3329.             $maxExternalForwards $account->findSOption('cfgMaxExternalForwards') == null $domainMaxExternalForwards $account->findSOption('cfgMaxExternalForwards');
  3330.             $skin $account->findSOption('cfgSkin') == null 'standard' $account->findSOption('cfgSkin');
  3331.             $emailForAuth $account->findSOption('cfgEmailForAuth') == null '' $account->findSOption('cfgEmailForAuth');
  3332.             $twoFactorEnabled $account->findSOption('cfgTwoFactorEnabled') == null false : ($account->findSOption('cfgTwoFactorEnabled') == '1' true false);
  3333.             $emailForAuthConfirmed $account->findSOption('emailForAuthConfirmed') == null false : ($account->findSOption('emailForAuthConfirmed') == '1' true false);
  3334.             $twoFactorMethod $account->findSOption('cfgTwoFactorMethod') == null 'email' $account->findSOption('cfgTwoFactorMethod');
  3335.             $confirms = [];
  3336.             
  3337.             foreach($confirmKeys as $opt) {
  3338.                 if($account->findSOption('cfgDontConfirm' $opt) == null) {
  3339.                     $confirms[] = $opt;
  3340.                 }
  3341.             }
  3342.             
  3343.             $form->get('sessionTime')->setData($sessionTime);
  3344.             $form->get('loginTarget')->setData($loginTarget);
  3345.             $form->get('confirms')->setData($confirms);
  3346.             $form->get('historyPagination')->setData($historyPagination);
  3347.             $form->get('pagination')->setData($pagination);
  3348.             $form->get('saMaxScore')->setData($saMaxScore);
  3349.             $form->get('forceWebmailLang')->setData($forceWebmailLang);
  3350.             $form->get('maxForwards')->setData($maxForwards);
  3351.             $form->get('maxExternalForwards')->setData($maxExternalForwards);
  3352.             $form->get('skin')->setData($skin);
  3353.             $form->get('emailForAuth')->setData($emailForAuth);
  3354.             $form->get('twoFactorEnabled')->setData($twoFactorEnabled);
  3355.             $form->get('twoFactorMethod')->setData($twoFactorMethod);
  3356.         }
  3357.         
  3358.         if($form->isSubmitted() && $form->isValid()) {
  3359.             // wykrywanie zmiany metody 2FA na google
  3360.             $prevTwoFactorMethod $account->findSOption('cfgTwoFactorMethod') ?? 'email';
  3361.             $prevTwoFactorEnabled $account->findSOption('cfgTwoFactorEnabled') == '1';
  3362.             $newTwoFactorMethod $form->get('twoFactorMethod')->getData();
  3363.             $newTwoFactorEnabled $form->get('twoFactorEnabled')->getData();
  3364.             if (
  3365.                 ($prevTwoFactorMethod !== 'google' && $newTwoFactorMethod === 'google') ||
  3366.                 (!$prevTwoFactorEnabled && $newTwoFactorEnabled && $newTwoFactorMethod === 'google')
  3367.             ) {
  3368.                 $request->getSession()->set('showQrAfterSave'true);
  3369.             }
  3370.             
  3371.             $account->setSOption('cfgUserHistoryPagination'$form->get('historyPagination')->getData());
  3372.             $account->setSOption('cfgUserPagination'$form->get('pagination')->getData());
  3373.             $account->setSOption('cfgSAMaxScore'$form->get('saMaxScore')->getData());
  3374.             $account->setSOption('cfgSessionTime'$form->get('sessionTime')->getData());
  3375.             $account->setSOption('cfgLoginTarget'$form->get('loginTarget')->getData());
  3376.             $account->setSOption('cfgForceWebmailLang'$form->get('forceWebmailLang')->getData());
  3377.             $account->setSOption('cfgSkin'$form->get('skin')->getData());
  3378.             $emailForAuth $account->findSOption('cfgEmailForAuth') == null '' $account->findSOption('cfgEmailForAuth');
  3379.             $showInfoAbout2FA false;
  3380.             if($twoFactorAllowed) {
  3381.                 $saveEmailForAuth true;
  3382.                 
  3383.                 if($emailForAuth != $form->get('emailForAuth')->getData()) {
  3384.                     // new email address for auth confirmations
  3385.                     $account->setSOption('emailForAuthConfirmed''');
  3386.                     $account->setSOption('cfgTwoFactorEnabled''');
  3387.                     $showInfoAbout2FA true;
  3388.                     $tf = new TwoFactor($this->translator);
  3389.                     $newAuthToken $tf->generateNewAuthToken($account);
  3390.                     $emailText $tf->createEmailForNewAuthConnection($newAuthToken$this->generateUrl('check-two-factor', ['token' => $newAuthToken], UrlGeneratorInterface::ABSOLUTE_URL));
  3391.                     $from $tf->getFromAddress();
  3392.                     $subject $tf->getNewEmailForAuthSubject();
  3393.                     $emailTo $form->get('emailForAuth')->getData();
  3394.                     if(!is_null($emailTo)) {
  3395.                         $email = (new Email())
  3396.                             ->subject($subject)
  3397.                             ->from($from)
  3398.                             ->to($emailTo)
  3399.                             ->text($emailText)
  3400.                         ;
  3401.                         try {
  3402.                             $this->mailer->send($email);
  3403.                         }
  3404.                         catch(\Exception $e) {
  3405.                             $this->logger->log('Error while sending email for 2FA'$request, ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3406.                             $this->addFlash('error'$this->translator->trans('Error while sending email for 2FA'));
  3407.                             $showInfoAbout2FA false;
  3408.                             $saveEmailForAuth false;
  3409.                         }
  3410.                     }
  3411.                     else {
  3412.                         $showInfoAbout2FA false;
  3413.                     }
  3414.                 }
  3415.                 else {
  3416.                     if($form->get('twoFactorEnabled')->getData()) {
  3417.                         $account->setSOption('cfgTwoFactorEnabled''1');
  3418.                     }
  3419.                     else {
  3420.                         $account->setSOption('cfgTwoFactorEnabled''');
  3421.                     }
  3422.                 }
  3423.                 // jeÅ›li zmieniamy metodÄ™ 2FA, to ustawiamy cfgTwoFactorEnabled na false
  3424.                 if ($prevTwoFactorMethod !== $newTwoFactorMethod) {
  3425.                     $account->setSOption('cfgTwoFactorEnabled''');
  3426.                 }
  3427.                 if($form->get('emailForAuth')->getData() == null) {
  3428.                     $account->setSOption('cfgEmailForAuth''');    
  3429.                 }
  3430.                 else {
  3431.                     if($saveEmailForAuth) {
  3432.                         $account->setSOption('cfgEmailForAuth'$form->get('emailForAuth')->getData());
  3433.                     }   
  3434.                 }
  3435.                 // jeÅ›li już jest secret w account, to nie tworzymy nowego
  3436.                 if($twoFactorGoogleAllowed) {
  3437.                     if ($form->get('twoFactorMethod')->getData() == 'google' && $account->findSOption('google2fa_secret') == null) {
  3438.                         $totp TOTP::create();
  3439.                         $totp->setIssuer($serviceDomain);
  3440.                         $totp->setLabel($account->getUserName().'@'.$account->getUserDomain());
  3441.                         $secret $totp->getSecret();
  3442.                         // secret do logu
  3443.                         $this->logger->log('Google Authenticator newly created secret: ' $secret$request);
  3444.                         $account->setSOption('google2fa_secret'$secret);
  3445.                         Api::saveAccountParameters($account);
  3446.                     
  3447.                         //$qrContent = $totp->getProvisioningUri();
  3448.                         //$qrResult = Builder::create()->data($qrContent)->size(300)->build();
  3449.                         //$qrCodeDataUri = $qrResult->getDataUri();
  3450.                         
  3451.                         $account->setSOption('cfgTwoFactorMethod''google');
  3452.                         Api::saveAccountParameters($account);
  3453.                     }
  3454.                     if ($request->get('google2fa_code')) {
  3455.                         $this->logger->log('Google Authenticator secret z account: ' $account->findSOption('google2fa_secret'), $request);
  3456.                         $this->logger->log('Google Authenticator code: ' $request->get('google2fa_code'), $request);
  3457.                         $totp TOTP::create($account->findSOption('google2fa_secret'));
  3458.                         if ($totp->verify($request->get('google2fa_code'))) {
  3459.                             $account->setSOption('google2fa_confirmed''1');
  3460.                             $account->setSOption('cfgTwoFactorEnabled''1');
  3461.                             Api::saveAccountParameters($account);
  3462.                             $this->addFlash('notice''Google Authenticator activated!');
  3463.                         } else {
  3464.                             $this->addFlash('error''Incorrect Google Authenticator code');
  3465.                             $account->setSOption('cfgTwoFactorEnabled''');
  3466.                             $request->getSession()->set('showQrAfterSave'true);
  3467.                         }
  3468.                     }
  3469.                 }
  3470.                 $account->setSOption('cfgTwoFactorMethod'$form->get('twoFactorMethod')->getData());
  3471.             }
  3472.             
  3473.             if($this->security->isGranted('IS_IMPERSONATOR')) {
  3474.                 $account->setSOption('cfgMaxForwards'$form->get('maxForwards')->getData());
  3475.                 $account->setSOption('cfgMaxExternalForwards'$form->get('maxExternalForwards')->getData());
  3476.             }
  3477.             
  3478.             $confirms $form->get('confirms')->getData();
  3479.             
  3480.             foreach($confirmKeys as $opt) {
  3481.                 if(!in_array($opt$confirms)) {
  3482.                     $account->setSOption('cfgDontConfirm' $opttrue);
  3483.                 }
  3484.                 else {
  3485.                     $account->deleteOption('cfgDontConfirm' $opt);
  3486.                 }
  3487.             }
  3488.             
  3489.             if(Api::saveAccountParameters($account)) {
  3490.                 if($showInfoAbout2FA) {
  3491.                     $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.'));
  3492.                 }
  3493.                 else {
  3494.                     $this->addFlash('notice'$this->translator->trans('Settings saved'));
  3495.                 }
  3496.                 $this->logger->log('Settings for account saved'$request);
  3497.             }
  3498.             else {
  3499.                 $this->addFlash('error'$this->translator->trans('Settings NOT saved'));
  3500.                 $this->logger->log('Error while saving settings for account'$request);
  3501.             }
  3502.             
  3503.             return $this->redirectToRoute('qu_settings');
  3504.         }
  3505.         elseif($form->isSubmitted() && !$form->isValid()){
  3506.             $this->addFlash('error'$this->translator->trans('Settings NOT saved'));
  3507.         }
  3508.         
  3509.         $showQr false;
  3510.         $qrCodeDataUri null;
  3511.         // wymuszenie wyÅ›wietlenia QR po zmianie metody lub włączeniu 2FA ---
  3512.         if ($request->getSession()->has('showQrAfterSave')) {
  3513.             $showQr true;
  3514.             $request->getSession()->remove('showQrAfterSave');
  3515.             $secret $account->findSOption('google2fa_secret');
  3516.             if ($secret) {
  3517.                 $totp TOTP::create($secret);
  3518.                 $totp->setIssuer($serviceDomain);
  3519.                 $totp->setLabel($account->getUserName().'@'.$account->getUserDomain());
  3520.                 $qrContent $totp->getProvisioningUri();
  3521.                 $qrResult Builder::create()->data($qrContent)->size(300)->build();
  3522.                 $qrCodeDataUri $qrResult->getDataUri();
  3523.             }
  3524.         }
  3525.         /*if ($form->get('twoFactorMethod')->getData() === 'google' && $account->findSOption('google2fa_confirmed') != '1') {
  3526.             
  3527.             $this->logger->log('Google Authenticator secret z account przy wyÅ›wietlaniu: ' . $secret, $request);
  3528.             
  3529.         }*/
  3530.         
  3531.         return $this->render('skins/' $this->skin '/q_user/settings.html.twig', [
  3532.             'form' => $form->createView(),
  3533.             'forceLoginTarget' => $forceLoginTarget,
  3534.             'emailForAuthConfirmed' => $emailForAuthConfirmed,
  3535.             'twoFactorAllowed' => $twoFactorAllowed,
  3536.             'twoFactorGoogleAllowed' => $twoFactorGoogleAllowed,
  3537.             'qrCodeDataUri' => $showQr $qrCodeDataUri null,
  3538.             'showQr' => $showQr,
  3539.         ]);
  3540.     }
  3541.     
  3542.     /**
  3543.      * @Route("/panel/login-history/{orderBy}/{orderDir}", defaults={"orderBy"="created_at", "orderDir"="desc"}, name="qu_login_history")
  3544.      */
  3545.     public function loginHistory($orderBy$orderDirRequest $requestPaginatorInterface $paginator)
  3546.     {        
  3547.         $account $this->security->getUser()->getAccount();
  3548.         $this->denyAccessUnlessGranted('LOGIN_HISTORY'$account);
  3549.         $form $this->createForm(LoginHistory::class);
  3550.         $form->handleRequest($request);
  3551.         $filter = [];
  3552.         $options = [];
  3553.         
  3554.         $options["limit"] = Account::NUMBER_OF_LOGINS;
  3555.         
  3556.         if($this->security->isGranted('IS_IMPERSONATOR')) {
  3557.             // for user limitation is always on last Account::NUMBER_OF_LOGINS records
  3558.             $options["orderBy"] = $orderBy;
  3559.             $options["orderDir"] = $orderDir;
  3560.             $options["limit"] = Account::NUMBER_OF_LOGINS 100;
  3561.         }
  3562.         else {
  3563.             $options["orderBy"] = "created_at";
  3564.             $options["orderDir"] = "desc";
  3565.         }
  3566.         
  3567.         if($form->isSubmitted() && $form->isValid()) {
  3568.             if($form->get('status')->getData() != '') {
  3569.                 $filter['success'] = (int)$form->get('status')->getData();
  3570.             }
  3571.             
  3572.             if($form->get('ip')->getData() != '') {
  3573.                 $filter['ip'] = $form->get('ip')->getData();
  3574.             }
  3575.         }
  3576.         
  3577.         $loginData Api::getLoginHistory($this->security->getUser()->getEmail(), $filter$options);
  3578.         $qpostmasterController = new QPostmasterController($this->logger$this->translator$this->security,
  3579.             $this->params$this->mailer$this->requestStack$this->appExtension);
  3580.         $tagsArr $qpostmasterController->loginHistoryTagsFromFilters($filter);
  3581.                 
  3582.         if(!$this->security->isGranted('IS_IMPERSONATOR')) {
  3583.             // order data for non-impersonificated user
  3584.             // possible value - created_at / ip / success
  3585.             if($orderBy == 'created_at' || $orderBy == 'ip' || $orderBy == 'success') {
  3586.                 $this->session->set('app_user_lhistory_order_by'$orderBy);
  3587.                 $this->session->set('app_user_lhistory_order_dir'$orderDir);
  3588.             }
  3589.             
  3590.             if($orderBy == 'session') {
  3591.                 if($this->session->has('app_user_lhistory_order_by')) {
  3592.                     $orderBy $this->session->get('app_user_lhistory_order_by');
  3593.                     $orderDir $this->session->get('app_user_lhistory_order_dir');
  3594.                 }
  3595.                 else {
  3596.                     $orderBy 'created_at';
  3597.                     $orderDir 'desc';
  3598.                 }
  3599.             }
  3600.             
  3601.             switch($orderBy) {
  3602.                 case "created_at":
  3603.                     if($orderDir == "asc") {
  3604.                         usort($loginData"App\Controller\QUserController::_sortByCreatedByAsc");
  3605.                     }
  3606.                     break;
  3607.                 case "ip":
  3608.                     if($orderDir == "asc") {
  3609.                         usort($loginData"App\Controller\QUserController::_sortByIpAsc");
  3610.                     }
  3611.                     else {
  3612.                         usort($loginData"App\Controller\QUserController::_sortByIpDesc");
  3613.                     }
  3614.                     break;
  3615.                     
  3616.                 case "success":
  3617.                     if($orderDir == "asc") {
  3618.                         usort($loginData"App\Controller\QUserController::_sortByStatusAsc");
  3619.                     }
  3620.                     else {
  3621.                         usort($loginData"App\Controller\QUserController::_sortByStatusDesc");
  3622.                     }
  3623.                     break;
  3624.             }
  3625.         }
  3626.         
  3627.         return $this->render('skins/' $this->skin '/q_user/login_history.html.twig', [
  3628.             'form' => $form->createView(),
  3629.             'loginData' => $paginator->paginate(
  3630.                 $loginData$request->query->getInt('page'1), Account::NUMBER_OF_LOGINS
  3631.                 ),
  3632.             'filterTags' => $tagsArr,
  3633.             'orderDir' => $orderDir,
  3634.             'orderBy' => $orderBy,
  3635.             
  3636.         ]);
  3637.     }
  3638.     
  3639.     /**
  3640.      * @Route("/panel/loginhistorytag/del/{tag}", name="qu_loginhistorytag_del")
  3641.      */
  3642.     public function loginHistoryTagDelete($tagRequest $request)
  3643.     {
  3644.         return $this->redirectToRoute('qu_login_history');
  3645.     }
  3646.     
  3647.     
  3648.     /**
  3649.      * @Route("/panel/operation-history/{orderBy}/{orderDir}", defaults={"orderBy"="time", "orderDir"="desc"}, name="qu_operation_history")
  3650.      */
  3651.     public function operationHistory($orderBy$orderDirRequest $requestPaginatorInterface $paginator)
  3652.     {
  3653.         //         $form = $this->createForm(OperationHistory::class);
  3654.         //         $form->handleRequest($request);
  3655.         $account $this->security->getUser()->getAccount();
  3656.         $this->denyAccessUnlessGranted('OPERATION_HISTORY'$account);
  3657.         $filter = [];
  3658.         $limit $account->findSOption('cfgUserHistoryPagination') == null Account::NUMBER_OF_OPERATIONS $account->findSOption('cfgUserHistoryPagination');
  3659.         $filter["limit"] = (int)$limit;
  3660.         
  3661.         if($this->security->isGranted('IS_IMPERSONATOR')) {
  3662.             // for user limitation is always on last Account::NUMBER_OF_LOGINS records
  3663.             $filter["order"] = $orderBy;
  3664.             $filter["order_dir"] = $orderDir;
  3665.             $filter["limit"] = Account::NUMBER_OF_OPERATIONS 100;
  3666.         }
  3667.         else {
  3668.             $filter["order"] = "time";
  3669.             $filter["order_dir"] = "desc";
  3670.         }
  3671.         
  3672.         $filter["module"] = 'qu_*';
  3673.         
  3674.         $opDataPresent true;
  3675.         
  3676.         try {
  3677.             $opData Api::getOperationsHistory($this->security->getUser()->getEmail(), $filter);
  3678.         }
  3679.         catch(\Exception $ex) {
  3680.             $opData = [];
  3681.             $opDataPresent false;
  3682.         }
  3683.         
  3684.         if($opDataPresent && (!$this->security->isGranted('IS_IMPERSONATOR'))) {
  3685. //             echo "wewn previous"; exit();
  3686.             // order data for non-impersonificated user
  3687.             // possible value - time / msg
  3688.             
  3689.             if($orderBy == 'time' || $orderBy == 'msg') {
  3690.                 $this->session->set('app_user_ohistory_order_by'$orderBy);
  3691.                 $this->session->set('app_user_ohistory_order_dir'$orderDir);
  3692.             }
  3693.             
  3694.             if($orderBy == 'session') {
  3695.                 if($this->session->has('app_user_ohistory_order_by')) {
  3696.                     $orderBy $this->session->get('app_user_ohistory_order_by');
  3697.                     $orderDir $this->session->get('app_user_ohistory_order_dir');
  3698.                 }
  3699.                 else {
  3700.                     $orderBy 'time';
  3701.                     $orderDir 'desc';
  3702.                 }
  3703.             }
  3704.             
  3705.             switch($orderBy) {
  3706.                 case "time":
  3707.                     if($orderDir == "asc") {
  3708.                         usort($opData"App\Controller\QUserController::_sortByTimeAsc");
  3709.                     }
  3710.                     break;
  3711.                 case "msg":
  3712.                     if($orderDir == "asc") {
  3713.                         usort($opData"App\Controller\QUserController::_sortByMsgAsc");
  3714.                     }
  3715.                     else {
  3716.                         usort($opData"App\Controller\QUserController::_sortByMsgDesc");
  3717.                     }
  3718.                     break;
  3719.                     
  3720.             }
  3721.         }
  3722.         
  3723.         return $this->render('skins/' $this->skin '/q_user/operation_history.html.twig', [
  3724.             'opData' => $paginator->paginate(
  3725.                 $opData$request->query->getInt('page'1), Account::NUMBER_OF_OPERATIONS
  3726.                 ),
  3727.             'orderDir' => $orderDir,
  3728.             'orderBy' => $orderBy,
  3729.             'opDataPresent' => $opDataPresent,
  3730.         ]);
  3731.     }
  3732.     
  3733.     /**
  3734.      * @Route("/panel/panel-info", name="qu_panel_info")
  3735.      */
  3736.     public function panelInfo()
  3737.     {
  3738.         $license Api::getLicense();
  3739.         $sys = [];
  3740.         $sys['version'] = $this->params->get('app.version.postmaster');
  3741.         $sys['apiVersion'] = Api::getVersion();
  3742.         $sys['wrappersVersion'] = Api::getWrappersVersion();
  3743.         $sys['apiVersionString'] = Api::getVersionString();
  3744.         $sys['licensed'] = $license['company'];
  3745.         $sys['expires'] = $license['expires'];
  3746.         $sys['plan'] = $license['plan'];
  3747.         
  3748.         return $this->render('skins/' $this->skin '/q_user/panel_info.html.twig', [
  3749.             'sys' => $sys,
  3750.         ]);
  3751.     }
  3752.     
  3753.     /// mixing enabled and disabled forwards
  3754.     // order - "asc" or "desc"
  3755.     private static function _mixForwardsArrays($enabledForwardsArr$disabledForwardsArr$order)
  3756.     {
  3757.         $forwards = [];
  3758.         
  3759.         foreach($enabledForwardsArr as $fw) {
  3760.             $elem = [];
  3761.             $elem['address'] = $fw;
  3762.             $elem['enabled'] = true;
  3763.             $forwards[] = $elem;
  3764.         }
  3765.         
  3766.         foreach($disabledForwardsArr as $fw) {
  3767.             $elem = [];
  3768.             $elem['address'] = $fw;
  3769.             $elem['enabled'] = false;
  3770.             $forwards[] = $elem;
  3771.         }
  3772.         
  3773.         if($order == "asc") {
  3774.             usort($forwards'self::_forwardsComparator');
  3775.         }
  3776.         else {
  3777.             usort($forwards'self::_forwardsComparatorRev');
  3778.         }
  3779.         
  3780.         return $forwards;
  3781.     }
  3782.     
  3783.     private static function _forwardsComparator($a$b)
  3784.     {
  3785.         return strcmp($a["address"], $b["address"]);
  3786.     }
  3787.     
  3788.     private static function _forwardsComparatorRev($a$b)
  3789.     {
  3790.         return strcmp($a["address"], $b["address"]) * -1;
  3791.     }
  3792.     
  3793.     private static function _sortByCreatedByAsc($a$b) {
  3794.         if($a["created_at"] == $b["created_at"]) {
  3795.             return 0;
  3796.         }
  3797.         
  3798.         return ($a["created_at"] < $b["created_at"]) ? -1;
  3799.     }
  3800.     
  3801.     private static function _sortByTimeAsc($a$b) {
  3802.         if($a["time"] == $b["time"]) {
  3803.             return 0;
  3804.         }
  3805.         
  3806.         return ($a["time"] < $b["time"]) ? -1;
  3807.     }
  3808.     
  3809.     private static function _sortByIpAsc($a$b) {
  3810.         return strcmp($a["ip"], $b["ip"]);
  3811.     }
  3812.     private static function _sortByIpDesc($a$b) {
  3813.         return strcmp($a["ip"], $b["ip"]) * -1;
  3814.     }
  3815.     
  3816.     private static function _sortByMsgAsc($a$b) {
  3817.         return strcmp($a["msg"], $b["msg"]);
  3818.     }
  3819.     
  3820.     private static function _sortByMsgDesc($a$b) {
  3821.         return strcmp($a["msg"], $b["msg"]) * -1;
  3822.     }
  3823.     
  3824.     private static function _sortByStatusAsc($a$b) {
  3825.         if($a["success"] == $b["success"]) {
  3826.             return 0;
  3827.         }
  3828.         
  3829.         if($a["success"] == true && $b["success"] == false) {
  3830.             return -1;
  3831.         }
  3832.         else {
  3833.             return 1;
  3834.         }
  3835.     }
  3836.     
  3837.     private static function _sortByStatusDesc($a$b) {
  3838.         return QUserController::_sortByStatusAsc($a$b) * -1;
  3839.     }
  3840.     
  3841.     
  3842.     /**
  3843.      * returns autoresponder of the user and its status in autoresponderStatus
  3844.      * status can be 'no' if no autoresponder is defined, 'active' and 'inactive'
  3845.      * @param Account $account
  3846.      * @param String $autoresponderStatus
  3847.      * @return \App\Model\Autoresponder
  3848.      */
  3849.     private function _getAutoresponderForUser(Account $accountString &$autoresponderStatus)
  3850.     {
  3851.         $autoresponder = new Autoresponder();
  3852.         $autoresponderStatus 'no';
  3853.         
  3854.         // check if user has the autoresponder
  3855.         try {
  3856.             $autoresponder Api::getAutoresponder($account->getUserName(), $account->getUserDomain());
  3857.             $autoresponder->setActive(true);
  3858.             $autoresponderStatus 'active';
  3859.         }
  3860.         catch(\Exception $e) {}
  3861.         
  3862.         if($autoresponderStatus == 'no') {
  3863.             try {
  3864.                 $autoresponder Api::getAutoresponder(Autoresponder::NOT_ACTIVE_PREFIX $account->getUserName(),
  3865.                     Autoresponder::NOT_ACTIVE_PREFIX $account->getUserDomain());
  3866.                 $autoresponder->setActive(false);
  3867.                 $autoresponderStatus 'inactive';
  3868.             }
  3869.             catch(\Exception $e) {}
  3870.         }
  3871.                 
  3872.         return $autoresponder;
  3873.     }
  3874.     
  3875.     private function _isAntispamOn(Account $account)
  3876.     {
  3877.         return Api::getSAProtection($account);
  3878.     }
  3879.     
  3880.     /**
  3881.      * checks if cookie accountReload is set and if so reload Account in User object
  3882.      */
  3883.     private function _isReloadNeeded()
  3884.     {
  3885.         if(array_key_exists('accountReload'$_COOKIE) && $_COOKIE['accountReload'] == 1) {
  3886.             $user $this->security->getUser();
  3887.             $user->loadAccount();
  3888.             unset($_COOKIE['accountReload']);
  3889.             setcookie('accountReload'null, -1'/'); 
  3890.         }
  3891.     }
  3892.     
  3893.     /**
  3894.      * returns maximum allowed number of forwards or -1 if failed
  3895.      */
  3896.     private function _maxForwards($account) : int
  3897.     {
  3898.         $maxForwards = isset($_SERVER['APP_DEFAULT_MAX_FORWARDS']) ? $_SERVER['APP_DEFAULT_MAX_FORWARDS'] : 10;
  3899.         
  3900.         try {
  3901.             $d Api::getDomain($account->getUserDomain());
  3902.         }
  3903.         catch(\Exception $e) {
  3904.             return -1;
  3905.         }
  3906.         
  3907.         if($account->findSOption('cfgMaxForwards') == null) {
  3908.             if($d->findOption('cfgMaxForwards') != null) {
  3909.                 $maxForwards $d->findOption('cfgMaxForwards');
  3910.             }
  3911.         }
  3912.         else {
  3913.             $maxForwards $account->findSOption('cfgMaxForwards');
  3914.         }
  3915.                 
  3916.         return $maxForwards;
  3917.         
  3918.     }
  3919.     
  3920.     /**
  3921.      * returns maximum allowed number of external forwards or -1 if failed
  3922.      */
  3923.     private function _maxExternalForwards($account) : int
  3924.     {
  3925.         $maxExternalForwards 0;
  3926.         
  3927.         try {
  3928.             $d Api::getDomain($account->getUserDomain());
  3929.         }
  3930.         catch(\Exception $e) {
  3931.             return -1;
  3932.         }
  3933.         
  3934.         if($account->findSOption('cfgMaxExternalForwards') == null) {
  3935.             if($d->findOption('cfgMaxExternalForwards') != null) {
  3936.                 $maxExternalForwards $d->findOption('cfgMaxExternalForwards');
  3937.             }
  3938.             else {
  3939.                 $maxExternalForwards = isset($_SERVER['APP_DEFAULT_MAX_EXTERNAL_FORWARDS']) ? $_SERVER['APP_DEFAULT_MAX_EXTERNAL_FORWARDS'] : 3;
  3940.             }
  3941.         }
  3942.         else {
  3943.             $maxExternalForwards $account->findSOption('cfgMaxExternalForwards');
  3944.         }
  3945.         
  3946.         return $maxExternalForwards;
  3947.     }
  3948.     
  3949.     /**
  3950.      * counts number of external forwards
  3951.      */
  3952.     private function _externalForwardsCount($forwards$account)
  3953.     {
  3954.         $cnt 0;
  3955.         
  3956.         foreach($forwards as $f) {
  3957.             if(AccountTools::isEmailExternal($f, [$account->getUserDomain()])) {
  3958.                 $cnt++;
  3959.             }
  3960.         }
  3961.         
  3962.         return $cnt;
  3963.     }
  3964.     
  3965.     /**
  3966.      * returns procmail rules that point to address email
  3967.      * @param Account $account
  3968.      * @return Array
  3969.      */
  3970.     private function _procmailRulesEmail(Account $account)
  3971.     {
  3972.         try {
  3973.             $rules Api::getProcmailRules($account);
  3974.         }
  3975.         catch(\Exception $e) {
  3976.             $this->logger->log('Api::getProcmailRules() - exception from API'null , ['error_code' => $e->getCode(), 'error_message' => $e->getMessage()], 'critical');
  3977.             $this->addFlash('error'$this->translator->trans('Critical error, contact administrator.'));
  3978.             return $this->redirectToRoute('qu_main');
  3979.         }
  3980.         
  3981.         $retArr = [];
  3982.         
  3983.         foreach($rules as $r) {
  3984.             if($r->isDestEmail()) {
  3985.                 $retArr[] = $r;
  3986.             }
  3987.         }
  3988.         
  3989.         return $retArr;
  3990.     }
  3991.     
  3992.     /**
  3993.      * returns number of procmail rules that point to address email
  3994.      * @param Account $account
  3995.      * @return int
  3996.      */
  3997.     private function _numberProcmailRulesEmail(Account $account)
  3998.     {
  3999.         return count($this->_procmailRulesEmail($account));
  4000.     }
  4001.     
  4002.     /**
  4003.      * returns number of procmail rules that point to address email that is external
  4004.      * @param Account $account
  4005.      * @return int
  4006.      */
  4007.     private function _numberProcmailRulesEmailExternal(Account $account)
  4008.     {
  4009.         $num 0;
  4010.         
  4011.         foreach($this->_procmailRulesEmail($account) as $r) {
  4012.             if(AccountTools::isEmailExternal($r->getDest(), [$account->getUserDomain()])) {
  4013.                 $num $num 1;
  4014.             }
  4015.         }
  4016.         
  4017.         return $num;
  4018.     }
  4019.     
  4020.     /**
  4021.      * get username and userdomain for imap
  4022.      * @param Account $account
  4023.      * @return array
  4024.      */
  4025.     private function _getImapUserDomain(Account $account) : Array 
  4026.     {
  4027.         $retArr = [];
  4028.         
  4029.         if($this->isGranted('IS_IMPERSONATOR')) {
  4030.             $token $this->security->getToken();
  4031.             
  4032.             if ($token instanceof SwitchUserToken) {
  4033.                 $impersonatorUser $token->getOriginalToken()->getUser();
  4034.             }
  4035.             
  4036.             $retArr[0] = $this->security->getUser()->getUsername() . '*';
  4037.             $userDomainArr explode('@'$impersonatorUser->getUsername());
  4038.             $retArr[0] .= $userDomainArr[0];
  4039.             $retArr[1] = $userDomainArr[1];
  4040.         }
  4041.         else {
  4042.             $retArr[0] = $account->getUserName();
  4043.             $retArr[1] = $account->getUserdomain();
  4044.         }
  4045.         
  4046.         return $retArr;
  4047.     }
  4048.     
  4049.     /**
  4050.      * returns array of directories only from given level
  4051.      * @param array $dirs
  4052.      * @param int $level
  4053.      * @return array
  4054.      */
  4055. /*     private function _dirsWithLevel(array $dirs, int $level) : array
  4056.     {
  4057.         $arr = [];
  4058.         
  4059.         foreach($dirs as $d) {
  4060.             if($d->getLevel() == $level) {
  4061.                 $arr[] = $d;
  4062.             }
  4063.         }
  4064.         
  4065.         return $arr;
  4066.     } */
  4067.     
  4068.     /**
  4069.      * arranges array of directories according to their parent-children connections 
  4070.      * @param array $dirs
  4071.      * @param string $parent
  4072.      * @param int $level
  4073.      * @return array
  4074.      */
  4075. /*     private function _dirsChildren(array $dirs, string $parent, int $level) : array
  4076.     {
  4077.         $dirsLev = $this->_dirsWithLevel($dirs, $level);
  4078.         $arr = [];
  4079.         
  4080.         foreach($dirsLev as $d) {
  4081.             if($d->getParent() == $parent) {
  4082.                 $arr[] = $d;
  4083.                 
  4084.                 $arr = array_merge($arr, $this->_dirsChildren($dirs, $d->getName(), $level + 1));
  4085.             }
  4086.         }
  4087.         
  4088.         return $arr;
  4089.     } */
  4090. }