<?php
/**
 * プラグイン処理関係
 *
 * PHP versions 5
 *
 * LICENSE: This source file is licensed under the terms of the GNU General Public License.
 *
 * @package    Magic3 Framework
 * @author     平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
 * @copyright  Copyright 2006-2015 Magic3 Project.
 * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
 * @version    SVN: $Id$
 * @link       http://www.magic3.org
 */
// Copyright (C)
//   2002-2005 PukiWiki Developers Team
//   2001-2002 Originally written by yu-ji
// License: GPL v2 or (at your option) any later version

define('PKWK_PLUGIN_CALL_TIME_LIMIT', 768);

// Set global variables for plugins
function set_plugin_messages($messages)
{
	foreach ($messages as $name=>$val)
		if (! isset($GLOBALS[$name]))
			$GLOBALS[$name] = $val;
}

/**
 * プラグインの存在確認
 *
 * @param string $name			プラグイン名
 * @return bool					true=プラグイン存在する(ファイルが必要であればロードする)、false=存在しない
 */
function exist_plugin($name)
{
	static $exist = array(), $count = array();

	$page = WikiParam::getPage();
	$name = strtolower($name);
	if(isset($exist[$name])) {
		if (++$count[$name] > PKWK_PLUGIN_CALL_TIME_LIMIT){
			die('Alert: plugin "' . htmlspecialchars($name) . '" was called over ' . PKWK_PLUGIN_CALL_TIME_LIMIT .
			' times. SPAM or someting?<br />' . "\n" .
			'<a href="' . get_script_uri() . WikiParam::convQuery('?cmd=edit&amp;page='. rawurlencode($page)) . '">Try to edit this page</a><br />' . "\n" .
			'<a href="' . get_script_uri() . '">Return to frontpage</a>');
		}
		return $exist[$name];
	}
	if (preg_match('/^\w{1,64}$/', $name)){		// 文字と数字それにアンダースコア のいずれかにマッチ
	    if (file_exists(PLUGIN_DIR . $name . '.inc.php')) {
	    	$exist[$name] = TRUE;
	    	$count[$name] = 1;
			require_once(PLUGIN_DIR . $name . '.inc.php');
			return TRUE;
		}
		// 「dirname_xxxx」のプラグインの場合は「dirname」のサブディレクトリを検索
		$parsedName = explode('_', $name);
		$nameHead = $parsedName[0];
		
		$pluginDir = PLUGIN_DIR . $nameHead;
		if (is_dir($pluginDir) && file_exists($pluginDir . '/' . $name . '.inc.php')){		// プラグインファイルが存在するとき
	    	$exist[$name] = TRUE;
	    	$count[$name] = 1;
			require_once($pluginDir . '/' . $name . '.inc.php');
			return TRUE;
		} else {
		    $exist[$name] = FALSE;
		    $count[$name] = 1;
			return FALSE;
		}
	} else {
	    $exist[$name] = FALSE;
	    $count[$name] = 1;
		return FALSE;
	}
}
// プラグイン処理のための関数名は、「_action」,「_convert」,「_inline」,「_init」
// Check if plugin API 'action' exists
function exist_plugin_action($name) {
	return	function_exists('plugin_' . $name . '_action') ? TRUE : exist_plugin($name) ?
		function_exists('plugin_' . $name . '_action') : FALSE;
}

// Check if plugin API 'convert' exists
function exist_plugin_convert($name) {
	return	function_exists('plugin_' . $name . '_convert') ? TRUE : exist_plugin($name) ?
		function_exists('plugin_' . $name . '_convert') : FALSE;
}

// Check if plugin API 'inline' exists
function exist_plugin_inline($name) {
	return	function_exists('plugin_' . $name . '_inline') ? TRUE : exist_plugin($name) ?
		function_exists('plugin_' . $name . '_inline') : FALSE;
}

// Do init the plugin
function do_plugin_init($name)
{
	static $checked = array();

	if (isset($checked[$name])) return $checked[$name];

	$func = 'plugin_' . $name . '_init';
	if (function_exists($func)) {
		// TRUE or FALSE or NULL (return nothing)
		$checked[$name] = call_user_func($func);
	} else {
		$checked[$name] = NULL; // Not exist
	}

	return $checked[$name];
}

// Call API 'action' of the plugin
function do_plugin_action($name)
{
	if (! exist_plugin_action($name)) return array();

	if(do_plugin_init($name) === FALSE)
		die_message('Plugin init failed: ' . $name);

	$retvar = call_user_func('plugin_' . $name . '_action');

	return $retvar;
}

// Call API 'convert' of the plugin
function do_plugin_convert($name, $args = '')
{
	global $digest;

	// 出力抑止中のプラグインの場合は実行しない
	if (in_array($name, WikiConfig::getDispOffPlugin())) return '';
	
	if(do_plugin_init($name) === FALSE)
		return '[Plugin init failed: ' . $name . ']';

	if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK) {
		// Multiline plugin?
		$pos  = strpos($args, "\r"); // "\r" is just a delimiter
		if ($pos !== FALSE) {
			$body = substr($args, $pos + 1);
			$args = substr($args, 0, $pos);
		}
	}

	if ($args === '') {
		$aryargs = array();                 // #plugin()
	} else {
		$aryargs = csv_explode(',', $args); // #plugin(A,B,C,D)
	}
	if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK) {
		if (isset($body)) $aryargs[] = $body;     // #plugin(){{body}}
	}

	$_digest = $digest;
	$retvar  = call_user_func_array('plugin_' . $name . '_convert', $aryargs);
	$digest  = $_digest; // Revert

	if ($retvar === FALSE) {
		return htmlspecialchars('#' . $name .
			($args != '' ? '(' . $args . ')' : ''));
	} else {
		return $retvar;
	}
}

// Call API 'inline' of the plugin
function do_plugin_inline($name, $args, & $body)
{
	global $digest;

	// 出力抑止中のプラグインの場合は実行しない
	if (in_array($name, WikiConfig::getDispOffPlugin())) return '';
	
	if(do_plugin_init($name) === FALSE)
		return '[Plugin init failed: ' . $name . ']';

	if ($args !== '') {
		$aryargs = csv_explode(',', $args);
	} else {
		$aryargs = array();
	}

	// NOTE: A reference of $body is always the last argument
	$aryargs[] = $body; // func_num_args() != 0

	$_digest = $digest;
	$retvar  = call_user_func_array('plugin_' . $name . '_inline', $aryargs);
	$digest  = $_digest; // Revert

	if($retvar === FALSE) {
		// Do nothing
		return htmlspecialchars('&' . $name . ($args ? '(' . $args . ')' : '') . ';');
	} else {
		return $retvar;
	}
}
?>
