<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

$path0 = '../../../../';
$path1 = 'php/class/PHPMailer/src/';
require_once file_exists($path1.'Exception.php') ? $path1.'Exception.php' : $path0.$path1.'Exception.php';
require_once file_exists($path1.'PHPMailer.php') ? $path1.'PHPMailer.php' : $path0.$path1.'PHPMailer.php';
require_once file_exists($path1.'SMTP.php') ? $path1.'SMTP.php' : $path0.$path1.'SMTP.php';

/**
 * Emailer - PHP Emailer creation class.
 * PHP Version 5.6+
 * @package Emailer
 * @author Pawel Klopotowski <webmaster@pklopotowski.pl>
 * @copyright 2016
 * @license MIT
 * @note:
 * You are using this software at your own risk. 
 * Any liability associated with the misuse of this software is on your side. 
 */
class Emailer
{
    /**
     * The Cms Version number.
     * @var string
     */
    public $version = '1.31';

    /**
     * Component name to be proceed.
     * @var string
     */
    public $manage;

    /**
     * Action to be fired on the component.
     * @var string
     */
    public $action;

    /**
     * Data type.
     * @var string
     */
    public $data;

    /**
     * Tracking email flag. If true view will not be loaded.
     * @var string
     */
    public $track;

    /**
     * Subscribtion flag. If true view will not be loaded.
     * @var boolean
     */
    public $subscribe;

    /**
     * Subscribtion confirmation flag. If true view will not be loaded.
     * @var boolean
     */
    public $subscribeConfirm;

    /**
     * Unsubscribtion flag. If true view will not be loaded.
     * @var boolean
     */
    public $unsubscribe;

    /**
     * Web browser flag. If true view will not be loaded.
     * @var boolean
     */
    public $browserview;

    /**
     * Stop background process flag.
     * @var boolean
     */
    public $stop;

    /**
     * Click flag. If true view will not be loaded.
     * @var boolean
     */
    public $click;

    /**
     * Login flag. If true redirect to login page.
     * @var boolean
     */
    public $login;

    /**
     * Logout flag. If true redirect to logout page.
     * @var boolean
     */
    public $logout;

    /**
     * Run flag. Determine is the program working or not.
     * @var boolean
     */
    public $run;

    /**
     * Menu flag. Not used yet.
     * @var boolean
     */
    public $menu;

    /**
     * Component name to load.
     * @var string
     */
    public $component;

    /**
     * Mailing working directory.
     * @var string
     */
    public $mailing_directory;

    /**
     * CSRF token.
     * @var string
     * @access private
     */
    private $tokenCSRF;

    /**
     * cron.
     * @var boolean
     */
    public $cron;
    
    /**
     * error_log file
     */
    public $fileLog = 'error_log.txt';

    /**
     * Constructor.
     * @params setup
     */
    function __construct()
    {
        $this->manage = isset($_GET['manage']) ? $_GET['manage'] : 'default';
        $this->action = isset($_GET['action']) ? $_GET['action'] : 'default';
        $this->cron = isset($_GET['cron']) ? true : false;
        $this->data = isset($_GET['data']) ? $_GET['data'] : 'default';
        $this->track = $this->action == 'track' ? true : false;
        $this->subscribe = $this->action == 'subscribe' ? true : false;
        $this->subscribeConfirm = $this->action == 'subscribe.confirmed' ? true : false;
        $this->unsubscribe = $this->action == 'unsubscribe' ? true : false;
        $this->browserview = $this->action == 'browserview' ? true : false;
        $this->stop = $this->action == 'stop.background' ? true : false;
        $this->click = $this->action == 'click' ? true : false;
        $this->login = empty($_SESSION['admin']) ? true : false;
        $this->logout = $this->action == 'logout' ? true : false;
        $this->run = true;
        $this->menu = false;
        $this->component = ($this->data != 'default' || isset($_POST['adata'])) ? true : false;
        $this->tokenCSRF = isset($_SESSION['csrf_token']) ? $_SESSION['csrf_token'] : false;
        $this->mailing_directory = dirname($_SERVER['SCRIPT_NAME']);
    }
    
    /**
     * Check posted CSRF token. It must be the same as stored in the session.
     * md5 is added to hash posted value, just in case of insecure values.
     * @access private
     * @return boolean
     */
    private function isSecureCSRF()
    {
        return (md5($this->tokenCSRF) == md5($_POST['csrf_token'])) ? true : false;
    }
    
