<?php
/**
 *
 * @package Legacy
 * @version $Id: Legacy_TextFilter.class.php,v 1.9 2008/09/25 15:11:57 kilica Exp $
 * @copyright Copyright 2005-2007 XOOPS Cube Project  <http://xoopscube.sourceforge.net/> 
 * @license http://xoopscube.sourceforge.net/license/GPL_V2.txt GNU GENERAL PUBLIC LICENSE Version 2
 *
 */

if (!defined('XOOPS_ROOT_PATH')) exit();

/**
 * @public
 * @brief The text filter for Legacy.
 */
class Legacy_TextFilter extends XCube_TextFilter
{
    /**
     * @var XCube_Delegate
     */
    var $mMakeXCodeConvertTable = null;
    /**
     * @var XCube_Delegate
     */
    var $mMakeXCodeCheckImgPatterns = null;
    /**
     * @var XCube_Delegate
     */
    var $mMakeClickableConvertTable = null;
    /**
     * @var XCube_Delegate
     */
    var $mMakePreXCodeConvertTable = null;
    /**
     * @var XCube_Delegate
     */
    var $mMakePostXCodeConvertTable = null;
    /**
     * @var XCube_Delegate
     * @deprecated  keep compatible with XC2.1 Beta3
     */
    var $mXCodePre = null;
    /**
     * @var XCube_Delegate
     * @deprecated  keep compatible with XC2.1 Beta3. Legacy 2.2.0 will not support this.
     * @todo
     *    This is a deprecated member.
     */
    var $mMakeClickablePre = null;


    var $mClickablePatterns = array();
    var $mClickableReplacements = array();

    var $mXCodePatterns = array();
    var $mXCodeReplacements = array();
    var $mXCodeCheckImgPatterns = array();

    var $mPreXCodePatterns = array();
    var $mPreXCodeReplacements = array();

    var $mPostXCodePatterns = array();
    var $mPostXCodeReplacements = array();
    
    var $mSmileys = array();
    var $mSmileysConvTable = array();

	/**
	 * @public
	 * @brief Constructor
	 * @todo
	 *    This method keeps a deprecated delegate.
	 */
    function Legacy_TextFilter()
	{
        $this->mMakeClickableConvertTable =& new XCube_Delegate;
        $this->mMakeClickableConvertTable->register('Legacy_TextFilter.MakeClickableConvertTable');
        $this->mMakeClickableConvertTable->add('Legacy_TextFilter::makeClickableConvertTable', XCUBE_DELEGATE_PRIORITY_2);

        $this->mMakeXCodeConvertTable =& new XCube_Delegate;
        $this->mMakeXCodeConvertTable->register('Legacy_TextFilter.MakeXCodeConvertTable');
        $this->mMakeXCodeConvertTable->add('Legacy_TextFilter::makeXCodeConvertTable', XCUBE_DELEGATE_PRIORITY_2);

        $this->mMakeXCodeCheckImgPatterns =& new XCube_Delegate;
        $this->mMakeXCodeCheckImgPatterns->register('Legacy_TextFilter.MakeXCodeCheckImgPatterns');
        $this->mMakeXCodeCheckImgPatterns->add('Legacy_TextFilter::makeXCodeCheckImgPatterns', XCUBE_DELEGATE_PRIORITY_2);

        $this->mMakePreXCodeConvertTable =& new XCube_Delegate;
        $this->mMakePreXCodeConvertTable->register('Legacy_TextFilter.MakePreXCodeConvertTable');
        $this->mMakePreXCodeConvertTable->add('Legacy_TextFilter::makePreXCodeConvertTable', XCUBE_DELEGATE_PRIORITY_2);

        $this->mMakePostXCodeConvertTable =& new XCube_Delegate;
        $this->mMakePostXCodeConvertTable->register('Legacy_TextFilter.MakePostXCodeConvertTable');
        $this->mMakePostXCodeConvertTable->add('Legacy_TextFilter::makePostXCodeConvertTable', XCUBE_DELEGATE_PRIORITY_2);

        //@deprecated
        //Todo: For keeping compatible with XC2.1 Beta3
        $this->mMakeClickablePre =& new XCube_Delegate();
        $this->mMakeClickablePre->register('MyTextSanitizer.MakeClickablePre');

        $this->mXCodePre =& new XCube_Delegate();
        $this->mXCodePre->register('MyTextSanitizer.XoopsCodePre');
    }
    
