<?php
/**
 @file       noiewarning/action.php 
 @brief      Warn users of Internet Explorer browser.
 @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 @author     Luis Machuca Bezzaza <luis [dot] machuca [at] gulix [dot] cl>
 @version    2018-08-21
**/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
if(!defined('DW_LF')) define('DW_LF',"\n");

if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
define('THIS_PLUGIN', DOKU_PLUGIN.'noiewarning/');
require_once(DOKU_PLUGIN.'action.php');
require_once(DOKU_INC.'inc/confutils.php');
require_once(DOKU_INC.'inc/infoutils.php'); // for notify facilities

/**
 * All DokuWiki plugins to extend the admin function
 * need to inherit from this class
 */
class action_plugin_noiewarning extends DokuWiki_Action_Plugin {

    // the plugin's data object
    var $cnf= array();
    // the browser recommendation
    var $betterbrowser= null;

    function action_plugin_noiewarning () {
        global $ID;
        global $ACT;
        // load options from configuration
        $this->cnf= array (
            'id'         => $ID,
            'is_IE'      => $this->_is_IE(),
            'browser'    => $_SERVER['HTTP_USER_AGENT'],
            'message'    => null,
            'file'       => null,
            'showhack'   => false
        );

        $this->betterbrowser= $this->get_better_browser();
        if ($this->cnf['showhack'] !== false) {
            $hackwarn = 'ERROR: the loaded hash "'. $this->cnf['file'];
            $hackwarn.= '" seems to recommend Internet Explorer.<br/>';
            $hackwarn.= '<strong>This wiki installation may have been hacked!</strong>';
            msg($hackwarn, -1);
            return; // nothing more to do
        }
        // if not IE, nothing more to do
        if (!$this->cnf['is_IE'] ) return; // nothing more to be done

        $this->cnf['method'] = $this->getConf('method');
        $this->cnf['datasrc']= $this->getConf('source');
        $this->cnf['banner'] = $this->getLang('wedetect');
        // set up information

    }

    function getInfo () {
        $parts = explode('_',get_class($this));
        $file  = DOKU_PLUGIN.'/'.$parts[2].'/plugin.info.txt';
        $info  = array();
        if(!@file_exists($file)) {
            trigger_error('getInfo() not implemented in '.get_class($this).' and '.$info.' not found', E_USER_WARNING);
        }
        else {
            $info= confToHash($file);
            $lang= explode(',', $info['lang']);
            if (in_array('desc', $lang) && ''!==$this->getLang('plugininfo_desc')) $info['desc']= $this->getLang('plugininfo_desc');
        }
        return $info;
    }

    /***
     * Register its handlers with the DokuWiki's event controller
     */
    function register(Doku_Event_Handler $controller) {
        global $ACT;
        if ($ACT != 'show' || $this->cnf['showhack']===true) return;
        $controller->register_hook(
        'TPL_CONTENT_DISPLAY','BEFORE', $this, 'warning',array());

        // debug handler (should be disabled by default)
        //$controller->register_hook(
        //'TPL_CONTENT_DISPLAY','BEFORE', $this, '_debug');
    }


/*
  rendering options (from getConf)
  subsection   -> write the message as first content of wikipage
  notify       -> use the DokuWiki notification message area
  load_note    -> use the note plugin if available
  splash       -> use a JS+CSS splash screen (not available in this release)
*/
    function warning (Doku_Event $event, $param) {
        global $ID;
        global $INFO;
        global $ACT;
        static $done= false;

        // we do work only when IE is detected
        if (!$this->_is_IE() // if user is not using IE
        || $ACT!='show' // or we are not actually displaying a page
        ) { 
            $done= true;
            return; 
        }
        else {
            $emessage= $this->cnf['banner'];

            switch ($this->cnf['method']) {
            case 'notify': {
                $this->render_notify_($event, $param);
                break;
            }
            case 'note': {
                $this->render_note_($event, $param);
                break;
            }
            /* case not yet implemented
            case 'splash': {
                $this->render_splash_($event, $param);
                break;
            }
            */
            default: {
                // prepends the warning to the page output data
                //$event->data= $emessage. DW_LF. $event->data;
                $this->render_text_($event, $param);
                break;
            }

            } // end switch
            $done= true;
        } // end else (working against IE)

    // end function
    }


/**
 *******************************************************************
 * Helper Functions
 */

    /**
     * @fn      _is_IE
     * @brief   Attempts to detect Internet Explorer
     * @return  <tt>true</tt> if IE is detected, <tt>false</tt> otherwise
     */
    private function _is_IE () {
        $useragent= $_SERVER['HTTP_USER_AGENT'];
        if (strpos($useragent, 'MSIE') !== false)
            return true;
        else if (strpos($useragent, 'Trident/') !== false)
            return true;
        else if (strpos($useragent, 'Edge/') !== false)
            return true;
        else
            return false;    // end function
    }