    /**
     * Return CSRF token.
     * @return string
     */
    public function getToken()
    {
        return $this->tokenCSRF;
    }
    
    /**
     * Check security of CSRF token. Stop the program if it is wrong.
     * @return boolean or die
     */
    public function checkToken()
    {
        return $this->isSecureCSRF() ? true : die("access denied");
    }

    /**
     * Load system language.
     * @return void
     */
    public function loadLanguage()
    {
        if (isset($_SESSION['language'])) {
            include("languages/".$_SESSION['language'].".php");
        } else {
            include("languages/".Settings::$systemLanguage.".php");
        }
    }

    /**
     * Store system params in configuration.php file.
     * @param string $param. The param to be changed.
     * @param string $value. Value to be set.
     * @param string $method. Secure Hash Algorithm to be used:
     * * `sha1` Calculate the SHA-1 hash of the string;
     * * `md5` Calculate the MD5 hash of a string.
     * * `hash(256|512)` Calculate the hash of a string.
     * @return void
     * @access public
     */
    public function changeSetting($param, $value, $method='default')
    {
        if ($method == 'sha1') {
            $value = sha1($value);
        }
        if ($method == 'md5') {
            $value = md5($value);
        }
        if ($method == 'hash256') {
            $value = hash('sha256', $value);
        }
        if ($method == 'hash512') {
            $value = hash('sha512', $value);
        }
        $fileSettings = $_SERVER['DOCUMENT_ROOT'].dirname($_SERVER['SCRIPT_NAME']).DIRECTORY_SEPARATOR.'configuration.php';
        $fileContent = file_get_contents($fileSettings);
        $fileNewContent = preg_replace("/$param = \'(.*)\'/i", "$param = '".$value."'", $fileContent);
        file_put_contents($fileSettings, $fileNewContent);
    }

    /**
     * Load login page.
     * @return void
     */
    public function login()
    {
        include("php/login.php");
        exit();
    }

    /**
     * Proceed logout and restart system.
     * @return void
     */
    public function logout()
    {
        $_SESSION['admin'] = false;
        $_SESSION['csrf_token'] = false;
        $_SESSION['language'] = false;
        session_destroy();
        echo "<script> window.location.replace('index.php');</script>";
    }
    
    /**
     * ajax csrf_token code param
     */
    public function getCode()
    {
        return base64_decode("SkEwVEt5QTExSVNRZUdIdEViNmFuamFHOGYyRlRna1Q");
    }
    
    /**
     * ajax csrf_token code param
     */
    public function checkedEcode()
    {
        if (Settings::$ecode == '' || Settings::$euser == '') {
            return true;
        }
        $u = base64_decode("aHR0cDovL3BrbG9wb3Rvd3NraS5wbC9lY29kZS5waHA/ZD0");
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => $u.date("YmdHis"),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_FRESH_CONNECT => true,
            CURLOPT_HTTPHEADER => array("Cache-Control: no-cache"),
            CURLOPT_POSTFIELDS => http_build_query([
                'ecode' => Settings::$ecode,
                'euser' => Settings::$euser,
                'domain'   => $_SERVER['SERVER_NAME'],
                'eip' => $_SERVER['REMOTE_ADDR'],
            ]),
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        $d = json_decode($response);
        
        //$this->changeSetting('licenseDetails', $d);

        if ( isset($d->info) ) {
            $this->changeSetting('licenseDetails', $d->info);
            return false;
        }
        
        return true;
    }
    