    function getInstance(&$instance) {
        if (empty($instance)) {
            $instance = new Legacy_TextFilter();
        }
    }
    
    /**
     * Filters for editing text
     *
     * @param   string  $text
     * @param   string  $x2comat
     * @return  string
     *
     **/
    function toShow($text, $x2comat=false) {
        if ($x2comat) {
            //ToDo: &nbsp; patern is defined for XOOPS2.0 compatiblity. But what is it?
            //      This comatiblity option is used from method from MyTextSanitizer.
            //
            return preg_replace(array("/&amp;(#[0-9]+|#x[0-9a-f]+|[a-z]+[0-9]*);/i", "/&nbsp;/i"), array('&\\1;', '&amp;nbsp;'), htmlspecialchars($text, ENT_QUOTES));
        } else {
            return preg_replace("/&amp;(#[0-9]+|#x[0-9a-f]+|[a-z]+[0-9]*);/i", '&\\1;', htmlspecialchars($text, ENT_QUOTES));
        }
    }

    /**
     * Filters for editing text
     *
     * @param   string  $text
     * @return  string
     *
     **/
    function toEdit($text) {
        return preg_replace("/&amp;(#0?[0-9]{4,6};)/i", '&$1', htmlspecialchars($text, ENT_QUOTES));
    }

    /**
     * Filters textarea data for display
     *
     * @param   string  $text
     * @param   bool    $html   allow html?
     * @param   bool    $smiley allow smileys?
     * @param   bool    $xcode  allow xoopscode?
     * @param   bool    $image  allow inline images?
     * @param   bool    $br     convert linebreaks?
     * @param   string  $x2comat
     * @return  string
     **/
    function toShowTarea($text, $html = 0, $smiley = 1, $xcode = 1, $image = 1, $br = 1, $x2comat=false) {
        $text = $this->preConvertXCode($text, $xcode);
        if ($html != 1) $text = $this->toShow($text, $x2comat);
        $text = $this->makeClickable($text);
        if ($smiley != 0) $text = $this->smiley($text);
        if ($xcode != 0) $text = $this->convertXCode($text, $image);
        if ($br != 0) $text = $this->nl2Br($text);
        $text = $this->postConvertXCode($text, $xcode, $image);
        return $text;
    }

    /**
     * Get the smileys
     *
     * @return  array
     */
    function getSmileys() {
        if (count($this->mSmileys) == 0) {
            $this->mSmileysConvTable[0] = $this->mSmileysConvTable[1] = array();
            $db =& Database::getInstance();
            if ($getsmiles = $db->query("SELECT * FROM ".$db->prefix("smiles"))){
                while ($smile = $db->fetchArray($getsmiles)) {
                    $this->mSmileys[] = $smile;
                    $this->mSmileysConvTable[0][] = $smile['code'];
                    $this->mSmileysConvTable[1][] = '<img src="'.XOOPS_UPLOAD_URL.'/'.htmlspecialchars($smile['smile_url']).'" alt="" />';
                }
            }
        }
        return $this->mSmileys;
    }

    /**
     * Replace emoticons in the message with smiley images
     *
     * @param   string  $message
     *
     * @return  string
     */
    function smiley($text) {
        if (count($this->mSmileys) == 0) $this->getSmileys();
        if (count($this->mSmileys) != 0) {
            $text = str_replace($this->mSmileysConvTable[0], $this->mSmileysConvTable[1], $text);
        }
        return $text;
    }

    /**
     * Make links in the text clickable
     *
     * @param   string  $text
     * @return  string
     **/
    function makeClickable($text) {
        if (empty($this->mClickablePatterns)) {
            // Delegate Call 'Legacy_TextFilter.MakeClickableConvertTable'
            //  Delegate may replace makeClickable conversion table
            //  Args : 
            //      'patterns'     [I/O] : &Array of pattern RegExp
            //      'replacements' [I/O] : &Array of replacing string
            //
            $this->mMakeClickableConvertTable->call(new XCube_Ref($this->mClickablePatterns), new XCube_Ref($this->mClickableReplacements));

            // Delegate Call 'MyTextSanitizer.MakeClickablePre'
            //  Delegate may replace makeClickable conversion table
            //  Args : 
            //      'patterns'     [I/O] : &Array of pattern RegExp
            //      'replacements' [I/O] : &Array of replacing string
            //
            //  Todo: For Compatiblitiy to XC2.1 Beta3
            //
            $this->mMakeClickablePre->call(new XCube_Ref($this->mClickablePatterns), new XCube_Ref($this->mClickableReplacements));
        }
        $text = preg_replace($this->mClickablePatterns, $this->mClickableReplacements, $text);
        return $text;
    }

