<?php

/*
  MailBeez Automatic Trigger Email Campaigns
  http://www.mailbeez.com

  Copyright (c) 2010, 2011, 2012 MailBeez

  inspired and in parts based on
  Copyright (c) 2003 osCommerce

  Released under the GNU General Public License

  v2.7.0
 */


///////////////////////////////////////////////////////////////////////////////
///																			 //
///                 MailBeez Core file - do not edit                         //
///                                                                          //
///////////////////////////////////////////////////////////////////////////////

require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/classes/mailbeez_editor_basic.php');
require_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'common/classes/mailbeez_template_codes_basic.php');
mh_define('MH_MAILERLOGFILE', MH_DIR_FS_LOGS . 'mailer_failed.log');


class mailbeez_mailer
{
    var $subject, $ga;
    var $filter;
    var $filter_loaded;
    var $mailbeez_editor;
    var $mailbeez_codes;

    function __construct($mailbeeObj, $initiate_editor = false)
    {
        $this->mailBee = $mailbeeObj; // current mailBee to work on
        $this->copySentCounter = 0;

        if ($initiate_editor) {
            // for previewing
            $this->mailbeez_editor = new mailbeez_editor();
            $this->mailbeez_editor->_register_editor_codes();
            $this->mailbeez_codes = new mailbeez_template_codes();
        }
    }

    function mailbeez_mailer($mailbeeObj, $initiate_editor = false)
    {
        self::__construct($mailbeeObj, $initiate_editor);
    }