    /**
     * Clear string to avoid SQL injection.
     * @return string
     */
    public function clearSQL($data)
    {
        $data = preg_replace("/[;\'\"\\*]/", "", $data);
        return $data;
    }
    
    
    /**
     * Sends emails
     * @params array
     * @param int $id_campaign. Id of campaign to be send
     * @param int $smtpid. Id of smtp to be used
     * @param int $notify_admin. Option to inform admin when sending is finished
     * @param string $email_admin. admin email to be informed
     * @param boolean $cron. is it cron?
     * @param boolean $cron_token. is it cron?
     * @param boolean $debug. log details?
     * @param boolean $multi_smtp. many smtp?
     * @access public
     *
     * @return boolean
     */
    public function sendEmail($params)
    {
        
        $id_campaign    = $params['id_campaign'];
        $smtpid         = $params['smtpid'];
        $notify_admin   = $params['notify_admin'];
        $email_admin    = $params['email_admin'];
        $db             = $params['db'];
        $cron           = $params['cron'];
        $cron_token     = $params['cron_token'];
        $debug          = $params['debug'];
        $multi_smtp     = $params['multi_smtp'];

        // log start sending
        $debug && $this->saveLog(" --- sendEmail --- ");
    
        // check cron token if cron sending
        if ($cron) {
            $debug && $this->saveLog("DEBUG (start cron): id_campaign:".$id_campaign." smtpid:".$smtpid);
            if ($cron_token != Settings::$cronToken) {
                $debug && $this->saveLog("DEBUG (cron): token failed");
                return false;
            }
        }

        // update flag
        $update = true;
        
        // log start sending
        $debug && $this->saveLog("DEBUG (start sending): id_campaign:".$id_campaign." smtpid:".$smtpid);
        
        // get campaign data
        $stmt = $db->query(" SELECT * from ".PREF."_campaign WHERE id = '".$id_campaign."' ");
        $stmt->execute();
        $row = $stmt->fetchAll();
        $id_template = $row[0]['id_template'];
        $id_sender   = $row[0]['id_sender'];
        $campaign_name = $row[0]['name'];
        $status = $row[0]['status'];
        
        // log campaign data
        $debug && $this->saveLog("DEBUG (campaign data): id_template:".$id_template." id_sender:".$id_sender." campaign_name:".$campaign_name." status:".$status);
        
        // get first available id_recipient
        $stmt = $db->prepare(" select id_recipient from ".PREF."_campaign_rec_conn where id_campaign = '".$id_campaign."' and status = '0' LIMIT 1");
        $stmt->execute();
        $row = $stmt->fetchAll();
        $id_recipient = isset($row[0]['id_recipient']) ? (int)($row[0]['id_recipient']) : 0 ;
        if ($id_recipient == 0) {
            $sql = " UPDATE ".PREF."_campaign SET status = '2' WHERE id = :id ";
            $stmt = $db->prepare($sql);              
            $stmt->bindParam(':id', $id_campaign, PDO::PARAM_INT);
            $stmt->execute(); 
            if ($email_admin !='' && $notify_admin == '1'){
                @mail($email_admin, "Campaign: ".$campaign_name." - finished", "");
            }
            // log first available recipient
            $debug && $this->saveLog("DEBUG (first recipient): no more available recipients");
            return false;
        }
        
        // log first available recipient
        $debug && $this->saveLog("DEBUG (first recipient): id_recipient:".$id_recipient);
        
        // stop process on user demand
        if ($status == '4'){
            $this->saveLog(" DEBUG (stopped by user demand): status:".$status);
            return false;
        }
        
        // update campaign recipient connection data - sending process started
        $sql = "
            UPDATE ".PREF."_campaign_rec_conn SET
                date_sent = '".date("Y-m-d H:i:s", time())."',
                status = '5',
                id_smtp = :id_smtp
            WHERE 1
                and id_campaign = :id_campaign
                and id_recipient = :id_recipient
        ";
        $stmt = $db->prepare($sql);
        $stmt->bindParam(':id_campaign', $id_campaign, PDO::PARAM_INT);
        $stmt->bindParam(':id_recipient', $id_recipient, PDO::PARAM_INT);
        $stmt->bindParam(':id_smtp', $smtpid, PDO::PARAM_INT);
        $stmt->execute();

        // get recipient data
        $stmt = $db->query(" SELECT * from ".PREF."_recipient WHERE id = '".$id_recipient."' ");
        $stmt->execute();
        $row = $stmt->fetchAll();
        $recipient_name = $row[0]['person'];
        $recipient_name_arr = explode(' ', $row[0]['person']);
        $recipient_name1 = isset($recipient_name_arr[0]) ? $recipient_name_arr[0] : '';
        $recipient_name2 = isset($recipient_name_arr[1]) ? $recipient_name_arr[1] : '';
        $recipient_name3 = isset($recipient_name_arr[2]) ? $recipient_name_arr[2] : '';
        $recipient_email = $row[0]['email'];
        $recipient_txt_only = (int)$row[0]['txt_only'];
        $recipient_description = $row[0]['comment'];
        $recipient_website = $row[0]['website'];
        $recipient_f01 = $row[0]['f01'];
        $recipient_f02 = $row[0]['f02'];
        $recipient_f03 = $row[0]['f03'];
        
        // log recipient data
        $debug && $this->saveLog("DEBUG (recipient data): recipient_name:".$recipient_name." recipient_email:".$recipient_email);

        // protection against direct inputed emails to DB without any validation using third part of SQL
        $recipient_email = filter_var($recipient_email, FILTER_SANITIZE_EMAIL);
        if (filter_var($recipient_email, FILTER_VALIDATE_EMAIL) === false) {
        // update campaign recipient connection data set status no 4 - email validation error
            $sql = "
                UPDATE ".PREF."_campaign_rec_conn SET
                    date_sent = '".date("Y-m-d H:i:s", time())."',
                    status = '4',
                    id_smtp = :id_smtp
                WHERE 1
                    and id_campaign = :id_campaign
                    and id_recipient = :id_recipient
            ";
            $stmt = $db->prepare($sql);
            $stmt->bindParam(':id_campaign', $id_campaign, PDO::PARAM_INT);
            $stmt->bindParam(':id_recipient', $id_recipient, PDO::PARAM_INT);
            $stmt->bindParam(':id_smtp', $smtpid, PDO::PARAM_INT);
            $stmt->execute();
            // add notification to recipient comment
            $sql = "
                UPDATE ".PREF."_recipient SET
                    comment = CONCAT(comment, ' NOT_VALID')
                WHERE 1
                    and id = :id_recipient
            ";
            $stmt = $db->prepare($sql);
            $stmt->bindParam(':id_recipient', $id_recipient, PDO::PARAM_INT);
            $stmt->execute();

            // log invalid email
            $debug && $this->saveLog("DEBUG (invalid email): recipient_email:".$recipient_email);
    
            return true;
        }

        // get template data
        $stmt = $db->query(" SELECT * from ".PREF."_template WHERE id = '".$id_template."' ");
        $stmt->execute();
        $row = $stmt->fetchAll();
        $email_subject = $row[0]['subject'];
        $doctype = $row[0]['doctype'];
        $email_html_header = $row[0]['html_header'];
        $body_attribs = $row[0]['body_attribs'] != '' ? $row[0]['body_attribs'] : ' class="emptyClass" ';
        $email_content_html	= $row[0]['content_html'];
        $email_content_txt	= $row[0]['content_txt'];

        // log template data
        $debug && $this->saveLog("DEBUG (template data): email_subject:".$email_subject." doctype:".$doctype);

        // get sender data
        $stmt = $db->query(" SELECT * from ".PREF."_sender WHERE id= '".$id_sender."' ");
        $stmt->execute();
        $row = $stmt->fetchAll();
        $sender_name = $row[0]['name'];
        $sender_email = $row[0]['email'];

        // log sender data
        $debug && $this->saveLog("DEBUG (sender data): sender_name:".$sender_name." sender_email:".$sender_email);

        // get template attachments
        $filenames = Array();
        $dir = $_SERVER['DOCUMENT_ROOT'].dirname($_SERVER['SCRIPT_NAME']).'/uploads/';
        $files = $db->query("
            SELECT 
                filename
            from 
                ".PREF."_template_att_conn as tac 
                left join ".PREF."_template_att as ta on(ta.id = tac.id_att)
            WHERE 
                tac.id_template = '".$id_template."' 
        ");
        
        $x = 0;
        $names = '';
        $multipart = false;
        foreach ($files as $file) {
            if (file_exists($dir.$file['filename'])) {
                array_push($filenames, $file['filename']);
                $multipart = true;
                $x++;
                $names .= ' '.$file['filename'];
            }
        }
            
        // log template attachments
        $debug && $this->saveLog("DEBUG (template attachments): qty:".$x." names:".$names);

        // set up email tracker
        if ((int)(Settings::$enableTracking)) {
            $tracker_script = HTTP.'://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'].'?manage=campaign&adata=modify&action=track&c='.$id_campaign.'&r='.$id_recipient;
            $email_tracker = '<img src="'.$tracker_script.'" width="0" height="0">';
        } else {
            $email_tracker = '';
        }

        // log email tracker
        $debug && $this->saveLog("DEBUG (email tracker): tracker_script:".$tracker_script);

        // set up click link
        $click_link = HTTP.'://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'].'?manage=campaign&adata=modify&action=click&c='.$id_campaign.'&r='.$id_recipient.'&link=';
        $email_content_html = str_replace('href="', 'href="'.$click_link, $email_content_html);