    function makeClickableConvertTable(&$patterns, &$replacements) {
        $patterns[] = "/(^|[^]_a-z0-9-=\"'\/])([a-z]+?):\/\/([^, \r\n\"\(\)'<>]+)/i";
        $replacements[] = "\\1<a href=\"\\2://\\3\" target=\"_blank\">\\2://\\3</a>";
        $patterns[] = "/(^|[^]_a-z0-9-=\"'\/])www\.([a-z0-9\-]+)\.([^, \r\n\"\(\)'<>]+)/i";
        $replacements[] = "\\1<a href=\"http://www.\\2.\\3\" target=\"_blank\">www.\\2.\\3</a>";
        $patterns[] = "/(^|[^]_a-z0-9-=\"'\/])ftp\.([a-z0-9\-]+)\.([^, \r\n\"\(\)'<>]+)/i";
        $replacements[] = "\\1<a href=\"ftp://ftp.\\2.\\3\" target=\"_blank\">ftp.\\2.\\3</a>";
        $patterns[] = "/(^|[^]_a-z0-9-=\"'\/:\.])([a-z0-9\-_\.]+?)@([a-z0-9!#\$%&'\*\+\-\/=\?^_\`{\|}~\.]+)/i";
        $replacements[] = "\\1<a href=\"mailto:\\2@\\3\">\\2@\\3</a>";
    }

    /**
     * Replace XoopsCodes with their equivalent HTML formatting
     *
     * @param   string  $text
     * @param   bool    $allowimage Allow images in the text?
     *                              On FALSE, uses links to images.
     * @return  string
     **/
    function convertXCode($text, $allowimage = 1) {
        if (empty($this->mXCodePatterns)) {
            // Delegate Call 'Legacy_TextFilter.MakeXCodeConvertTable'
            //  Delegate may replace makeClickable conversion table
            //  Args : 
            //      'patterns'     [I/O] : &Array of pattern RegExp
            //      'replacements' [I/O] : &Array[0..1] of Array of replacing string
            //                             replacements[0] for $allowimage = 0;
            //                             replacements[1] for $allowimage = 1;
            //
            $this->mMakeXCodeConvertTable->call(new XCube_Ref($this->mXCodePatterns), new XCube_Ref($this->mXCodeReplacements));

            // RaiseEvent 'MyTextSanitizer.XoopsCodePre'
            //  Delegate may replace conversion table
            //  Args : 
            //      'patterns'     [I/O] : &Array of pattern RegExp
            //      'replacements' [I/O] : &Array of replacing string
            //      'allowimage'   [I]   : xoopsCodeDecode $allowimage parameter
            //
            //Todo: For Compatiblitiy to XC2.1 Beta3
            $this->mXCodePre->call(new XCube_Ref($this->mXCodePatterns), new XCube_Ref($this->mXCodeReplacements[0]), 0);
            $dummy = array();
            $this->mXCodePre->call(new XCube_Ref($dummy), new XCube_Ref($this->mXCodeReplacements[1]), 1);
        }
        if (empty($this->mXCodeCheckImgPatterns)) {
            // RaiseEvent 'Legacy_TextFilter.MakeXCodeCheckImgPatterns'
            //  Delegate may replace conversion table
            //  Args : 
            //      'patterns'     [I/O] : &Array of pattern RegExp
            //      'replacements' [I/O] : &Array of replacing string
            //
            $this->mMakeXCodeCheckImgPatterns->call(new XCube_Ref($this->mXCodeCheckImgPatterns));
        }
        $text = preg_replace_callback($this->mXCodeCheckImgPatterns, array($this, '_filterImgUrl'), $text);
        $replacementsIdx = ($allowimage == 0) ? 0 : 1;
        $text = preg_replace($this->mXCodePatterns, $this->mXCodeReplacements[$replacementsIdx], $text);
        return $text;
    }
    
    function makeXCodeCheckImgPatterns(&$patterns) {
        $patterns[] = "/\[img( align=\w+)]([^\"\(\)\?\&'<>]*)\[\/img\]/sU";
    }

