<?php

/**
 * Notes :
 *    % Need to either a) install Text_Highlighter as a PEAR module properly or b) alter it so
 *      that it can be included properly without having a Text/ directory at the same level
 *        as the index file.
 *      % Needs some form of cron job or similar to remove old entries
 *        * This would seem preferable to running a delete query every page view
 *        * The retain_until field is there and set by the script so
 *          the framework is there for removal.
 *        * Rather than using a cron job this could be done using a simple timestamp stored in a php
 *          file which could be included (ie $timestamp = X, then include that and
 *          if($timestamp >= now()) { delete query }
 *    % Preventing XSS in User input needed
 *        * Should be handled by any User Auth
 *    % Needs Checking for Aeternus-Brand Stupidity
 * Fixed :
 *    % Problem with strtotime() not parsing PostGres timestamps
 * set field type to timestamp(0) to remove fractional seconds
 *    % Added User Authentication using pwauth
 *        * Could still do with session handling
 *    % Frosty mentioned it wasn't using a monospace font
 *        * Simply made all text within the .hl-main block use the
 *          Courier New Monospace font
 *        * Could possibly offer the user more customisation in terms of
 *          how they want things displayed (necessary??)
 */


// Debugging
//error_reporting(E_ALL);

// Config
define('_LIST_LIMIT', 15);
// Defined so we can customise them to whatever we like
define('_BASE_PATH', 'https://' . $_SERVER['SERVER_NAME'] . '/');
define('_SCRIPT_NAME', 'PasteBin/');
define('_TABLE_NAME', 'pastebin');

$smarty->assign('urifragment', '/Tools/PasteBin/');
$pburi = 'https://' . $_SERVER['SERVER_NAME'] . $baseurl;
$smarty->assign('uri', $pburi . '/pb/');

// Init
$id = '';
if (is_numeric($pathlist[count($pathlist) - 1])) {
    //$id = substr($_SERVER['PATH_INFO'],1);
    //$id = preg_match('/[0-9]+/', $id)?$id:'';
    $i = count($pathlist) - 1;
    $id = $pathlist[$i];
    $id = preg_match('/[0-9]+/', $id) ? $id : '';
} else if (is_numeric($pathlist[count($pathlist) - 2]) && (strtolower($pathlist[count($pathlist) - 1]) == 'plain')) {
    // Plain text
    $no_template = true;
    $id = $pathlist[count($pathlist) - 2];
    $id = preg_match('/[0-9]+/', $id) ? $id : '';
    $code = $DB->GetOne('SELECT code FROM ' . _TABLE_NAME . ' WHERE  id = ?', array($id));
    header('Content-Type: text/plain');
    print html_entity_decode($code, ENT_QUOTES, 'UTF-8');
    return; // Finish processing in this file
}
$code = '';
$pblang = '';

// Includes
require_once 'PEAR.php';
require_once 'Text/Highlighter.php';
require_once 'Text/Highlighter/Renderer.php';
require_once 'Text/Highlighter/Renderer/Html.php';
require_once '../lib/ArrayRenderer.php';

//yay php5.4
(new PEAR)->setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_WARNING);

// Grabbed from blog.lib.php
// Returns a textual diff between two time stamps
function timeDiff($first, $second = 0)
{
    if ($second == 0) {
        $second = time();
    }

    $diff = max($first, $second) - min($first, $second);

    if ($diff > 604800) {
        $ret = round($diff / 604800);
        return $ret . (($ret > 1) ? _(" weeks") : _(" week"));
    } elseif ($diff > 86400) {
        $ret = round($diff / 86400);
        return $ret . (($ret > 1) ? _(" days") : _(" day"));
    } elseif ($diff > 3600) {
        $ret = round($diff / 3600);
        return $ret . (($ret > 1) ? _(" hours") : _(" hour"));
    } elseif ($diff > 60) {
        $ret = round($diff / 60);
        return $ret . (($ret > 1) ? _(" minutes") : _(" minute"));
    } elseif ($diff > 0) {
        return $diff . (($diff > 1) ? _(" seconds") : _(" second"));
    } else {
        return "no time";
    }
}

// Languages
$LANGUAGES = array(
    'PHP' => 'PHP',
    'CPP' => 'C/C++',
    'DIFF' => 'Diff',
    'DTD' => 'DTD',
    'HTML' => 'HTML',
    'JAVA' => 'Java',
    'JAVASCRIPT' => 'Javascript',
    'MYSQL' => 'MySQL',
    'PERL' => 'Perl',
    'PYTHON' => 'Python',
    'RUBY' => 'Ruby',
    'SQL' => 'SQL',
    'XML' => 'XML'
);

// Remove Old Pastebin Entries
// possibly some error handling needed?
$DB->Execute('DELETE FROM ' . _TABLE_NAME . ' WHERE retain_til < now()');