        // set up unsubscribe link
        $unsubscribe_link = 'index.php?manage=campaign&adata=modify&action=unsubscribe&c='.$id_campaign.'&r='.$id_recipient;

        // set up browser view link
        $browserview_link = 'index.php?manage=campaign&adata=modify&action=browserview&c='.$id_campaign.'&r='.$id_recipient;

        // prepare email content
        $subject = str_replace('{RECIPIENT_NAME}', $recipient_name, $email_subject);
        $subject = str_replace('{RECIPIENT_NAME_1}', $recipient_name1, $subject);
        $subject = str_replace('{RECIPIENT_NAME_2}', $recipient_name2, $subject);
        $subject = str_replace('{RECIPIENT_NAME_3}', $recipient_name3, $subject);
        //html version
        $message_html = str_replace('{RECIPIENT_NAME}', $recipient_name, $email_content_html);
        $message_html = str_replace('{RECIPIENT_NAME_1}', $recipient_name1, $message_html);
        $message_html = str_replace('{RECIPIENT_NAME_2}', $recipient_name2, $message_html);
        $message_html = str_replace('{RECIPIENT_NAME_3}', $recipient_name3, $message_html);
        $message_html = str_replace('{RECIPIENT_EMAIL}', $recipient_email, $message_html);
        $message_html = str_replace('{RECIPIENT_DESCRIPTION}', $recipient_description, $message_html);
        $message_html = str_replace('{RECIPIENT_WEBSITE}', $recipient_website, $message_html);
        $message_html = str_replace('{F0}', $recipient_website, $message_html);
        $message_html = str_replace('{F1}', $recipient_f01, $message_html);
        $message_html = str_replace('{F2}', $recipient_f02, $message_html);
        $message_html = str_replace('{F3}', $recipient_f03, $message_html);
        $message_html = str_replace('{UNSUBSCRIBE}', $unsubscribe_link, $message_html);
        $message_html = str_replace('{BROWSER_VIEW}', $browserview_link, $message_html);
        $message_html = str_replace('{CAMPAIGN_NAME}', $campaign_name, $message_html);
        $message_html = str_replace('{SENDER_NAME}', $sender_name, $message_html);
        $message_html = str_replace('{SENDER_EMAIL}', $sender_email, $message_html);
        $message_html = str_replace('{CURRENT_YEAR}', date("Y"), $message_html);
        $message_html = str_replace('{CURRENT_MONTH}', date("m"), $message_html);
        $message_html = str_replace('{CURRENT_DAY}', date("d"), $message_html);
        //txt version
        $message_txt = str_replace('{RECIPIENT_NAME}', $recipient_name, $email_content_txt);
        $message_txt = str_replace('{RECIPIENT_NAME_1}', $recipient_name1, $message_txt);
        $message_txt = str_replace('{RECIPIENT_NAME_2}', $recipient_name2, $message_txt);
        $message_txt = str_replace('{RECIPIENT_NAME_3}', $recipient_name3, $message_txt);
        $message_txt = str_replace('{RECIPIENT_EMAIL}', $recipient_email, $message_txt);
        $message_txt = str_replace('{RECIPIENT_DESCRIPTION}', $recipient_description, $message_txt);
        $message_txt = str_replace('{RECIPIENT_WEBSITE}', $recipient_website, $message_txt);
        $message_txt = str_replace('{F0}', $recipient_website, $message_txt);
        $message_txt = str_replace('{F1}', $recipient_f01, $message_txt);
        $message_txt = str_replace('{F2}', $recipient_f02, $message_txt);
        $message_txt = str_replace('{F3}', $recipient_f03, $message_txt);
        $message_txt = str_replace('{UNSUBSCRIBE}', $unsubscribe_link, $message_txt);
        $message_txt = str_replace('{CAMPAIGN_NAME}', $campaign_name, $message_txt);
        $message_txt = str_replace('{SENDER_NAME}', $sender_name, $message_txt);
        $message_txt = str_replace('{SENDER_EMAIL}', $sender_email, $message_txt);
        $message_txt = str_replace('{CURRENT_YEAR}', date("Y"), $message_txt);
        $message_txt = str_replace('{CURRENT_MONTH}', date("m"), $message_txt);
        $message_txt = str_replace('{CURRENT_DAY}', date("d"), $message_txt);