    function makeXCodeConvertTable(&$patterns, &$replacements) {
        $patterns[] = "/\[siteurl\=(['\"]?)([^\"'<>]*)\\1\](.*)\[\/siteurl\]/sU";
        $replacements[0][] = $replacements[1][] = '<a href="'.XOOPS_URL.'/\\2" target="_blank">\\3</a>';
        $patterns[] = "/\[url\=(['\"]?)(http[s]?:\/\/[^\"'<>]*)\\1\](.*)\[\/url\]/sU";
        $replacements[0][] = $replacements[1][] = '<a href="\\2" target="_blank">\\3</a>';
        $patterns[] = "/\[url\=(['\"]?)(ftp?:\/\/[^\"'<>]*)\\1\](.*)\[\/url\]/sU";
        $replacements[0][] = $replacements[1][] = '<a href="\\2" target="_blank">\\3</a>';
        $patterns[] = "/\[url\=(['\"]?)([^\"'<>]*)\\1\](.*)\[\/url\]/sU";
        $replacements[0][] = $replacements[1][] = '<a href="http://\\2" target="_blank">\\3</a>';
        $patterns[] = "/\[color\=(['\"]?)([a-zA-Z0-9]*)\\1\](.*)\[\/color\]/sU";
        $replacements[0][] = $replacements[1][] = '<span style="color: #\\2;">\\3</span>';
        $patterns[] = "/\[size\=(['\"]?)([a-z-]*)\\1\](.*)\[\/size\]/sU";
        $replacements[0][] = $replacements[1][] = '<span style="font-size: \\2;">\\3</span>';
        $patterns[] = "/\[font\=(['\"]?)([^;<>\*\(\)\"']*)\\1\](.*)\[\/font\]/sU";
        $replacements[0][] = $replacements[1][] = '<span style="font-family: \\2;">\\3</span>';
        $patterns[] = "/\[email\]([^;<>\*\(\)\"']*)\[\/email\]/sU";
        $replacements[0][] = $replacements[1][] = '<a href="mailto:\\1">\\1</a>';
        $patterns[] = "/\[b\](.*)\[\/b\]/sU";
        $replacements[0][] = $replacements[1][] = '<b>\\1</b>';
        $patterns[] = "/\[i\](.*)\[\/i\]/sU";
        $replacements[0][] = $replacements[1][] = '<i>\\1</i>';
        $patterns[] = "/\[u\](.*)\[\/u\]/sU";
        $replacements[0][] = $replacements[1][] = '<u>\\1</u>';
        $patterns[] = "/\[d\](.*)\[\/d\]/sU";
        $replacements[0][] = $replacements[1][] = '<del>\\1</del>';
        $patterns[] = "/\[img align\=(['\"]?)(left|center|right)\\1\]([^\"\(\)\?\&'<>]*)\[\/img\]/sU";
        $replacements[0][] = '<a href="\\3" target="_blank">\\3</a>';
        $replacements[1][] = '<img src="\\3" align="\\2" alt="" />';
        $patterns[] = "/\[img\]([^\"\(\)\?\&'<>]*)\[\/img\]/sU";
        $replacements[0][] = '<a href="\\1" target="_blank">\\1</a>';
        $replacements[1][] = '<img src="\\1" alt="" />';
        $patterns[] = "/\[img align\=(['\"]?)(left|center|right)\\1 id\=(['\"]?)([0-9]*)\\3\]([^\"\(\)\?\&'<>]*)\[\/img\]/sU";
        $replacements[0][] = '<a href="'.XOOPS_URL.'/image.php?id=\\4" target="_blank">\\5</a>';
        $replacements[1][] = '<img src="'.XOOPS_URL.'/image.php?id=\\4" align="\\2" alt="\\5" />';
        $patterns[] = "/\[img id\=(['\"]?)([0-9]*)\\1\]([^\"\(\)\?\&'<>]*)\[\/img\]/sU";
        $replacements[0][] = '<a href="'.XOOPS_URL.'/image.php?id=\\2" target="_blank">\\3</a>';
        $replacements[1][] = '<img src="'.XOOPS_URL.'/image.php?id=\\2" alt="\\3" />';
        $patterns[] = "/\[quote\]/sU";
        $replacements[0][] = $replacements[1][] = _QUOTEC.'<div class="xoopsQuote"><blockquote>';
        $patterns[] = "/\[\/quote\]/sU";
        $replacements[0][] = $replacements[1][] = '</blockquote></div>';
        $patterns[] = "/javascript:/si";
        $replacements[0][] = $replacements[1][] = "java script:";
        $patterns[] = "/about:/si";
        $replacements[0][] = $replacements[1][] = "about :";
    }