    function sendBeez($mailbeez_module_path, $_iteration = 1, $mode = 'production')
    {


        if (!is_object($this->mailbeez_editor)) {
            $this->mailbeez_editor = new mailbeez_editor();
            $this->mailbeez_editor->_register_editor_codes();
            $this->mailbeez_codes = new mailbeez_template_codes();
        }

        $doCheck = true;
        if ($mode == 'test') {
            $doCheck = false;
        }
        $row = 0;
        $row_out = 0;

        $mailbeez_module = $this->get_module_name($mailbeez_module_path);

        // changed handling of iteration -> can be overwritten by resultset
        $iteration = $_iteration;

        $this->load_filter();

        foreach ($this->mailBee->audience as $key => $mail) {
            $timestamp_start = microtime(true);
            $row_out++;
            $order_id = 'none'; // using order id in templates
            $reference_id = 'none'; // for referencing in tracking

            if (isset($mail['order_id'])) {
                $order_id = $mail['order_id'];
            }

            if ($this->mailBee->orderid_is_reference) {
                if (isset($mail['reference_id'])) {
                    $reference_id = $mail['reference_id'];
                }
            } else {
                if (isset($mail['order_id'])) {
                    $reference_id = $mail['order_id'];
                }
            }

            $filter_result = null;


            $mail = $this->sanitize_data($mail); // clean up

            $mail_before = $mail;
            list($mail) = @mhpi('mailbeez_mailer_1', $mail, $this->mailBee);
            $this->checkMailData($mail, $mail_before, 'mailbeez_mailer_1');


            // set dynamic iteration if exists
            $iteration = isset($mail['_iteration']) ? $mail['_iteration'] : $iteration;
            $mail['iteration'] = $iteration;
            $this->mailBee->iteration = $iteration;

            // overwrite coupon_id_set if exists
            if (isset($mail['_coupon_id_set']) && (int)$mail['_coupon_id_set'] > 0) {
                $this->mailBee->coupon_id_set = $mail['_coupon_id_set'];
            }
            // overwrite coupon_expiry_days_set if exists
            if (isset($mail['_coupon_expire_days'])) {
                $this->mailBee->coupon_expire_days = $mail['_coupon_expire_days'];
            }
            $mail['module_iteration'] = $mailbeez_module . '::' . $mail['iteration'];

            $mail['list_unsubscribe_post'] = $this->buildBlockUrl($mail, $mailbeez_module_path);


            if ($doCheck == true) {
                $check_result = $this->late_check($mailbeez_module, $iteration, $mail['customers_id'], $reference_id, $mail, $mode, false);

                if ($check_result != false) {

                    $expectedLength = 9;
                    $default_value = false; // default value for padding
                    $check_result = array_pad($check_result, $expectedLength, $default_value);

                    list($check_result, $date_sent, $_result_iteration, $date_block, $filter_block, $valid_block, $filter_result, $bounce_block, $check_subscr) = $check_result;
                }
            }

            if (isset($filter_result['STOP']) && $filter_result['STOP'] == true) {
                echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . TEXT_EMAIL_FILTER_STOP;
                echo $filter_block;
                echo '</div>';
                $this->mailBee->update_process_lock();
                return $row;
            }

            if ($doCheck == true && !mailbeez::lock("$mailbeez_module#$iteration#" . $mail['customers_id'] . "#$reference_id#" . mh_cfg('MAILBEEZ_SIMULATION_ID'))) {
                echo '<div class="w"><a name="1">&nbsp;</a>' . $row .  ' locked: ' . mh_lng('TEXT_EMAIL_ALREADY_SEND');
                echo '</div>';

            } elseif($doCheck == true && $check_result == true) {
                // was already sent
                if ($date_sent != false) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_ALREADY_SEND');
                    echo $date_sent . ' ' . $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                } elseif ($date_block != false) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_BLOCKED');
                    echo $date_block . ' ' . $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                } elseif ($filter_block != false) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_FILTER_BLOCKED');
                    echo $filter_block . ' ' . $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                } elseif ($valid_block != false) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_VALID_BLOCKED');
                    echo $valid_block . ' ' . $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                } elseif ($bounce_block != false) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_BOUNCE_BLOCKED');
                    echo $bounce_block . ' ' . $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                } elseif ($check_subscr != false) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_SUBSCRIPTION_BLOCKED');
                    echo $bounce_block . ' ' . $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                }
                echo '</div>';
            } else {
                // send
                $row++;

                mh_free($smarty);

                $smarty = new mh_Smarty;
                $smarty->setCompileCheck(true);
                $smarty->compile_id = $this->mailBee->get_module_id();

                // some magic
                list($smarty, ,) = @mhpi('mailbeez_mailer_2', $smarty, $this, $mail);

                $mail_before = $mail;
                $mail = $this->mailBee->beforeFilter($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'beforeFilter');


                // add data
                $mail_before = $mail;
                $mail = $this->mailBee->beforeFilterData($mail, $mode);
                list($mail, $filter_result) = $this->process_data_filter($mailbeez_module_path, $iteration, $mail['customers_id'], $order_id, $mail, $mode);
                $this->checkMailData($mail, $mail_before, 'beforeFilterData');


                $mail_before = $mail;
                $mail = $this->mailBee->afterFilterData($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'afterFilterData');


                // insert content
                $mail_before = $mail;
                $mail = $this->mailBee->beforeFilterContent($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'beforeFilterContent');

                $mail_before = $mail;
                list($mail, $filter_result) = $this->process_content_filter($mailbeez_module_path, $iteration, $mail['customers_id'], $order_id, $mail, $mode);
                $mail = $this->mailBee->afterFilterContent($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'beforeFilterContent');


                // generate Email
                $mail_before = $mail;
                $mail = $this->mailBee->beforeGenerate($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'beforeGenerate');

                list($output_subject, $output_content_html, $output_content_txt, $output_preheader) = mh_smarty_generate_mail($this, $mail, $mailbeez_module_path, $smarty);
                $this->checkMailData($mail, $mail_before, 'mh_smarty_generate_mail', $output_content_html);


                $mail_before = $mail;
                $mail = $this->mailBee->afterGenerateMail($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'afterGenerateMail');

                // modifiy output
                $mail_before = $mail;
                $mail = $this->mailBee->beforeFilterModify($mail, $mode);
                list($output_subject, $output_content_html, $output_content_txt) = $this->process_modifier_filter($mailbeez_module_path, $iteration, $mail['customers_id'], $order_id, $output_subject, $output_content_html, $output_content_txt, $mode, $this, $mail);
                $this->checkMailData($mail, $mail_before, 'beforeFilterModify', $output_content_html);


                $mail_before = $mail;
                $mail = $this->mailBee->afterFilterModify($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'afterFilterModify');


                $mail_before = $mail;
                $mail = $this->mailBee->afterFilter($mail, $mode);
                $this->checkMailData($mail, $mail_before, 'afterFilter');

                //exit();
                // do things before sending

                $mail_before = $mail;
                if ((int)$this->mailBee->required_mb_version < 2 && (mh_cfg('MAILBEEZ_MAILHIVE_MODE') == 'production')) {
                    $this->mailBee->beforeSend($mail, $mode);
                } elseif ((int)$this->mailBee->required_mb_version >= 2) {
                    $mail = $this->mailBee->beforeSend($mail, $mode);
                }
                $this->checkMailData($mail, $mail_before, 'beforeSend');

                $output_content_html = mh_template_emogrify($output_content_html);
                $output_content_html = mh_template_outlook_helper($output_content_html);
                $this->checkMailData($mail, null, 'mh_template_outlook_helper', $output_content_html);


                $mail_before = $mail;
                list($mail, $filter_result_beforeSend) = $this->process_beforeSend_filter($this->mailBee, $iteration, $mail, $mode);
                list($output_subject, $output_content_html, $output_content_txt) = $this->mailBee->beforePerformSend($output_subject, $output_content_html, $output_content_txt, $mode);


                if (mh_arr_val($filter_result_beforeSend, 'STOP') == true) {
                    echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . TEXT_EMAIL_FILTER_STOP;
                    echo $filter_result_beforeSend['filter_name'];
                    echo '</div>';
                    $this->mailBee->update_process_lock();
                    return $row;
                }

                if (MAILBEEZ_SIMULATION == 'False' || $mode == 'test') {
                    // send "real" email to customer
                    $mail_meta = mh_sendEmail($mail, $mail['email_address'], $this->mailBee->sender_name, $this->mailBee->sender, $output_subject, $output_content_html, $output_content_txt);
                } else {
                    // send simulation
                    $output_subject = MAILBEEZ_SIMULATION_TAG . $output_subject;
                    $mail_meta = mh_sendEmail($mail, mh_cfg('MAILBEEZ_CONFIG_SIMULATION_EMAIL'), $this->mailBee->sender_name, $this->mailBee->sender, $output_subject, $output_content_html, $output_content_txt);
                }

                $mail['message_id'] = $mail_meta['message_id'];


                if ($mail_meta === false || (mh_arr_val($mail_meta, 'stop'))) {
                    // an error occurred in mh_sendEmail();

                } else {

                    if (mh_cfg('MAILBEEZ_MAILHIVE_RUN_SHOW_EMAIL') == 'True') {
                        echo $output_content_html;
                        echo "<hr style='opacity: 0.2;'>";
                    }


                    // do things after sending
                    if ((int)$this->mailBee->required_mb_version < 2 && (mh_cfg('MAILBEEZ_MAILHIVE_MODE') == 'production')) {
                        $this->mailBee->afterSend($mail, $mode);
                    } elseif ((int)$this->mailBee->required_mb_version >= 2) {
                        $this->mailBee->afterSend($mail, $mode);
                    }

                    $mail_before = $mail;
                    list($mail, $filter_result_afterSend) = $this->process_afterSend_filter($this->mailBee, $iteration, $mail, $mode);

                    if (($doCheck && (mh_cfg('MAILBEEZ_SIMULATION') == 'False')) ||
                        ($doCheck && (mh_cfg('MAILBEEZ_SIMULATION') == 'True' && mh_cfg('MAILBEEZ_CONFIG_SIMULATION_TRACKING') == 'True'))
                    ) {

                        $this->track($mailbeez_module, $iteration, $mail, $reference_id);

                        $this->mailBee->afterTrack($mail, $mode);
                    }

                    $time_generate = microtime(true) - $timestamp_start;

                    if ((mh_cfg('MAILBEEZ_MAILHIVE_COPY') == 'True' && mh_cfg('MAILBEEZ_SIMULATION') == 'False') ||
                        (mh_cfg('MAILBEEZ_CONFIG_SIMULATION_COPY') == 'True' && mh_cfg('MAILBEEZ_MAILHIVE_COPY') == 'True' && mh_cfg('MAILBEEZ_SIMULATION') == 'True')
                    ) {
                        // send copy
                        if ($this->copySentCounter < mh_cfg('MAILBEEZ_MAILHIVE_EMAIL_COPY_MAX_COUNT')) {

                            // modify copy email
                            // subject [COPY]
                            // remove tracking code
                            // disable archive

                            $mail_copy = $mail;
                            $mail_copy['message_id'] = -1;

                            mh_sendEmail($mail_copy, mh_cfg('MAILBEEZ_MAILHIVE_EMAIL_COPY'), $this->mailBee->sender_name, $this->mailBee->sender, '[COPY] ' . $output_subject, $output_content_html, $output_content_txt, true);
                            $this->copySentCounter++;
                        }
                    }
                    $time_sendmail = microtime(true) - $timestamp_start - $time_generate;
                }


                if ($mail['message_id'] > 0) {
                    echo '<div class="s"><a name="1">&nbsp;</a>' . $row . ' ' . ((mh_cfg('MAILBEEZ_SIMULATION') == 'False') ? ''
                            : MAILBEEZ_SIMULATION_TAG) . mh_lng('TEXT_EMAIL_SEND');
                    echo $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                    echo '<br>';
                    echo '&nbsp;Generate: ' . $this->_formatTime($time_generate) . ' | Send: ' . $this->_formatTime($time_sendmail) . ' | ';
                    echo 'Memory: ' . $this->_formatMemory(memory_get_usage(true)) . ' | ';
                    echo 'Peak: ' . $this->_formatMemory(memory_get_peak_usage(true));
                    echo '</div>';
                } elseif ($mail['message_id'] == -1) {
                    // todo
                    // $mail['error'] set in \mh_php_mail

                    echo '<div class="W"><a name="1">&nbsp;</a>' . $row . ' ' . ((mh_cfg('MAILBEEZ_SIMULATION') == 'False') ? ''
                            : MAILBEEZ_SIMULATION_TAG) . mh_lng('TEXT_EMAIL_SEND_FAILED');
                    echo $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                    echo '|Error:' . $mail_meta['error'];
                    echo '</div>';
                } elseif ($mail['message_id'] == -10) {
                    // todo
                    // $mail['error'] set in \mh_sendEmail

                    echo '<div class="W"><a name="1">&nbsp;</a>' . $row . ' ' . ((mh_cfg('MAILBEEZ_SIMULATION') == 'False') ? ''
                            : MAILBEEZ_SIMULATION_TAG) . mh_lng('TEXT_EMAIL_SEND_FAILED_MSG') . '' . $mail_meta['_error_msg'] . '<br>';
                    echo $mail['customers_id'] . ' ' . $mail['firstname'] . ' ' . $mail['lastname'] . ' ' . $mail['email_address'];
                    echo '</div>';
                }

                mh_free($mail);
                mh_free($mail_before);
            }

            $this->mailBee->update_process_lock();

            if (($row_out % 100) == 0) {
                echo '<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">  scrolldown(); </SCRIPT>';
                echo str_repeat(" ", 4096); // force a flush
                ob_flush();
                flush();
            }

            if (isset($filter_result_afterSend) && mh_arr_val($filter_result_afterSend, 'STOP')) {
                echo '<div class="w"><a name="1">&nbsp;</a>' . $row . ' ' . mh_lng('TEXT_EMAIL_FILTER_STOP');
                echo $filter_result_afterSend['filter_name'];
                echo '</div>';
                $this->mailBee->update_process_lock();
                return $row;
            }

            if (isset($mail_meta) && mh_arr_val($mail_meta, 'stop')) {
                return false;
            }
        }
        return $row;
    }

    private function _formatTime($pv)
    {
        return (number_format($pv, 3)) * 1000 . 'ms';
    }

    private function _formatMemory($m)
    {
        return number_format(intval($m) / (1024 * 1024), 2, '.', '') . 'Mb';
    }

    function track($mailbeez_module, $iteration = 1, $mail = [], $reference_id = 0)
    {

        // TABLE_MAILBEEZ_TRACKING
        $channel = (isset($mail['channel'])) ? $mail['channel'] : 'DEFAULT';
        $customers_id = $mail['customers_id'];

        $customers_email = $mail['email_address'];
        $ref_id = ($reference_id == 'none') ? 0 : (int)$reference_id;
        $message_id = $mail['message_id'];

        // return code given in mailhive/common/functions/email_engine_php_mailer.php
        // for bounces through mailbeez.email
        // do not track
//        if ($message_id == -42) {
//            return false;
//        }


        $sql_data_array = array('module' => $mailbeez_module,
            'date_sent' => 'now()',
            'iteration' => (int)$iteration,
            'customers_id' => $customers_id,
            'customers_email' => $customers_email,
            'orders_id' => $ref_id,
            'channel' => $channel,
            'simulation' => mh_cfg('MAILBEEZ_SIMULATION_ID'),
            'batch_id' => mh_cfg('MAILBBEEZ_EVENTLOG_BATCH_ID'),
            'message_id' => $message_id
        );

        list($sql_data_array,) = @mhpi('mailbeez_mailer_3', $sql_data_array, $mail);


        return mh_db_perform(TABLE_MAILBEEZ_TRACKING, $sql_data_array);
    }

    function block($mailbeez_module, $customers_id, $email_address, $source = 0, $docheck = true, $mode = 'prod', $behaviour = 'Global')
    {
        // TABLE_MAILBEEZ_BLOCK
        // block module for customer
        // check if combination of customer_id and email_address is valid

        $check_result = true;
        if ($docheck) {
            $check_result = $this->check_track($mailbeez_module, false, $customers_id);
        }

        if ($behaviour == 'Global') {
            // nicetohavetodo
            // implement global block
            // currently check_block works depending on configuration setting
            // and
        }

        if ($check_result) {
            // this customer has received an email
            if (!$this->check_block($mailbeez_module, $customers_id)) {

                // not yet blocked
                $sql_data_array = array('module' => $mailbeez_module,
                    'date_block' => 'now()',
                    'customers_id' => $customers_id,
                    'source' => $source,
                    'simulation' => ($mode == 'prod' || $mode == '') ? 0 : 1);

                mh_db_perform(TABLE_MAILBEEZ_BLOCK, $sql_data_array);
                return 'ok';
            }
            return '-1';
        }
        return 'failed';
    }

    function unblock($mailbeez_module, $customers_id, $email_address, $source = 0, $docheck = false, $mode = null, $behaviour = null)
    {
        // TABLE_MAILBEEZ_BLOCK
        // block module for customer
        // check if combination of customer_id and email_adress is valid
        $check_result = true;
        if ($docheck) {
            $check_result = $this->check_track($mailbeez_module, false, $customers_id);
        }

        if ($behaviour == 'Global') {
            // nicetohavetodo
            // implement global unblock
            // currently check_block works depending on configuration setting
            // and
        }

        if ($check_result) {
            // this customer has received an email
            if ($this->check_block($mailbeez_module, $customers_id)) {
                mh_db_query("DELETE FROM " . TABLE_MAILBEEZ_BLOCK . "
                             WHERE module = '" . $mailbeez_module . "'
                                AND customers_id = '" . $customers_id . "'");
                return 'ok';
            }
            return '-1';
        }
        return 'failed';
    }


    function check_last($customers_id)
    {
        return false;
    }

    function check_track($mailbeez_module, $iteration = '', $customers_id = 0, $order_id = 'none')
    {
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_check_track_start');
        $sql = '';
        if ($order_id != 'none') {
            // check for orders_id (e.g. when blocking)
            $sql .= " and orders_id='" . $order_id . "' ";
        }

        if ($iteration != '') {
            // check for iteration ( e.g. when sending)
            $sql .= " and iteration='" . $iteration . "' ";
        }

        // V2.7.6 added SQL_NO_CACHE
        $check_query_raw = "SELECT SQL_NO_CACHE date_sent, iteration
					        FROM " . TABLE_MAILBEEZ_TRACKING . "
    					WHERE module='" . $mailbeez_module . "'
							" . $sql . "
							" . MAILBEEZ_SIMULATION_SQL . "
							AND customers_id='" . $customers_id . "'
						ORDER BY date_sent DESC";

        $check_query = mh_db_query($check_query_raw);

        if (mh_db_num_rows($check_query) > 0) {
            $check = mh_db_fetch_array($check_query);
            $return = array($check['date_sent'], $check['iteration']);
            // does something crazy!!!!
            //mh_free($check_query);// free memory
        } else {
            $return = array(false, false);
        }
        $request_profiler->restart('mailbeez_mailer_check_track_end');


        return $return;
    }

    // V2.6
    // check does no longer check for mode
    // also sim-blocks are valid in production mode

    function check_block($mailbeez_module, $customers_id)
    {
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_check_block_start');

        $cache_key = 'cache_check_block_' . "$mailbeez_module#$customers_id";

        if (isset($GLOBALS[$cache_key]) && mh_cfg('MAILBEEZ_CHECK_CACHE')) {
            $cache_value = $GLOBALS[$cache_key];
            $request_profiler->restart('mailbeez_mailer_check_block_end_cached');
            return $cache_value;
        }

        // $this->mailBee might not be assigned correctly...
        // constructor might assign empty array to $this->mailBeez, e.g. in magic_14
//        if ($this->mailBee->noblock) {
//            return false;
//        }

        if (isset($GLOBALS[$mailbeez_module]) && $GLOBALS[$mailbeez_module]->noblock) {
            return false;
        }


        // TABLE_MAILBEEZ_BLOCK
        $sql = '';
        if (mh_cfg('MAILBEEZ_CONFIG_OPTOUT_BEHAVIOUR') == 'Global') {
            $sql = '';
        } else {
            $sql = " ( module='" . $mailbeez_module . "' or module='ALL' ) and ";
        }
        $check_query_sql = "SELECT date_block
                                FROM " . TABLE_MAILBEEZ_BLOCK . "
                            WHERE " . $sql . " customers_id='" . $customers_id . "'
                            ORDER BY date_block DESC";

        $check_query = mh_db_query($check_query_sql);

        $check_block_result = false;
        if (mh_db_num_rows($check_query) > 0) {
            $check = mh_db_fetch_array($check_query);
            $check_block_result = $check['date_block'];
            // does something crazy!!
            //mh_free($check_query);// free memory
        }
        if (mh_cfg('MAILBEEZ_CHECK_CACHE')) {
            $GLOBALS[$cache_key] = $check_block_result;
        }
        $request_profiler->restart('mailbeez_mailer_check_block_end');


        return $check_block_result;
    }


    // mailbeez v2.6

    function check_subscription($mailbeez_module, $customers_id)
    {
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_check_subscription_start');
        // use Spam Compliance Framework if available
        if (mh_cfg('MAILBEEZ_CONFIG_SPAMCOMPLIANCE_ADVANCED_STATUS') == 'True') {
            require_once(mh_cfg('MH_DIR_CONFIG') . 'config_spamcompliance_advanced.php');
            $return = config_spamcompliance_advanced::check_subscription($mailbeez_module, $customers_id);
        } elseif (mh_cfg('MAILBEEZ_CONFIG_CHECK_SUBSCRIPTION') == 'True') {
            if ($this->mailBee->nochk) {
                $return = false;
            } else {
                $check_query_sql = "SELECT customers_email_address
                                            FROM " . TABLE_CUSTOMERS . "
                                            WHERE customers_id = '" . $customers_id . "' AND customers_newsletter = '1'";

                $check_query = mh_db_query($check_query_sql);
                if (mh_db_num_rows($check_query) > 0) {
                    $return = false;
                    // does something crazy!
                    //mh_free($check_query);// free memory
                } else {
                    $return = true;
                }
            }
        } else {
            $return = false;
        }

        $request_profiler->restart('mailbeez_mailer_check_subscription_end');
        return $return;
    }

    function load_filter()
    {
        if (mh_cfg('MAILBEEZ_FILTER_INSTALLED')) {
            if (!$this->filter_loaded) {
                $filter_modules = explode(';', mh_cfg('MAILBEEZ_FILTER_INSTALLED'));

                if (is_array($filter_modules)) {
                    foreach ($filter_modules as $filterbee) {
                        $class = substr($filterbee, 0, strrpos($filterbee, '.'));
                        if ($class == '') {
                            continue;
                        }
                        $class_name = mh_get_class_name($class);
                        if (!isset($GLOBALS[$class]) || !is_object($GLOBALS[$class])) {
                            if (file_exists(mh_cfg('MH_DIR_FS_CATALOG') . mh_cfg('MH_ROOT_PATH') . 'filterbeez/' . $filterbee)) {
                                include_once(mh_cfg('MH_DIR_FS_CATALOG') . mh_cfg('MH_ROOT_PATH') . 'filterbeez/' . $filterbee);
                                $GLOBALS[$class] = new $class_name; // register filter
                            }
                        }
                        if (isset($GLOBALS[$class]) && is_object($GLOBALS[$class])) {
                            $this->filter[] = $class; // register filter
                        }
                    }

                }
            }
        } else {
            $this->filter = array();
//            $this->filter = false;
        }
        if (!$this->filter_loaded) {
            $this->filter_loaded = true;
        }
    }

    function process_data_filter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode)
    {
        $mail_backup = $mail;
        $result = null;

        // run through active data filters
        if (is_array($this->filter)) {

            reset($this->filter);
            foreach ($this->filter as $filterClass) {
//        while (list(, $filterClass) = each($this->filter)) {
                if ($GLOBALS[$filterClass]->enabled && $GLOBALS[$filterClass]->filter_type == 'data') {
                    if ($mode == 'test' && !$GLOBALS[$filterClass]->process_preview) {
                        continue;
                    }
                    list($mail, $result) = $GLOBALS[$filterClass]->processFilter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode);
                }
            }
        }
        if (!is_array($mail)) {
            // something went wrong, avoid breaking the system
            $mail = $mail_backup;
        }

        return array($mail, $result);
    }

    function process_content_filter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode)
    {
        $mail_backup = $mail;
        $result = null;
        // run through active data filters
        if (is_array($this->filter)) {
            reset($this->filter);
            foreach ($this->filter as $filterClass) {

//        while (list(, $filterClass) = each($this->filter)) {
                if ($GLOBALS[$filterClass]->enabled && $GLOBALS[$filterClass]->filter_type == 'content') {
                    if ($mode == 'test' && !$GLOBALS[$filterClass]->process_preview) {
                        continue;
                    }

                    list($mail, $result) = $GLOBALS[$filterClass]->processFilter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode);
                }
            }
        }
        if (!is_array($mail)) {
            // something went wrong, avoid breaking the system
            $mail = $mail_backup;
        }

        return array($mail, $result);
    }

    // issues:
    // filter like filter_check_block_all
    // do not respect module setting nochk


    function process_check_filter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode)
    {
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_check_process_check_filter_start');
        $this->load_filter();
// run through active check filters
        if (!isset($mail['bypass_process_check_filter'])) {
            if (is_array($this->filter)) {
                reset($this->filter);
                foreach ($this->filter as $filterClass) {
                    if ($GLOBALS[$filterClass]->enabled && $GLOBALS[$filterClass]->filter_type == 'check') {
                        $request_profiler->restart('mailbeez_mailer_check_process_check_filter_process_start ' . $filterClass);
                        $filter_result = $GLOBALS[$filterClass]->processFilter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode);
                        $request_profiler->restart('mailbeez_mailer_check_process_check_filter_process_end ' . $filterClass);
                        if ($filter_result != false) {
                            $request_profiler->restart('mailbeez_mailer_check_process_check_filter_return ' . $filterClass);
                            return $filter_result;
                        }
                    }
                }
            }
        }
        $request_profiler->restart('mailbeez_mailer_check_process_check_filter_end');
        return [false, false];
    }

    // added $mailbeez_obj, $mail
    // 01.11.2011 - 2.5A

    function process_modifier_filter($mailbeez_module, $iteration, $customers_id, $order_id, $output_subject, $output_content_html, $output_content_txt, $mode, $mailbeez_obj, $mail)
    {
        $this->load_filter();
        // run through active modifier filters
        if (is_array($this->filter)) {
            reset($this->filter);
            foreach ($this->filter as $filterClass) {
                if ($GLOBALS[$filterClass]->enabled && $GLOBALS[$filterClass]->filter_type == 'modifier') {
                    list($output_subject, $output_content_html, $output_content_txt) = $GLOBALS[$filterClass]->processFilter($mailbeez_module, $iteration, $customers_id, $order_id, $output_subject, $output_content_html, $output_content_txt, $mode, $mailbeez_obj, $mail);
                }
            }
        }
        return array($output_subject, $output_content_html, $output_content_txt);
    }

    function process_beforeSend_filter($mailbeez_obj, $iteration, $mail, $mode)
    {
        $mail_backup = $mail;
        $this->load_filter();
        $result = null;
        // run through active filters
        if (is_array($this->filter)) {
            reset($this->filter);
            foreach ($this->filter as $filterClass) {
                if ($GLOBALS[$filterClass]->enabled && $GLOBALS[$filterClass]->filter_type == 'beforeSend') {
                    $result = $GLOBALS[$filterClass]->processFilter($mailbeez_obj, $iteration, $mail, $mode);
                }
            }
        }
        if (!is_array($mail)) {
            // something went wrong, avoid breaking the system
            $mail = $mail_backup;
        }
        return array($mail, $result);
    }

    function process_afterSend_filter($mailbeez_obj, $iteration, $mail, $mode)
    {
        $mail_backup = $mail;
        $result = null;
        $this->load_filter();
        // run through active filters
        if (is_array($this->filter)) {
            reset($this->filter);

            foreach ($this->filter as $filterClass) {
//        while (list(, $filterClass) = each($this->filter)) {
                if ($GLOBALS[$filterClass]->enabled && $GLOBALS[$filterClass]->filter_type == 'afterSend') {
                    $result = $GLOBALS[$filterClass]->processFilter($mailbeez_obj, $iteration, $mail, $mode);
                }
            }
        }
        if (!is_array($mail)) {
            // something went wrong, avoid breaking the system
            $mail = $mail_backup;
        }
        return array($mail, $result);
    }

    function check_valid($mailbeez_module, $iteration, $customers_id, $order_id, $mail)
    {
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_check_valid_start');
        // check if data is valid
        if (!is_array($mail)) {
            $return = false;
        } elseif ($mail['email_address'] == '' || is_null($mail['email_address']) || !stristr($mail['email_address'], '@')) {
            $return = 'email_address empty - data not valid for sending';
        } elseif (function_exists('filter_var')) { // PHP 4 compatibility
            if (!filter_var($mail['email_address'], FILTER_VALIDATE_EMAIL)) {
                $return = 'email_address invalid - data not valid for sending';
            } else {
                $return = false;
            }
        } elseif (!$this->isValidEmail($mail['email_address'])) {
            $return = 'email_address invalid - data not valid for sending';
        }

        // v2.7.6
        // fixed logic
        if (!$return && isset($mail['firstname']) && isset($mail['lastname'])) {
            if (($mail['firstname'] == '' && $mail['lastname'] == '') || (is_null($mail['firstname']) && is_null($mail['lastname']))) {
                $return = 'both firstname and lastname empty - data not valid for sending';
            } else {
                $return = false;
            }
        }

        $request_profiler->restart('mailbeez_mailer_check_valid_end');
        return $return;
    }


    function check_bounce($customers_id, $mail)
    {
        // Check if there is a hard bounce
        // or soft bounce within the last x days.
        // get the latest bounce date
        // in case of a converted softbounces that will be the hardbounce date
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_bounce_start');
        $return = false;

        $softdays = (('mlbz_ubvx' == mh_cfg('MAILBEEZ_CONFIG_EMAIL_ENGINE')) || ('mlbz_hysndr' == mh_cfg('MAILBEEZ_CONFIG_EMAIL_ENGINE'))  )? mh_cfg('MAILBEEZ_MLBZ_BOUNCE_SOFT_DAYS') : mh_cfg('MAILBEEZ_BOUNCEHIVE_SOFT_DAYS');


        if (isset($mail['email_address'])) {
            $sql_query_raw = 'SELECT bounce_type, date_bounce
                        FROM ' . TABLE_MAILBEEZ_BOUNCE . '
                        WHERE customers_id = "' . $customers_id . '"
                        AND customers_email = "' . $mail['email_address'] . '"
                        AND (
                            bounce_type = "H"
                        OR
                          ( bounce_type = "S"
                            AND date_bounce > ' . $this->dbdate($softdays) . ')
                        )
                        ORDER BY date_bounce DESC
                        ';
            $check_query = mh_db_query($sql_query_raw);
            if (mh_db_num_rows($check_query) > 0) {
                $check = mh_db_fetch_array($check_query);
                $return = $check['date_bounce'];
            }
        }
        // does something crazy!?!?!
        //mh_free($check_query);// free memory

        $request_profiler->restart('mailbeez_mailer_bounce_end');
        return $return;
    }

    function check($mailbeez_module, $iteration, $customers_id, $order_id = 'none', $mail = '', $mode = '', $called_by_filter = false)
    {
        global $request_profiler;
        $request_profiler->restart('mailbeez_mailer_check_start');

        $cache_key = 'cache_check_' . "$mailbeez_module#$iteration#$customers_id#$order_id";

        // issue
        // sending process might run long time, initial check result is cached, but must be invalid

        if ($mailbeez_module != 'mb_newsletter') {

            if (isset($GLOBALS[$cache_key]) && mh_cfg('MAILBEEZ_CHECK_CACHE')) {
                $cache_value = $GLOBALS[$cache_key];
                return $cache_value;
            }
        }

        if (!is_array($mail) || !isset($mail['email_address'])) {

            if (!is_array($mail)) {
                $mail = array();
                $mail['email_address'] = null;
            }
            // email_address is required for some filters, make sure it exists (backwards compatiblity)
            // modules should give that information
            $email_query_sql = "SELECT customers_email_address AS email_address
                                FROM " . TABLE_CUSTOMERS . "
                                WHERE customers_id = '" . $customers_id . "'";
            $email_query = mh_db_query($email_query_sql);
            if (mh_db_num_rows($email_query) > 0) {
                $email_query_result = mh_db_fetch_array($email_query);
                $mail['email_address'] = $email_query_result['email_address'];
            }
            // does something crazy!?!?!
            // mh_free($email_query);
        }


        if (!$this->mailBee->noblock) {

            // compatibility filter_check_block_all.php early version which calls "check" instead of "check_block"
            if ($mailbeez_module == 'ALL') {
                $check_result_array = $this->check_block($mailbeez_module, $customers_id);
                if (mh_cfg('MAILBEEZ_CHECK_CACHE')) {
                    $GLOBALS[$cache_key] = $check_result_array;
                }
                $request_profiler->restart('mailbeez_mailer_check_end_cached');
                return $check_result_array;
            }
        }

        if (mh_cfg('MAILBEEZ_CHECK_CACHE')) {
            $GLOBALS[$cache_key] = false;
        }

        $filter_result = false;
        $filter_block = false;
        $global_pattern_block = false;

        // exclude special email addresses
        $exclude_domains_array = [
            '@marketplace.amazon',
            '@members.ebay',
            '@newmail.de',
            '@post.meinpaket.de',
            '@dawanda.com',
            '@allyouneed',
            '@checkout.idealo.de',
            '@customer.otto.market',
            '@kaufland',
            '@moebel.check24.de',
            '@b.metro-marketplace.eu',
            '@hood.de',
            '@shoepping.at'
        ];

        foreach ($exclude_domains_array as $exclude_domain) {
            $exclude_domain = trim($exclude_domain);
            if (preg_match("/" . $exclude_domain . "/", $mail['email_address']) > 0) {
                $filter_block = 'global_pattern_block';
                $global_pattern_block = 'global_pattern_block';
            }
        }

        // check 1: already sent?
        list($date_sent, $iteration_result) = $this->check_track($mailbeez_module, $iteration, $customers_id, $order_id);

        // check 2: blocked?
//        if (!$date_sent && !$global_pattern_block) {
        // fix: missing blocked data in list_segmentation_export
        if (!$global_pattern_block && !$this->mailBee->noblock) {
            $date_block = $this->check_block($mailbeez_module, $customers_id);
        } else {
            $date_block = false;
        }

        // check 3: filter?
        if (!$date_sent && !$date_block && !$global_pattern_block && is_array($mail)) {
            $result = $this->process_check_filter($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode);
            list($filter_block, $filter_result) = array_pad((array)$result, 2, null);
        }


        // check 4: valid?
        if (!$date_sent && !$date_block && !$filter_block && is_array($mail)) {
            $valid_block = $this->check_valid($mailbeez_module, $iteration, $customers_id, $order_id, $mail);
        } else {
            $valid_block = false;
        }


        // check 5: subscriber?
        if (!$date_sent && !$date_block && !$filter_block && !$valid_block) {
            $check_subscr = $this->check_subscription($mailbeez_module, $customers_id);
        } else {
            $check_subscr = false;
        }

        // check 6: bounce?
        if (!$date_sent && !$date_block && !$filter_block && !$valid_block && !$check_subscr && is_array($mail)) {
            $bounce_block = $this->check_bounce($customers_id, $mail);
        } else {
            $bounce_block = false;
        }

        $check_result = false;
        if ($date_sent || $date_block || $filter_block || $valid_block || $bounce_block || $check_subscr) {
            $check_result = true; // no email to this customer
            $check_result_array = array($check_result, $date_sent, $iteration_result, $date_block, $filter_block, $valid_block, $filter_result, $bounce_block, $check_subscr);
            if (mh_cfg('MAILBEEZ_CHECK_CACHE')) {
                $GLOBALS[$cache_key] = $check_result_array;
            }
            $return = $check_result_array;
        } else {
            $return = false;
        }
        $request_profiler->restart('mailbeez_mailer_check_end');
        return $return;
    }

    // added $order_id
    // 03.10.2011 - 2.5A
    // added $mail
    // 15.11.2012 - 2.7A
    function early_check($module, $iteration, $customers_id, $order_id = 'none', $mail = '')
    {
        // early check enabled.
        if (mh_cfg('MAILBEEZ_MAILHIVE_EARLY_CHECK_ENABLED') == 'True') {
            $chk_result = $this->check($module, $iteration, $customers_id, $order_id, $mail);
            return $chk_result;
        }
        return false;
    }

    function late_check($mailbeez_module, $iteration, $customers_id, $order_id = 'none', $mail = '', $mode = '', $called_by_filter = false)
    {
        if ($mailbeez_module == 'mb_newsletter') {
            return $this->check_track($mailbeez_module, $iteration, $customers_id, $order_id);
        }

        return $this->check($mailbeez_module, $iteration, $customers_id, $order_id, $mail, $mode, $called_by_filter);
    }


    // V2.6: make mode aware
    function buildBlockUrl($mail, $module_path)
    {
        $mode = 'prod';
        if (mh_cfg('MAILBEEZ_SIMULATION') == 'True') {
            $mode = MAILBEEZ_SIMULATION_ID;
        }

        $behaviour = mh_cfg('MAILBEEZ_CONFIG_OPTOUT_BEHAVIOUR');

        $block_token = base64_encode($mail['customers_id'] . '|' . $mail['email_address'] . '|' . $mode . '|' . $behaviour);

        //might run through URL rewrite
        //$block_url = mh_href_email_link(FILENAME_HIVE, 'ma=block&m=' . $module . '&mp=' . $block_token , 'NONSSL', false);
        // plain url

        $block_url = MAILBEEZ_MAILHIVE_URL_DIRECT . '?ma=block&m=' . $this->get_module_name($module_path) . '&mp=' . $block_token;
        return $block_url;
    }

    // not used?
    function buildUnBlockUrl($mail, $module_path)
    {
        $block_token = base64_encode($mail['customers_id'] . '|' . $mail['email_address']);
        $block_url = MAILBEEZ_MAILHIVE_URL_DIRECT . '?ma=unblock&m=' . $this->get_module_name($module_path) . '&mp=' . $block_token;
        return $block_url;
    }

    function dbdate($day)
    {
        $rawtime = strtotime("-" . $day . " days");
        $ndate = date("Ymd", $rawtime);
        return $ndate;
    }


    function get_module_name($module_path)
    {
        return mh_get_module_name($module_path);
    }

    function isValidEmail($email)
    {
        return preg_match("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$^", $email);
    }

    function checkMailData($mail, $mail_before = null, $filter = null, $content = 'default')
    {
        $invalid = false;

        if (!$mail) {
            $invalid = true;
        } elseif (!sizeof($mail)) {
            $invalid = true;
        } elseif ($mail_before && (sizeof($mail) < sizeof($mail_before))) {
            $invalid = true;
        } elseif (!trim($content)) {
            $invalid = true;
        }

        if ($invalid) {
            $msg = "*****\n";
            $msg .= ($filter) ? ' filter ' . $filter . ' ' : "";
            $msg .= "Module:" . $this->mailBee->get_module_id();
            $msg .= "\n";
            $msg .= "invalid data:";
            $msg .= "\n";
            $msg .= '$mail ' . sizeof($mail);
//            $msg .= '$mail: ' . var_export($mail, true);
            $msg .= ($content) ? '$content: ' . $content . "\n" : '';
            $this->mailer_error_log($msg);
        }

    }


    public static function sanitize_data($mail)
    {
        $fields = array('firstname', 'lastname');
        foreach ($fields as $f) {
            $mail[$f] = mailbeez_mailer::sanitize_data_field($mail[$f]);
        }

        // {} are valid email address chars https://en.wikipedia.org/wiki/Email_address#Local-part
        // but break smarty
        $mail['email_address'] = str_replace(array('{', '}'), array('&#123;', '&#125;'), $mail['email_address']);

        return $mail;
    }


    public static function sanitize_data_field($field)
    {
        $san_field = str_replace(array('<', '&lt;', '>', '&gt;'), array(), $field);
        return $san_field;
    }

    function mailer_error_log($msg)
    {
        $filename = MH_MAILERLOGFILE;
        $stream = fopen($filename, 'a');
        $string = "[" . date("Y/m/d h:i:s", time()) . "] " . $msg;
        fwrite($stream, $string . PHP_EOL);
        fclose($stream);
    }

}