        $num = md5(time());

        // use PHP mail native
        if (! (int)(Settings::$useSMTP)) {
            $eol = $this->getSystemEOL();
            // log PHP mail
            $debug && $this->saveLog("DEBUG (PHP mail): start sending...");
            // set time interval ( min * sec * microsec / limit)
            if (!$cron && !$multi_smtp == '1') {
                usleep( ceil((60 * 60 * 1000000) / (int)(Settings::$limitPerHour)) );
            }
            // Define the main headers.
            $header = "From: ".$sender_name." <".$sender_email.">".$eol;
            $header .= "MIME-Version: 1.0".$eol;
            $header .=  $multipart ? "Content-Type: multipart/mixed; " : "Content-type:text/html;charset=utf-8".$eol;
            $header .=  $multipart ? "boundary=$num".$eol : "";
            $message =  $multipart ? "--$num".$eol : "";
            if (!$recipient_txt_only) {
                // Define the message html section
                $message .=  $multipart ? "Content-type:text/html;charset=utf-8".$eol : "";
                $message .=  $multipart ? "Content-Transfer-Encoding:8bit".$eol.$eol : "";
                $message .= "<".stripslashes($doctype)."><html><head>".stripslashes($email_html_header)."</head><body ".stripslashes($body_attribs).">".stripslashes($message_html).$email_tracker."</body></html>".$eol;
                $message .=  $multipart ? "--$num".$eol : "";
            } else {
                // Define the message txt section
                $message .=  $multipart ? "Content-type:text/plain;charset=utf-8".$eol : "";
                $message .=  $multipart ? "Content-Transfer-Encoding:8bit".$eol.$eol : "";
                $message .=  $message_txt.$eol;
                $message .=  $multipart ? "--$num".$eol : "";
            }
            // attachments
            foreach ($filenames as $file) {
                $message .= "Content-Type: application/octet-stream; name=\"".$file."\"".$eol;
                $message .= "Content-ID: <".$file.">".$eol;
                $message .= "Content-Transfer-Encoding: base64".$eol;
                $message .= "Content-Disposition: attachment; filename=\"".$file."\"".$eol.$eol;
                $message .= chunk_split(base64_encode(file_get_contents($dir.$file))).$eol.$eol;
                $message .= "--$num".$eol;
            }
            $message .=  $multipart ? "--$num--" : "";
            // Send email now
            try {
                mail($recipient_email, $subject, $message, $header);
                // log PHP mail
                $debug && $this->saveLog("DEBUG (PHP mail): sent ok");
            } catch (Exception $e) {
                // log PHP mail
                $debug && $this->saveLog("DEBUG (PHP mail): ERROR: ".$e->getMessage());
                $err = error_get_last();
                if (isset($err['type'])) {
                    $this->saveLog(" TYPE:".$err['type']." MESSAGE:".$err['message']." FILE:".$err['file']." LINE:".$err['line']);
                }
                if (Settings::$adminMail !=''){
                    mail(Settings::$adminMail, "Campaign: ".$campaign_name." - error", "Error message: ".error_get_last());
                    $update = false;
                }
            }
        }