// Needed here?
//removeMagicQuotes($_POST);

if (isset($_POST['code'])) {
    $code = htmlentities($_POST['code'], ENT_QUOTES, 'UTF-8');
    if (isset($_POST['language']) && isset($_POST['retain'])) {
        // Add
        $pblang = strtoupper($_POST['language']);
        if (!isset($LANGUAGES[$pblang])) {
            $pblang = 'NONE';
        }


        switch ($_POST['retain'][0]) {
            case 'month' :
                $retain = 2592000;
                $retainTil = date('Y/m/d H:i:s', time() + $retain);
                break;
            case 'week' :
                $retain = 604800;
                $retainTil = date('Y/m/d H:i:s', time() + $retain);
                break;
            case 'forever' :
                $retain = null;
                $retainTil = null;
                break;
            case 'day' :
            default :
                $retain = 86400;
                $retainTil = date('Y/m/d H:i:s', time() + $retain);
        }

        if (trim($code) == '') {
            trigger_error('No Code Given', E_USER_NOTICE);
        } else if (!$session->loggedin) {
            trigger_error('You must be logged in to use this service.', E_USER_NOTICE);
        } else {
            // Additional user validation needed here
            //$retainTil = date('Y/m/d H:i:s', time() + $retain);
            $id = $DB->GetOne("SELECT nextval('pastebin_id_seq'::regclass)");
            $DB->Execute(
                'INSERT INTO ' . _TABLE_NAME . ' ( id, code, username, retain_til, language) ' .
                'VALUES (?, ?, ?, ?, ?)',
                array($id, $code, $session->username, $retainTil, $pblang));

            //bump user to uri of newly pasted item
            header('Status: 303 See Other');
            header("Location: $pburi/Tools/PasteBin/$id");

            $userInfo = 'Created By ' . $session->username . ' at ' . date('Y/m/d H:i');
            $smarty->assign('id', $id);
            $smarty->assign('userInfo', $userInfo);
            $smarty->assign('code', $code);

        }
    }
}

// List All Entries in order.
$pasteList = $DB->GetAll(
    'SELECT id, username AS name, created AS time_diff FROM ' . _TABLE_NAME . ' ORDER BY created DESC LIMIT ' . _LIST_LIMIT);
for ($i = 0; $i < count($pasteList); $i++) {
    $pasteList[$i]['time_diff'] = timeDiff(strtotime($pasteList[$i]['time_diff']));
}
$smarty->assign('pasteList', $pasteList);

// Check for either display or form input
if (!empty($id) || !empty($code)) {
    // Form
    if (empty($code)) {
        $result = $DB->GetRow('SELECT * FROM ' . _TABLE_NAME . ' WHERE  id = ?', array($id));
        //$query = db_query('SELECT * FROM ' . _TABLE_NAME . ' WHERE id = \'' . $id . '\'');
        if (!empty($result)) {
            //$result = db_getrow($query);
            $code = $result['code'];
            $userInfo = 'Created By ' . $result['username'] . ' at ' . date('Y/m/d H:i', strtotime($result['created']));
            $pblang = $result['language'];
            // Smarty
            $smarty->assign('id', $id);
            $smarty->assign('code', $code);
            $smarty->assign('userInfo', $userInfo);

        } else {
            // Error
            trigger_error('Error - Code Piece not found for id - ' . $id, E_USER_WARNING);
        }
    }
    // Check there hasn't been an error
    // Code should have been set in the if statement above, this can not become
    // an else
    if (!empty($code)) {
        // Highlight the code
        if ($pblang == 'NONE') {
            $pblang = 'HTML';
        }
        $renderer = new Text_Highlighter_Renderer_Array_dez();
        $tmpobj = new Text_Highlighter;
        $hl =& $tmpobj->factory($pblang);
        $hl->setRenderer($renderer);
        // Have to decode again here for the highlighting
        // It might be a little better if we kept the unencoded version from above
        $highlightedCode = $hl->highlight(html_entity_decode($code, ENT_QUOTES, 'UTF-8'));
        $smarty->assign('highlightedCode', $highlightedCode);
    }
}
// Sort Out Languages
if (!empty($pblang) && $pblang != 'NONE') {
    $smarty->assign('selectedLanguage', array('key' => $pblang, 'lang' => $LANGUAGES[$pblang]));
    unset($LANGUAGES[$pblang]);
}
$smarty->assign('pasteLanguages', $LANGUAGES);

// Load templates etc
$smarty->assign("extra_styles", array("$baseurl/css/pastebin.css"));
$result = $smarty->fetch('pastebin.tpl');
$sidebar = $smarty->fetch('pastebin-sidebar.tpl');
$smarty->assign('title', 'PasteBin');
$smarty->assign('body', $result);
$smarty->assign('secondary', $sidebar);
?>