<?php

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

  Copyright (c) 2010 - 2015 MailBeez

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

  Released under the GNU General Public License (Version 2)
  [http://www.gnu.org/licenses/gpl-2.0.html]

 */


if (!function_exists('mh_cfg')) {
    function mh_cfg($c)
    {
        if (defined($c)) {
            return constant($c);
        }
        return $c;
    }
}

class Cloudloader extends CloudloaderBase
{
    /**
     * @var InstallerRewrite Configuration rewriter object.
     */
    protected $rewriter;

    /**
     * @var string Application base path.
     */

    protected $baseDirectory;

    /**
     * @var string A temporary working directory.
     */
    protected $tempDirectory;

    /**
     * @var string A temporary working directory.
     */
    protected $unzipDirectory;

//    protected $deployDirectory = '../mailhive/';

    public $deployDirectory;

    /**
     * @var string Backup target directory.
     */
    public $backupDirectory;

    /**
     * @var string Glob pattern used to locate the mailhive payload inside an archive.
     */
    public $glob_pattern;

    /**
     * @var array Files that must not be overwritten on a core update.
     */
    public $exclude_overwrite = array();

    /**
     * @var array Files that must not be overwritten on a package update.
     */
    public $exclude_overwrite_package = array();

    /**
     * @var string Absolute path to the install log file.
     */
    public $logFile;

    /**
     * @var string Backup archive file name.
     */
    public $backup_file;

    /**
     * @var string Cloudbeez API key.
     */
    public $apikey;

    /**
     * @var mixed Framework application instance (lazy, optional).
     */
    public $app;


    /**
     * Constructor/Router
     */
    public function __construct()
    {

        /*
         * Establish directory paths
         */
        $this->baseDirectory = PATH_INSTALL;
        $this->deployDirectory = PATH_INSTALL . '/../';
        $this->tempDirectory = PATH_INSTALL . '/cloudloader/temp'; // @todo Use sys_get_temp_dir()
        $this->unzipDirectory = PATH_INSTALL . '/cloudloader/work';
        $this->backupDirectory = PATH_INSTALL . '/backup';
        $this->glob_pattern = '*/catalog/mailhive';
        $this->exclude_overwrite = array();
        $this->exclude_overwrite_package = array();


        $this->logFile = PATH_INSTALL . '/cloudloader/install.log';

        // some servers do not allow to create a zip-file on root level
        $this->backup_file = ($this->readSessionVar('mailbeez_installer_backup_location')) ? $this->readSessionVar('mailbeez_installer_backup_location') : '/mailhive' . date("Ymd-His") . '.zip';

        $this->apikey = mh_cfg('CLOUDLOADER_API_KEY');
    }

    public function run()
    {
        $this->writeSessionVar('mailbeez_installer_backup_location', $this->backup_file);
        $this->writeSessionVar('mailbeez_installer_backup_location_dir', $this->backupDirectory . $this->backup_file);


        if (!is_null($handler = $this->post('handler'))) {
            if (!strlen($handler)) exit;
//            $this->log('SESSION: %s', print_r($_SESSION, true));

            try {
                $this->log('Execute AJAX handler: %s', $handler);

                if (!preg_match('/^on[A-Z]{1}[\w+]*$/', $handler))
                    throw new Exception(sprintf('Invalid handler: %s', $handler));

                if (method_exists($this, $handler) && ($result = $this->$handler()) !== null) {
                    header('Content-Type: application/json');
                    die(json_encode($result));
                }
            } catch (Exception $ex) {
                header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
                $this->log('Handler error (%s): %s', $handler, $ex->getMessage());
                $this->log(array('Trace log:', '%s'), $ex->getTraceAsString());

                die($ex->getMessage());
            }

            exit;
        }

    }

    protected function onCheckRequirement()
    {
        $checkCode = $this->post('code');
        $this->log('System check: %s', $checkCode);

        $result = false;
        switch ($checkCode) {
            case 'liveConnection':
                $check = $this->requestServerData('ping', '', 'public');
                $result = (is_array($check) && $check['result']);
                break;
            case 'liveConnectionSpeed':
                $check = $this->serverConnectionSpeedTest();
                $result = (is_array($check) && $check['result']);
                break;
            case 'liveConnectionPrivate':
                $check = $this->requestServerData('ping', '', 'private');
                $result = (is_array($check) && $check['result']);
                break;
            case 'liveConnectionPrivateSpeed':
                $check = $this->serverConnectionSpeedTest();
                $result = (is_array($check) && $check['result']);
                break;
            case 'writePermission':
                $result = (is_writable(PATH_INSTALL)
                    && is_writable($this->tempDirectory)
                    && is_writable($this->unzipDirectory)
                    && is_writable($this->backupDirectory));
                break;
            case 'phpVersion':
                $php_min = defined('CLOUDBEEZ_MAILBEEZ_INSTALLER_PHP_MIN') ? CLOUDBEEZ_MAILBEEZ_INSTALLER_PHP_MIN : '7.4';
                $php_max_lt = defined('CLOUDBEEZ_MAILBEEZ_INSTALLER_PHP_MAX_LT') ? CLOUDBEEZ_MAILBEEZ_INSTALLER_PHP_MAX_LT : '8.5';
                $result = version_compare(PHP_VERSION, $php_min, '>=')
                    && version_compare(PHP_VERSION, $php_max_lt, '<');
                break;
            case 'safeMode':
                $result = !ini_get('safe_mode');
                break;
            case 'pdoLibrary':
                $result = defined('PDO::ATTR_DRIVER_NAME');
                break;
            case 'mcryptLibrary':
                $result = extension_loaded('mcrypt');
                break;
            case 'gdLibrary':
                $result = extension_loaded('gd');
                break;
            case 'curlLibrary':
                $result = function_exists('curl_init');
                break;
            case 'zipLibrary':
                $result = class_exists('ZipArchive');
                break;
        }

        $this->log('Requirement %s %s', $checkCode, ($result ? '+OK' : '=FAIL'));
        return array('result' => $result);
    }

    protected function onValidateAdvancedConfig()
    {
//        if (!strlen($this->post('encryption_code')))
//            throw new CloudloaderException('Please specify encryption key', 'encryption_code');

//        if (strlen($this->post('encryption_code')) < 6)
//            throw new CloudloaderException('The encryption key should be at least 6 characters in length.', 'encryption_code');

        if (!strlen($this->post('folder_mask')))
            throw new CloudloaderException('Please specify folder permission mask', 'folder_mask');

        if (!strlen($this->post('file_mask')))
            throw new CloudloaderException('Please specify file permission mask', 'file_mask');

        if (!preg_match("/^[0-9]{3}$/", $this->post('folder_mask')) || $this->post('folder_mask') > 777)
            throw new CloudloaderException('Please specify a valid folder permission mask', 'folder_mask');

        if (!preg_match("/^[0-9]{3}$/", $this->post('file_mask')) || $this->post('file_mask') > 777)
            throw new CloudloaderException('Please specify a valid file permission mask', 'file_mask');
    }

    protected function onGetPopularPlugins()
    {
        return $this->requestServerData('plugin/popular');
    }

    protected function onGetPopularThemes()
    {
        return $this->requestServerData('theme/popular');
    }

    protected function onSearchPlugins()
    {
        return $this->requestServerData('plugin/search', array('query' => $this->post('query')));
    }

    protected function onSearchThemes()
    {
        return $this->requestServerData('theme/search', array('query' => $this->post('query')));
    }

    protected function onPluginDetails()
    {
        return $this->requestServerData('plugin/detail', array('name' => $this->post('name')));
    }

    protected function onThemeDetails()
    {
        return $this->requestServerData('theme/detail', array('name' => $this->post('name')));
    }

    protected function onProjectDetails()
    {
        return $this->requestServerData('project/detail', array('id' => $this->post('code')));
    }

    protected function onInstallStep()
    {
        $installStep = $this->post('step');
        $this->log('Install step: %s', $installStep);
        $result = false;

        switch ($installStep) {
            case 'getMetaDataCore':
                $result = $this->requestServerData('core/install', '', 'public');
                $this->log('getMetaDataCore:' . print_r($result, true));
                if (!$result) {
                    throw new Exception('Unable to get core information');
                }
                break;

            case 'downloadCore':
                $hash = $this->getHashFromMeta('core');
                $result = $this->requestServerFile('core', $hash, 'core/get', array('type' => 'install'), 'public');

                if (!$result) {
                    throw new Exception('Unable to open download archive file');
                }
                break;

            // todo package installation

            case 'getMetaDataPackage':

                // todo

                $result = $this->requestServerData('package/install', '', 'private');
                $this->log('getMetaDataPackage:' . print_r($result, true));
                if (!$result) {
                    throw new Exception('Unable to get package information');
                }

                break;

            case 'downloadPackage':
                // todo

                $hash = $this->getHashFromMeta('package');
                $this->requestServerFile('package', $hash, 'package/get', array('name' => 'todo: packagetype'), 'private');
                $this->log('downloadPackage:' . print_r($result, true));
                break;

            // todo

            /*
            $name = $this->post('name');
            if (!$name)
                throw new Exception('Plugin download failed, missing name');

            $params = array('name' => $name);
            if ($project = $this->post('project', false))
                $params['project'] = $project;

            $hash = $this->getHashFromMeta($name, 'plugin');
            $this->requestServerFile($name, $hash, 'plugin/get', $params);
            break;
            */

            case 'backupZip':

                $exclude_dirs = array('images/cache', 'common/templates_c', 'cloudbeez');
                $exclude_files = '';
                $backup_dir = '../' . MH_ROOT_PATH;
                $this->cleanLegacyImageCache($this->deployDirectory . 'images/cache');
                $this->cleanBackups($this->backupDirectory);
                $result = $this->backup($backup_dir, $this->backupDirectory, $this->backup_file, $exclude_files, $exclude_dirs);
                $this->deleteSessionVar('mailbeez_installer_backup_location');

                if (!$result) {
                    throw new Exception('Unable to backup application files');
                }

                break;

            case 'checkFilePermission':
                $workpath = $this->extract_zip($this->getFilePath('core'), $this->unzipDirectory);
                $this->debug_output("starting checkFilePermission: workpath $workpath\n");

                if (!$workpath) {
                    throw new Exception('Unable to extract application files');
                }

                $this->writeSessionVar('mailbeez_installer_workpath', $workpath);

                $write_test = $this->test_deploy_files($workpath, $this->deployDirectory, $this->exclude_overwrite, $this->glob_pattern);

                if (!$write_test) {
                    throw new Exception('Could not extract application files (not writeable) ' . $write_test);
                }

                $result = true;

                /*
                // fix strange behaviour not storing sessions on some server
                // workaround PHP5.2 error
                // Fatal error: session_start() [<a href='function.session-start'>function.session-start</a>]: Failed to initialize storage module: user (path: /tmp)

                if (version_compare(PHP_VERSION, "5.3", ">=")) {
                    session_write_close();
                    session_start();
                }
                $_SESSION['mailbeez_installer_workpath'] = $workpath;
                session_write_close();
                */
//                return true;
                break;

            case 'checkFilePermissionPackage':

                $this->debug_output("getFilePath('package') " . $this->getFilePath('package'));
                $workpath = $this->extract_zip($this->getFilePath('package'), $this->unzipDirectory);

                $this->debug_output("starting checkFilePermissionPackage: workpath $workpath\n");

                $this->writeSessionVar('mailbeez_package_installer_workpath', $workpath);

                if (!$workpath) {
                    throw new Exception('Unable to extract package files - workpath empty');
                }

                $this->debug_output("starting checkFilePermissionPackage: workpath $workpath\n");


                $write_test = $this->test_deploy_files($workpath, $this->deployDirectory, $this->exclude_overwrite_package, $this->glob_pattern);
                if (!$write_test) {
                    throw new Exception('Could not extract package files (not writeable) ' . $write_test);
                }

                $result = true;

                /*
                if (version_compare(PHP_VERSION, "5.3", ">=")) {
                    session_write_close();
                    session_start();
                }
                $_SESSION['mailbeez_package_installer_workpath'] = $workpath;
                session_write_close();
                */
                //return true;
                break;

            case 'extractCore':

                $workpath = $this->readSessionVar('mailbeez_installer_workpath'); //$_SESSION['mailbeez_installer_workpath'];

                if (!$workpath) {
                    throw new Exception('Unable to extract application files - workpath empty');
                }

                $result = $this->deploy_files($workpath, $this->deployDirectory, $this->exclude_overwrite, $this->glob_pattern);

                $this->delete_folder($workpath);

                $this->deleteSessionVar('mailbeez_installer_workpath');
                $this->deleteSessionVar('mailbeez_installer_backup_location');
                $this->deleteSessionVar('mailbeez_installer_backup_location_dir');

                if (!$result) {
                    throw new Exception('Unable to deploy application files');
                }

                // todo
                // update signature


                break;

            case 'extractPackage':

                $workpath = $this->readSessionVar('mailbeez_package_installer_workpath'); //$_SESSION['mailbeez_package_installer_workpath'];

                if (!$workpath) {
                    throw new Exception('Unable to extract package files - workpath empty');
                }

                $this->debug_output("starting extractPackage: workpath $workpath\n");


                $result = $this->deploy_files($workpath, $this->deployDirectory, $this->exclude_overwrite_package, $this->glob_pattern);

                $this->delete_folder($workpath);

                $this->deleteSessionVar('mailbeez_package_installer_workpath');

                //unset($_SESSION['mailbeez_package_installer_workpath']);

                if (!$result) {
                    throw new Exception('Unable to deploy package files');
                }

                // update signature
                $hashFile = $this->deployDirectory . 'package.hash';
                if (file_exists($hashFile)) {
                    $package_hash = file_get_contents($hashFile);
                    mh_insert_config_value(array('configuration_title' => 'Package hash',
                        'configuration_key' => 'MAILBEEZ_CLOUDBEEZ_PACKAGE_HASH',
                        'configuration_value' => $package_hash,
                        'configuration_description' => 'set automatically',
                        'set_function' => ''
                    ), true);
                    $this->debug_output("set package hash: $package_hash\n");
                } else {
                    $this->debug_output("ERROR package hash file not found\n");
                }

                $this->deleteSessionVar('mailbeez_package_installer_workpath');
                $this->deleteSessionVar('mailbeez_installer_workpath');
                $this->deleteSessionVar('mailbeez_installer_backup_location');
                $this->deleteSessionVar('mailbeez_installer_backup_location_dir');

                break;

            case 'finishInstall':
                break;
        }

        $this->log('Step %s +OK', $installStep);

        return array('result' => $result);
    }

    //
    // Installation Steps
    //


    public function setCoreBuild()
    {
        /*
        $this->bootFramework();

        call_user_func('System\Models\Parameters::set', array(
            'system::core.hash'  => post('hash'),
            'system::core.build' => post('build'),
        ));
        */
    }

    //
    // File Management
    //

    private function moveHtaccess($old = null, $new = null)
    {
        $oldFile = $this->baseDirectory . '/.htaccess';
        if ($old) $oldFile .= '.' . $old;

        $newFile = $this->baseDirectory . '/.htaccess';
        if ($new) $newFile .= '.' . $new;

        if (file_exists($oldFile))
            rename($oldFile, $newFile);
    }

    private function unzipFile($fileCode, $directory = null)
    {
        $source = $this->getFilePath($fileCode);
        $destination = $this->unzipDirectory;

        $this->log('Extracting file (%s): %s', $fileCode, basename($source));

        if ($directory)
            $destination .= '/' . $directory;

        if (!file_exists($destination))
            mkdir($destination, $this->dir_permissions, true);

        $zip = new ZipArchive;
        if ($zip->open($source) === true) {
            $zip->extractTo($destination);
            $zip->close();
            return true;
        }

        return false;
    }

    private function getFilePath($fileCode)
    {
        $name = md5($fileCode) . '.arc';
        return $this->tempDirectory . '/' . $name;
    }

    public function cleanWorkDirectory()
    {
        // delete all folders underneath $this->unzipDirectory;
        $dir = $this->unzipDirectory;
        $files = array_diff(scandir($dir), array('.', '..'));
        foreach ($files as $file) {
            if ($file == 'index.html') {
                continue;
            }
            (is_dir("$dir/$file")) ? $this->delete_folder("$dir/$file") : unlink("$dir/$file");
        }
    }


    //
    // Logging
    //

    public function cleanLog()
    {
        $message = array(
            "====================================================================.",
            "========================== INSTALLATION LOG ========================'",
            "",
        );

        file_put_contents($this->logFile, implode(PHP_EOL, $message) . PHP_EOL);
    }

    public function log()
    {
        $args = func_get_args();
        $message = array_shift($args);


        if (is_array($message)) {
            unset($message['changelog']);
            $message = implode(PHP_EOL, $message);
        }

        if (count($args) === 0) {
            $message = str_replace('%', '%%', $message);
        }

        $filename = $this->logFile;

        $stream = @fopen($filename, 'a');

        if ($stream === false) {
            return;
        }

        $string = "[" . date("Y/m/d h:i:s", time()) . "] " . vsprintf($message, $args);
        fwrite($stream, $string . PHP_EOL);
        fclose($stream);
    }

    //
    // Helpers
    //

    private function bootFramework()
    {
        require $this->baseDirectory . '/bootstrap/autoload.php';
        $this->app = $app = require_once $this->baseDirectory . '/bootstrap/start.php';
        $app->boot();
    }


    private function serverConnectionSpeedTest()
    {

        $result = false;

        $curl = $this->prepareServerRequest(null, null, $auth_mode = 'public');

        // overwrite URI
        curl_setopt($curl, CURLOPT_URL, CLOUDBEEZ_CONNECTION_SPEED_TEST_URL);

        $filePath = $this->getFilePath('speedtest');
        $stream = fopen($filePath, 'w');

        curl_setopt($curl, CURLOPT_FILE, $stream);

        $data = curl_exec($curl);
//        $error = curl_error($curl);
        $info = curl_getinfo($curl);


        // PHP 8.0+ returns a CurlHandle object instead of a resource.
        if ($curl instanceof \CurlHandle || is_resource($curl)) {
            curl_close($curl);
        }

        if ($info['speed_download'] > CLOUDBEEZ_CONNECTION_SPEED_LIMIT) {
            $result = true;
        }


        $_result = array('result' => $result);

        return $_result;

    }

    private function requestServerData($uri = null, $params = null, $auth_mode = 'private')
    {
        $result = null;
        $error = null;
        try {
            $curl = $this->prepareServerRequest($uri, $params, $auth_mode);
            $result = curl_exec($curl);

            $this->log('Server request: %s', $uri);

            $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

            if ($httpCode == 500) {
                $error = $result;
                $result = '';
            }

            $this->log('Request information: %s', print_r(curl_getinfo($curl), true));

            curl_close($curl);
        } catch (Exception $ex) {
            $this->log('Failed to get server data (ignored): ' . $ex->getMessage());
        }
        if ($error !== null)
            throw new Exception('Server responded with error: ' . $error);

        if (!$result || !strlen($result))
            throw new Exception('Server responded had no response.');

        try {
            $_result = @json_decode($result, true);
        } catch (Exception $ex) {
        }

        if (!is_array($_result)) {
            $this->log('Server response: ' . $result);
            throw new Exception('Server returned an invalid response.');
        }

        return $_result;
    }

    private function requestServerFile($fileCode, $expectedHash, $uri = null, $params = null, $auth_mode = 'private')
    {
        $result = null;
        $error = null;


        try {

            if (!file_exists($this->tempDirectory))
                mkdir($this->tempDirectory, $this->dir_permissions, true);

            $filePath = $this->getFilePath($fileCode);
            $stream = fopen($filePath, 'w');


            $curl = $this->prepareServerRequest($uri, $params, $auth_mode);
            curl_setopt($curl, CURLOPT_FILE, $stream);
            curl_exec($curl);


            $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
            if ($httpCode == 500) {
                $error = file_get_contents($filePath);
            }

            curl_close($curl);
            fclose($stream);
        } catch (Exception $ex) {
            $this->log('Server request: %s', $uri);
            $this->log('Failed to get server delivery: ' . $ex->getMessage());
            throw new Exception('Server failed to deliver the package');
        }

        if ($error !== null)
            throw new Exception('Server responded with error: ' . $error);

        $fileHash = filesize($filePath);


        if ($expectedHash != $fileHash) {
            $this->log('File hash mismatch: %s (expected) vs %s (actual)', $expectedHash, $fileHash);
            $this->log('Local file size: %s', filesize($filePath));


            $filePath_failed = $filePath . '_failed';
            @unlink($filePath_failed);
            rename($filePath, $filePath_failed);

            throw new Exception("Transfer of Package files $fileCode from server $uri failed, check the content of $filePath_failed");
        }

        $this->log('Saving to file (%s): %s', $fileCode, $filePath);

        return true;
    }

    private function prepareServerRequest($uri, $params = null, $auth_mode = 'private')
    {

        $uri = (string)$uri;

        if (!is_array($params)) {
            $params = array();
        }

        $params['p'] = urlencode(base64_encode(serialize(array('domain' => $_SERVER['SERVER_NAME'],
            'p' => MH_PLATFORM,
            'a' => MH_ID,
            'url' => base64_encode($this->getBaseUrl())))));

        // set api

        if ($auth_mode == 'private') {
            $params['apikey'] = $this->apikey;
        }

        $uri .= (stristr($uri, '?')) ? '&' : '?';
        $uri .= http_build_query($params, '', '&');

        $url = (($auth_mode == 'public') ? CLOUDBEEZ_GATEWAY_PUBLIC : CLOUDBEEZ_GATEWAY_PRIVATE) . '/' . $uri;

        $this->log('Server request (prepare): %s', $uri);


        // workaround for CURLOPT_FOLLOWLOCATION -> open_basedir conflict
        $real_url = $this->curlProcessRedirects($url);

        $curl = curl_init($real_url);

        // Issue a HEAD request and follow any redirects.

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 120);
//        curl_setopt($curl, CURLOPT_NOBODY, true);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false); // open_basedir conflict

        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

        if (defined('CLOUDBEEZ_GATEWAY_AUTH')) {
            curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
            curl_setopt($curl, CURLOPT_USERPWD, CLOUDBEEZ_GATEWAY_AUTH);
        }


        return $curl;
    }

    private function post($var, $default = null)
    {
        if (array_key_exists($var, $_REQUEST)) {
            $result = $_REQUEST[$var];
            if (is_string($result)) $result = trim($result);
            return $result;
        }

        return $default;
    }

    private function getHashFromMeta($targetCode, $packageType = 'plugin')
    {
        $meta = $this->post('meta');
        $packageType .= 's';

        if ($targetCode == 'core')
            return (isset($meta['core']['hash'])) ? $meta['core']['hash'] : null;

        if ($targetCode == 'package')
            return (isset($meta['package']['hash'])) ? $meta['package']['hash'] : null;

        if (!isset($meta[$packageType]))
            return null;

        $collection = $meta[$packageType];
        if (!is_array($collection))
            return null;

        foreach ($collection as $code => $hash) {
            if ($code == $targetCode)
                return $hash;
        }

        return null;
    }

    public function getBaseUrl()
    {
        if (isset($_SERVER['HTTP_HOST'])) {
            $baseUrl = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
            $baseUrl .= '://' . $_SERVER['HTTP_HOST'];
            $baseUrl .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
        } else {
            $baseUrl = 'http://localhost/';
        }

        return $baseUrl;
    }

    public function curlProcessRedirects($url)
    {
        $curl_location = curl_init($url);

        // Issue a HEAD request and follow any redirects.

        curl_setopt($curl_location, CURLOPT_TIMEOUT, 30);
        curl_setopt($curl_location, CURLOPT_NOBODY, true);
        curl_setopt($curl_location, CURLOPT_HEADER, true);
        curl_setopt($curl_location, CURLOPT_FOLLOWLOCATION, false); // open_basedir conflict
        curl_setopt($curl_location, CURLOPT_RETURNTRANSFER, true);

        $rawResult = curl_exec($curl_location);

        // check if redirect
        if (preg_match('#Location: (.*)#', $rawResult, $r)) {
            $real_url = trim($r[1]);
            //$this->log('real url: %s', $real_url);
            return $this->curlProcessRedirects($real_url);
        } else {
            return $url;
        }

    }


    public function cleanUp()
    {
        $path = $this->tempDirectory;
        if (!file_exists($path))
            return;

        $d = dir($path);
        while (($entry = $d->read()) !== false) {
            $filePath = $path . '/' . $entry;

            if ($entry == '.' || $entry == '..' || $entry == '.htaccess' || is_dir($filePath))
                continue;

            $this->log('Cleaning up file: %s', $entry);
            @unlink($filePath);
        }

        $d->close();
    }

    public function getContent($route, $params)
    {

        $result = null;
        $error = null;
        try {
            $curl = $this->prepareServerRequest('content/' . $route, $params, 'public');
            $content = curl_exec($curl);

            $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

            if ($httpCode == 500) {
                $error = $result;
                $result = '';
            }

            curl_close($curl);
        } catch (Exception $ex) {
            $this->log('Failed to get server data (ignored): ' . $ex->getMessage());
        }

        $a = 'a=' . MH_ID;
        $content = preg_replace("#href=\"(([a-zA-Z]+://)([a-zA-Z0-9%.;:/=+_-]*[?]+[a-zA-Z0-9&%.;:/=+_-]*))\"#", "href=\"$1" . "&" . $a . "\"", $content);
        $content = preg_replace("#href=\"(([a-zA-Z]+://)([a-zA-Z0-9%.;:/=+_-]*))\"#", "href=\"$1" . "?" . $a . "\"", $content);

        $content = str_replace('mailhive/', MH_ROOT_PATH, $content);

        $content = str_replace('mailbeez.php?', $this->link(''), $content);

        return $content;
    }


    function writeSessionVar($name, $value)
    {
        $_SESSION[$name] = $value;
        $filename = $this->tempDirectory . '/var_' . $name . '.txt';
        $stream = @fopen($filename, 'w');

        if ($stream === false) {
            return;
        }

        fwrite($stream, $value);
        fclose($stream);
    }

    function readSessionVar($name)
    {
        if (file_exists($this->tempDirectory . '/var_' . $name . '.txt')) {
            $value = file_get_contents($this->tempDirectory . '/var_' . $name . '.txt');
            $_SESSION[$name] = $value;
            return $value;
        } else {
            return false;
        }
    }

    function deleteSessionVar($name)
    {
        if (file_exists($this->tempDirectory . '/var_' . $name . '.txt')) {
            @unlink($this->tempDirectory . '/var_' . $name . '.txt');
        }
    }


    function link($uri = '')
    {
        if (defined('SESSION_FORCE_COOKIE_USE') && constant('SESSION_FORCE_COOKIE_USE') == 'False' && function_exists('xtc_href_link')) {
            $link = xtc_href_link('mailbeez.php', '', $connection = 'NONSSL', $add_session_id = true);
            if (stristr($link, '?')) {
                $link .= '&' . $uri;
            } else {
                $link .= '?' . $uri;
            }
            return $link;
        } else {

            return 'mailbeez.php?' . $uri;
        }

    }

}