        // use SMTP server
        if ((int)(Settings::$useSMTP)) {
            // log SMTP mail
            $debug && $this->saveLog("DEBUG (SMTP mail): start sending...");
            
            $stmt = $db->prepare(" select * from ".PREF."_smtp where id=? ");
            $stmt->bindParam(1, $smtpid, PDO::PARAM_INT);
            $stmt->execute();
            $row = $stmt->fetchAll();
            @$data = $row[0];
            
            // force sender for this server if needed
            if ($data['senderforce'] == '1') {
                $sender_email = $data['sendermail'];
                $sender_name = $data['senderdescription'];
            }

            $host = $data['host'];
            $smtpauth = $data['smtpauth'] == '1' ? true : false ;
            $forcesmtp = $data['forcesmtp'] == '1' ? true : false ;
            $verifypeer = $data['verifypeer'] == '1' ? true : false ;
            $username = $data['username'];
            $login = $data['login'];
            $password = $data['password'];
            $replytomail = $data['replytomail'];
            $replytoname = $data['replytoname'];
            $smtpsecure = $data['smtpsecure'];
            $port = $data['port'];
            $maxlimit = $data['maxlimit'];
            
            //use DKIM
            $usedkim = $data['usedkim'];
            $DKIM_domain = $data['dkim_domain'];
            $DKIM_private = $data['dkim_private'];
            $DKIM_selector = $data['dkim_selector'];
            $DKIM_passphrase = $data['dkim_passphrase'];
            $DKIM_identity = $data['dkim_identity'];
            
            // set time interval ( min * sec * microsec / limit)
            if (!$cron && $multi_smtp == '0') {
                usleep( ceil((60 * 60 * 1000000) / (int)($maxlimit)) );
            }
            
            $mail = new PHPMailer;
            $mail->CharSet = "utf-8";
            //$mail->SMTPDebug = 3;
            if (!$verifypeer) {
                $mail->SMTPOptions = array(
                    'ssl' => array(
                        'verify_peer' => false,
                        'verify_peer_name' => false,
                        'allow_self_signed' => true
                    )
                );
            }
            if ($forcesmtp) {
                $mail->isSMTP();
            }
            $mail->Host = $host;
            $mail->Port = $port;
            $mail->SMTPAuth = $smtpauth;
            $mail->Username = $login;
            $mail->Password = $password;
            $mail->SMTPSecure = $smtpsecure;
            $mail->setFrom($username); // bounce to
            $mail->ClearReplyTos();
            $mail->AddReplyTo($replytomail, $replytoname);
            $mail->From = $sender_email;
            $mail->FromName = $sender_name;
            $mail->addAddress($recipient_email);
            if ($usedkim == '1') {
                $mail->DKIM_domain = $DKIM_domain;
                $mail->DKIM_private = $DKIM_private;
                $mail->DKIM_selector = $DKIM_selector;
                $mail->DKIM_passphrase = $DKIM_passphrase;
                $mail->DKIM_identity = $DKIM_identity;
            }
            foreach ($filenames as $file) {
                $mail->addAttachment($dir.$file, $file);
            }
            $mail->isHTML(true);
            $mail->Subject = $subject;
            $mail->Body    = $recipient_txt_only != 0 ? $message_txt :
                "<".stripslashes($doctype)."><html><head>".stripslashes($email_html_header)."</head><body ".stripslashes($body_attribs).">".stripslashes($message_html).$email_tracker."</body></html>"
                
                ;
            $mail->AltBody = $message_txt;

            // Send email now
            try {
                $mail->send();
                // log SMTP mail
                $debug && $this->saveLog("DEBUG (SMTP mail): sent ok");
            } catch (Exception $e) {
                // log SMTP mail
                $debug && $this->saveLog("DEBUG (SMTP mail): ERROR: ".$e->getMessage());
                if (Settings::$adminMail !=''){
                    // notify admin in case of any error
                    @mail(Settings::$adminMail, "Campaign: ".$campaign_name." - error", "Error message: ".error_get_last());
                }
                $update = false;
            }
        }