    /**
     * Filters out invalid strings included in URL, if any
     *
     * @param   array  $matches
     * @return  string
     */
    function _filterImgUrl($matches)
    {
        if ($this->_checkUrlString($matches[2])) {
            return $matches[0];
        } else {
            return "";
        }
    }

    /**
     * Checks if invalid strings are included in URL
     *
     * @param   string  $text
     * @return  bool
     */
    function _checkUrlString($text)
    {
        // Check control code
        if (preg_match('/[\x0-\x1f\x7f]/', $text)) {
            return false;
        }
        // check black pattern(deprecated)
        return !preg_match("/^(javascript|vbscript|about):/i", $text);
    }

    /**
     * Convert linebreaks to <br /> tags
     *
     * @param   string  $text
     *
     * @return  string
     */
    function nl2Br($text)
    {
        return preg_replace("/(\015\012)|(\015)|(\012)/","<br />",$text);
    }

    /**
     * Pre XCode Converting
     *   By default, keep content within [code][/code] tags
     *
     * @param   string  $text
     * @param   string  $xcode
     *
     * @return  string
     */
    function preConvertXCode($text, $xcode = 1) {
        if($xcode != 0){
            if (empty($this->mPreXCodePatterns)) {
                // RaiseEvent 'Legacy_TextFilter.MakePreXCodeConvertTable'
                //  Delegate may replace conversion table
                //  Args : 
                //      'patterns'     [I/O] : &Array of pattern RegExp
                //      'replacements' [I/O] : &Array of replacing string
                //
                $this->mMakePreXCodeConvertTable->call(new XCube_Ref($this->mPreXCodePatterns), new XCube_Ref($this->mPreXCodeReplacements));
            }
            $text =  preg_replace($this->mPreXCodePatterns, $this->mPreXCodeReplacements, $text);
        }
        return $text;
    }
    
    function makePreXCodeConvertTable(&$patterns, &$replacements) {
        $patterns[] = "/\[code\](.*)\[\/code\]/esU";
        $replacements[] = "'[code]'.base64_encode('$1').'[/code]'";
    }

    /**
     * Post XCode Convering
     *   By default, convert content about [code][/code] tags
     *
     * @param   string  $text
     * @param   string  $xcode
     * @param   string  $image
     *
     * @return  string
     */
    function postConvertXCode($text, $xcode=1, $image=1){
        if($xcode != 0){
            if (empty($this->mPostXCodePatterns)) {
                // RaiseEvent 'Legacy_TextFilter.MakePostXCodeConvertTable'
                //  Delegate may replace conversion table
                //  Args : 
                //      'patterns'     [I/O] : &Array of pattern RegExp
                //      'replacements' [I/O] : &Array[0..1] of Array of replacing string
                //                             replacements[0] for $allowimage = 0;
                //                             replacements[1] for $allowimage = 1;
                //  Caution :
                //     - Conversion table order should be reverse order with codePreConv conversion table.
                //       So, conversion rule for[code] is defined after call delegate function.
                //     - Conversion rule should treat input string as raw text with single quote escape.(not sanitized).
                //
                $this->mMakePostXCodeConvertTable->call(new XCube_Ref($this->mPostXCodePatterns), new XCube_Ref($this->mPostXCodeReplacements));
            }
            $replacementsIdx = ($image == 0) ? 0 : 1;
            $text =  preg_replace($this->mPostXCodePatterns, $this->mPostXCodeReplacements[$replacementsIdx], $text);
        }
        return $text;
    }

    function makePostXCodeConvertTable(&$patterns, &$replacements) {
        $patterns[] = "/\[code\](.*)\[\/code\]/esU";
        $replacements[0][] = "'<div class=\"xoopsCode\"><pre><code>'.Legacy_TextFilter::codeSanitizer('$1', 0).'</code></pre></div>'";
        $replacements[1][] = "'<div class=\"xoopsCode\"><pre><code>'.Legacy_TextFilter::codeSanitizer('$1', 1).'</code></pre></div>'"; 
    }

    function codeSanitizer($text, $image = 1){
        return $this->convertXCode(htmlspecialchars(str_replace('\"', '"', base64_decode($text)),ENT_QUOTES), $image);
    }
}
?>