    function render_text_ (Doku_Event $event, $param) {
        global $conf;
        $warn= p_render('xhtml', p_get_instructions($this->getLang('wedetect')), $info);
        $warn= '<div id="noiewarning"> '. $warn;

        if ($this->betterbrowser !== null && !empty($this->betterbrowser)) { // can't do a thing

            $url= $this->betterbrowser['url'];
            $favicon= htmlspecialchars( $this->betterbrowser['icon'] ? 'background-image: url('.$this->betterbrowser['icon'].') ;' : '' );
            $color= $this->betterbrowser['color'] ? 'border-bottom: 2px solid '. str_replace('%','#', $this->betterbrowser['color']). ';' : '';
            $werecommend= htmlspecialchars($this->getLang('werecommend'));
            $name= htmlspecialchars($this->betterbrowser['browser']);
            $warn= <<<EOF
$warn
<p>$werecommend <a href="$url" class="urlextern" style="$favicon $color">$name</a>.</p>
EOF;

        }
        $warn= $warn. DW_LF. '</div>'. DW_LF;
        $event->data = $warn.$event->data;
    }


    function render_notify_ (Doku_Event $event, $param) {
        global $conf;
        $warn= p_render('xhtml', p_get_instructions($this->getLang('wedetect')), $info);
        $warn= substr($warn, 4, -5);
        msg($warn, -1);

        if ($this->betterbrowser !== null && !empty($this->betterbrowser)) {

            $url= $this->betterbrowser['url'];
            $favicon= $this->betterbrowser['icon'] ? 'background-image: url('.$this->betterbrowser['icon'].') ;' : '';
            $name= htmlspecialchars($this->betterbrowser['browser']);
            $title= htmlspecialchars("Switch to ". $name);
            $werecommend= htmlspecialchars($this->getLang('werecommend'));
            $more= 'line-height: 1.6em; text-decoration: none; text-shadow: -1px -1px '. $this->betterbrowser['color']. ';'. $favicon;
            $reclink= <<<EOF
$werecommend <a href="$url" class="urlextern" rel="follow" title="$title" style="$more" >$name</a>
EOF;

            msg($reclink, 0);
        } // end if
    }

    function render_note_ (Doku_Event $event, $param) {
        $notehelper= &plugin_load('syntax', 'note');
        if (!$notehelper) {
            msg("noiewarning: the plugin (note) was selected as an assist, but not found.", -1);
        }
        global $conf;
        $warn = '<note warning>'.DW_LF. DW_LF;
        $warn.= $this->getLang('wedetect'). DW_LF;
        if ($this->betterbrowser !== null && !empty($this->betterbrowser)) { // can't do a thing
            $wrecc.= DW_LF. $this->getLang('werecommend');
            $url= $this->betterbrowser['url'];
            $name= $this->betterbrowser['browser'];
            
            $wrecc.= "[[${url}|${name}]] .". DW_LF;
            $warn.= $wrecc;
        }
        $warn.= '</note>'. DW_LF;
        
        $outp= p_render('xhtml', p_get_instructions($warn), $info);
        $event->data = $outp.$event->data;
    }

    function render_splash_ (Doku_Event $event, $param) {
    }


    function _debug (Doku_Event $event, $param) {
        global $ACT;
        $d .= '<pre> ACT: '. $ACT. DW_LF;
        if (!$this->betterbrowser) $d .= ' --- BADARRAY ---';
        else $d .= print_r ($this->betterbrowser, true);
        $d .= '</pre><br/>';
        $event->data = $d. $event->data;
    }
        

  /**
   * @fn    _getraw
   * @brief Loads the wikitext from a file, given its wikipage
   *
   * Technically just a wrapper on io_readfile, but as it is intended 
   * to grow and do specific parsing, will be separated here.
   */
    private function _getraw ($wikipage) {
    if (page_exists($page) ) {
        // start a renderer and pass it the warning wikipage
        $file  = wikiFN($page);
        $text  = io_readfile($file);
        }
    return $text;
    // end function
    }



    /**
     This function looks for a hash file called 
     DOKU_CONF/better-browser.txt, which contains info about a 
     recommended browser.
    **/
    private function get_better_browser ($id = '') {
        $hash= null;
        if ($id === '') $id= $this->getConf('better');
        // search recommend at $DOKU_CONF or browserlist path
        if ($id === 'custom') {
            $betterfile= DOKU_CONF. '/better-browser.txt';
            if (file_exists($betterfile)) {
                $hash= confToHash($betterfile);
                $this->cnf['file']= $id;
            }
            else $id= 'firefox';
        }
        if ($hash === null) {
            $betterfile= THIS_PLUGIN.'recommend/'.$id.'.txt';
            if (file_exists($betterfile)) {
                $hash= confToHash($betterfile);
                $this->cnf['file']= $id;
            }
        }
        //sanitize the hash, checking that there are no mentions of IE
        if ($hash === null) return $hash; // nothing more can be done
        if (in_array('IE', $hash)!==false 
        || in_array('Internet Explorer', $hash)!==false 
        || in_array('Microsoft', $hash)!==false
        || in_array('Edge/', $hash)!==false
        ) {
            $this->cnf['file']= $id. '(?)';
            // should NOT be recommending!
            $hash= null;
            //$hackwarn= htmlspecialchars($hackwarn);
            if ($this->cnf['showhack'] === false) { 
                $this->cnf['showhack']= true; 
            }
        }
        return $hash;
    }

}