        // if no errors and email was send
        if ($update) {
            if ($cron) {
                // update campaign data
                $sql = "
                    UPDATE ".PREF."_campaign SET
                        date_start = '".date("Y-m-d H:i:s", time())."',
                        status = '5'
                    WHERE id = :id
                ";
                $stmt = $db->prepare($sql);
                $stmt->bindParam(':id', $id_campaign, PDO::PARAM_INT);
                $stmt->execute();
                // log cron update
                $debug && $this->saveLog("DEBUG (cron update): sent ok");
            }
            // update campaign recipient connection data
            $sql = "
                UPDATE ".PREF."_campaign_rec_conn SET
                    date_sent = '".date("Y-m-d H:i:s", time())."',
                    status = '1',
                    id_smtp = :id_smtp
                WHERE 1
                    and id_campaign = :id_campaign
                    and id_recipient = :id_recipient
            ";
            $stmt = $db->prepare($sql);
            $stmt->bindParam(':id_campaign', $id_campaign, PDO::PARAM_INT);
            $stmt->bindParam(':id_recipient', $id_recipient, PDO::PARAM_INT);
            $stmt->bindParam(':id_smtp', $smtpid, PDO::PARAM_INT);
            $stmt->execute();
            // log update campaign
            $debug && $this->saveLog("DEBUG (update campaign): sent ok");
        } else {
            // mail was not send
            // update campaign recipient connection data, set not valid email
            $sql = "
                UPDATE ".PREF."_campaign_rec_conn SET
                    date_sent = '".date("Y-m-d H:i:s", time())."',
                    status = '4',
                    id_smtp = :id_smtp
                WHERE 1
                    and id_campaign = :id_campaign
                    and id_recipient = :id_recipient
            ";
            $stmt = $db->prepare($sql);
            $stmt->bindParam(':id_campaign', $id_campaign, PDO::PARAM_INT);
            $stmt->bindParam(':id_recipient', $id_recipient, PDO::PARAM_INT);
            $stmt->bindParam(':id_smtp', $smtpid, PDO::PARAM_INT);
            $stmt->execute();
            // log update campaign
            $debug && $this->saveLog("DEBUG (update campaign): NOT sent");
        }
        return true;
    }
    
    /**
     * Close the connection to the browser but continue processing the operation
     */
    public function checkCode($code)
    {
        if (!preg_match("/^([a-f0-9]{8})-(([a-f0-9]{4})-){3}([a-f0-9]{12})$/i", $code)) {
            return false;
        }
        $u = base64_decode("aHR0cHM6Ly9hcGkuZW52YXRvLmNvbS92My9tYXJrZXQvYXV0aG9yL3NhbGU/Y29kZT0");
        $personalToken = $this->getCode();
        $userAgent = $_SERVER['HTTP_USER_AGENT'];
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => "$u{$code}",
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_HTTPHEADER => array(
                "Authorization: Bearer {$personalToken}",
                "User-Agent: {$userAgent}"
            ),
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        $d = json_decode($response);

        if ( isset($d->description) ) {
            $this->changeSetting('euser', '');
            $this->changeSetting('ecode', '');
            return false;
        } else {
            $this->changeSetting('euser', $d->buyer);
        }
        return true;
    }
    
    /**
     * Close the connection to the browser but continue processing the operation
     * @param $body
     */
    public function closeConnection($body, $responseCode)
    {
        // Cause we are clever and don't want the rest of the script to be bound by a timeout.
        // Set to zero so no time limit is imposed from here on out.
        set_time_limit((int)(Settings::$phpTimeOutLimit));
        // Client disconnect should NOT abort our script execution
        ignore_user_abort(true);
        // Clean (erase) the output buffer and turn off output buffering
        // in case there was anything up in there to begin with.
        if (ob_get_contents()) {
            ob_end_clean();
        }
        // Turn on output buffering, because ... we just turned it off ...
        // if it was on.
        if (!ob_start("ob_gzhandler")) {
            ob_start();
        }
        echo $body;
        // Return the length of the output buffer
        $size = ob_get_length();
        // send headers to tell the browser to close the connection
        // remember, the headers must be called prior to any actual
        // input being sent via our flush(es) below.
        header("Connection: close\r\n");
        header("Content-Encoding: none\r\n");
        header("Content-Length: $size");
        // Set the HTTP response code
        // this is only available in PHP 5.4.0 or greater
        http_response_code($responseCode);
        // Flush (send) the output buffer and turn off output buffering
        ob_end_flush();
        // Flush (send) the output buffer
        // This looks like overkill, but trust me. I know, you really don't need this
        // unless you do need it, in which case, you will be glad you had it!
        if( ob_get_level() > 0 ) ob_flush();
        // Flush system output buffer
        // I know, more over kill looking stuff, but this
        // Flushes the system write buffers of PHP and whatever backend PHP is using
        // (CGI, a web server, etc). This attempts to push current output all the way
        // to the browser with a few caveats.
        flush();
        // close current session
        if (session_id()) session_write_close();
        
        return;
    }
    
    /**
     * save to log file
     */
    public function saveLog($txt)
    {
        $file = fopen($this->fileLog, "a");
        fwrite($file, @date("Y-m-d H:i:s")." ".$txt);
        fclose($file);
    }

    /**
     * get current system EOL, because of interrupted email headers
     */
    public function getSystemEOL()
    {
        // Is the OS Windows or Mac or Linux
        if (strtoupper(substr(PHP_OS,0,3)=='WIN')) {
            $eol="\r\n";
        } elseif ( strtoupper(substr(PHP_OS,0,3)=='MAC')) {
            $eol="\r";
        } else {
            $eol="\n";
        }
        return $eol;
    }
}
