<?php
/**
 @file       nobadbrowser/action.php 
 @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 @author     Luis Machuca Bezzaza <lambalicious [at] tuta [dot] io>
**/
// 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.'nobadbrowser/');
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_nobadbrowser extends DokuWiki_Action_Plugin {

	// detected browser info
	var $binfo = array();
	// the plugin's data object
	var $cnf= array();

	function action_plugin_nobadbrowser () {
		//global $ID;		
		//global $ACT;
		global $bid;
		$this->cnf= array();
		$this->binfo= [];
	}

	/***
	 * Register its handlers with the DokuWiki's event controller
	 */
	function register (Doku_Event_Handler $controller) {
		global $ACT;
		if ($ACT != 'show') return;
		$controller->register_hook('TPL_CONTENT_DISPLAY','BEFORE', $this, 'warning',array());
	}


/*
  rendering options (from getConf)
  notify       -> use the DokuWiki notification message area
  splash       -> use a JS+CSS splash screen (not available in this release)
*/
	function warning (Doku_Event $event, $param) {
		global $ACT;
		static $done= false;

		if ($ACT!='show') {
			return;
		}

		$bc= extension_loaded('browscap');
		$with= $this->getConf('with_browscap');
		
		if ( $bc == false && $this->getConf('debug') == true ) {
			msg(<<<EOF
nobadbrowser notice: This PHP installation seems to lack ''browscap'' support. Results may be inconclusive.
EOF
, 2);
		}

		if ( $bc == true && $with == true ) {
			$this->binfo= get_browser(null, true);
		} else {
			$this->binfo= $this->get_browser_local($_SERVER['HTTP_USER_AGENT']);
			$this->binfo['browscap']= false;
		}
		$this->binfo['browscap']= $bc;
		$this->binfo['with']= $with;
		$this->binfo['_UA']= $_SERVER['HTTP_USER_AGENT'];


		if ($this->getConf['debug'] ?? false) {
			$this->render_debug($event, $param);
		}

		if ($this->whybadbrowser()) {
			$parameter= $this->cnf['parameter'];
			$reason= $this->cnf['reason'];
			$see= $this->cnf['see'];
			$mens = <<<EOF
You seem to be using a bad browser. \\\\ 
You are at risk because __${parameter}__ is: __${reason}__. 
Visit [[${see}|nobadbrowser @ DokuWiki]] for more details.
EOF;
			$outp= p_render('xhtml', p_get_instructions($mens), $info);
			msg(($outp), -1); 
		}
    // end function
    }


/**
 *******************************************************************
 * Helper Functions
 */


	function whybadbrowser () {

		// minimum and maximum acceptable versions, in format MAJOR*100+MINOR
		$minmaxversions= [
			'Edge' 	=> [null, null], 
			'Internet Explorer' 	=> [800, 900],
			'Opera' 	=> [1000, 1264],
			'Chrome' 	=> [null, null],
			'Firefox' 	=> [3800, 15000],
			'SeaMonkey' => [249, 300],
			'PaleMoon' 	=> [2500, 3000],
			'Safari' 	=> [null, null]
			];

		// Match Internet Explorer
		if (preg_match('/\bIE/', $this->binfo['browser']) && intval($this->binfo['version'])< 10 ) {
			$this->cnf= array(
				'parameter' => 'Browser old age', 
				'reason' => $this->binfo['browser'] . " " . $this->binfo['version'] ,
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#internet_explorer'
			);
			return true;
		}
		// ... or browsers made by Microsoft (incl. Edge)
		if (preg_match('/^Microsoft.*/', $this->binfo['browser_maker'])) {
			$this->cnf= array(
				'reason' => $this->binfo['browser_maker'] ,
				'parameter' => 'Browser Ecosystem', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#internet_explorer'
			);
			return true;
		}
		// Match Opera post-Presto
		if (preg_match('/^Opera/', $this->binfo['browser']) && intval($this->binfo['version'])>12 ) {
			$this->cnf= [
				'reason' => $this->binfo['browser'] . " " . $this->binfo['version'],
				'parameter' => 'Browser is a Chrome reskin', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#opera'
			];
			return true;
		}
		// Match Google Chrome
		if (preg_match('/\bChrome/', $this->binfo['browser'])) {
			$this->cnf= array(
				'reason' => $this->binfo['browser'] ,
				'parameter' => 'Browser', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
			);
			return true;
		}
		// ... or browsers made by Google (incl. Android WebView)
		if (preg_match('/^Google.*/', $this->binfo['browser_maker'])) {
			$this->cnf= array(
				'reason' => $this->binfo['browser_maker'] ,
				'parameter' => 'Browser Ecosystem', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
			);
			return true;
		}
		// ...or Chrome reskins
		if (preg_match('/\bChrome/', $this->binfo['parent']) ) {
			$this->cnf= array(
				'reason' => $this->binfo['parent'] ,
				'parameter' => 'Browser type', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
			);
			return true;
		}		
		// ...or Chrome reskins "trying to pass"
		if (preg_match('/.*Google Inc.*/', $this->binfo['renderingengine_maker']) ) {
			$this->cnf= array(
				'reason' => 'Chrome reskin' ,
				'parameter' => 'Browser type', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
			);
			return true;
		}
		// match browsers made by Apple
		if (preg_match('/^Safari/', $this->binfo['browser']) 
		|| preg_match('/^Apple/', $this->binfo['browser_maker']) ) {
			$this->cnf= [
				'reason' => $this->binfo['browser_maker'] ,
				'parameter' => 'Browser Ecosystem', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#apple'
			];
			return true;
		}
		// match browsers made by Facebook, for GAFAM completeness
		if (preg_match('/^Facebook/', $this->binfo['browser_maker']) ) {
			$this->cnf= [
				'reason' => $this->binfo['browser_maker'] ,
				'parameter' => 'Browser Ecosystem', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#facebook'
			];
			return true;
		}
		// match browsers made by Amazon, for GAFAM completeness
		if (preg_match('/^Amazon/', $this->binfo['browser_maker']) ) {
			$this->cnf= [
				'reason' => $this->binfo['browser_maker'] ,
				'parameter' => 'Browser Ecosystem', 
				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#amazon'
			];
			return true;
		}
		return false;
	}

	/**
	 * This function is an alternative to get_browser when not available.
	 * It does some parsing of the user agent string to provide acceptable, not necessarily accurate results, focused on returning five primary keys about the browser which are to concern for nobadbrowser :
	 * * browser
	 * * version
	 * * browser_maker
	 * * renderingengine_name
	 * * renderingengine_maker
	 * 
	 * Other keys that can also be of interest:
	 * 
	 * * renderingengine_version
	 * * parent
	 * 
	 * */
	function get_browser_local ($user_agent, $return_array=true) {
		$ret= [ 'browser' => 'generic', 'browser_maker' => 'generic', 'parent' => '', 'version' => '0' ];
		// Internet Explorer
		if (strpos($user_agent, 'MSIE') !== false) {
			$ret['browser']= 'IE';
			$ret['browser_maker']= 'Microsoft Corporation';
			if (preg_match ('#MSIE ([0-9\.]+);#', $user_agent, $browserversion) ) {
				$ret['version']= $browserversion[1];
				$ver= explode('.', $browserversion[1], 3);
				list($ret['majorver'], $ret['minorver'])= $ver;
				$ret['parent']= $ret['browser']. ' ' . $ret['majorver'];
			}			
			$ret['renderingengine_name']= 'Trident';
			$ret['renderingengine_maker']= 'Microsoft Corporation';
			if (preg_match ('#Trident/([0-9\.]+)#', $user_agent, $rendererversion) ) {
				$ret['renderingengine_version']= $rendererversion[1];
			}
		}
		// Google Chrome and its various derivations
		if (preg_match_all(
		'#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Chrome/([0-9]+\.[0-9]+).+Safari/[0-9\.]+\b(.*)$#'
		, $user_agent, $chrome_info) ) {
			$ret['browser']= 'Chrome';
			$ret['browser_maker']= 'Google Inc';
			$ret['version']= $chrome_info[1][0];
			$ret['parent']= 'Chrome';
			$variants= $chrome_info[2];
			//msg( print_r($variants, true), 2);
			if (count($variants) > 0 && (isset($variants[0]) ) && ($variants[0] != '') ) {
				//$ret['variant']= 1;
				$variant= explode('/', $variants[0]);
				$variantname= trim($variant[0]);
				$variantmaker= $ret['browser_maker'];
				if (false) {
				} else if ($variantname=='Edg') { 
					$variantname= 'Edge'; 
				} else if ($variantname=='OPR') { 
					$variantname= 'Opera'; $variantmaker= 'Opera Software ASA'; 
				} else if ($variantname=='uacq') {
					$variantname= 'User Agent Switcher';
				}
				$variantversion= explode('.', $variant[1],3);
				$variantversion= $variantversion[0].'.'.$variantversion[1];
				$ret['variant_found']= [ $variantname, $variantversion];
				$ret['browser']= $variantname;
				$ret['version']= $variantversion;
				$ret['browser_maker']= $variantmaker;
			}
			//list($ret['majorver'], $ret['minorver'])= explode('.', $chrome_info[1],3);
			$ret['renderingengine_name']= 'Blink';
			$ret['renderingengine_maker']= 'Google Inc';
			$ret['renderingengine_version']= '';
		}
		// Safari
		if (preg_match_all(
		'#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Version/([0-9]+\.[0-9]+).*Safari/([0-9]+\.[0-9]+).*#'
		, $user_agent, $safari_info) ) {
			$ret['browser']= 'Safari';
			$ret['browser_maker']= 'Apple Inc';
			$ret['version']= $safari_info[1][0];
			$ret['renderingengine_name']= 'WebKit';
			$ret['renderingengine_maker']= 'Apple Inc';
			$ret['renderingengine_version']= '';
		}
		// TODO: Facebook Browser
		if (preg_match_all(
		'#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Version/([0-9]+\.[0-9]+).*Safari/([0-9]+\.[0-9]+).*(FBAV|FBIOS).*#'
		, $user_agent, $facebook_info) ) {
			$ret['browser']= 'Facebook';
			$ret['browser_maker']= 'Facebook';
			$ret['version']= $facebook_info[1][0];
			$ret['renderingengine_name']= 'WebKit';
			$ret['renderingengine_maker']= 'Apple Inc';
			$ret['renderingengine_version']= '';
		}
		// Firefox and its variants
		if (preg_match_all(
		'#^Mozilla/[0-9\.]+.*Gecko/[0-9]+.+Firefox/([0-9]+\.[0-9]+).*$#'
		, $user_agent, $firefox_info) ) {
			$ret['browser']= 'Firefox';
			$ret['browser_maker']= 'Mozilla Foundation';
			$ret['version']= $firefox_info[1][0];
			$rendererversion= $ret['version'];
			$ret['renderingengine_name']= 'Gecko';
			$ret['renderingengine_maker']= 'Mozilla Foundation';
			$ret['renderingengine_version']= $rendererversion;
		}
		return $ret;
	}

	function render_debug (Doku_Event $event, $param) {
		$x= print_r($this->binfo, true);
		msg($x,3);
	}
	
}
