*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
// todo
// - maintain a history of file modified
// - allow a plugin to contain extras to be copied to the current template (extra/tpl/)
// - to images (lib/images/) [ not needed, should go in lib/plugin/images/ ]
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'admin.php');
//--------------------------[ GLOBALS ]------------------------------------------------
// note: probably should be dokuwiki wide globals, where they can be accessed by pluginutils.php
// global $plugin_types;
// $plugin_types = array('syntax', 'admin');
// plugins that are an integral part of dokuwiki, they shouldn't be disabled or deleted
global $plugin_protected;
$plugin_protected = array('acl','plugin','config','info','usermanager');
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
*/
class admin_plugin_plugin extends DokuWiki_Admin_Plugin {
var $disabled = 0;
var $plugin = '';
var $cmd = '';
var $handler = NULL;
var $functions = array('delete','update',/*'settings',*/'info'); // require a plugin name
var $commands = array('manage','download','enable'); // don't require a plugin name
var $plugin_list = array();
var $msg = '';
var $error = '';
function admin_plugin_plugin() {
global $conf;
$this->disabled = (isset($conf['pluginmanager']) && ($conf['pluginmanager'] == 0));
}
/**
* return some info
*/
function getInfo(){
$disabled = ($this->disabled) ? '(disabled)' : '';
return array(
'author' => 'Christopher Smith',
'email' => 'chris@jalakai.co.uk',
'date' => '2005-08-10',
'name' => 'Plugin Manager',
'desc' => "Manage Plugins, including automated plugin installer $disabled",
'url' => 'http://wiki.splitbrain.org/plugin:adminplugin',
);
}
/**
* return prompt for admin menu
*/
function getMenuText($language) {
if (!$this->disabled)
return parent::getMenuText($language);
return '';
}
/**
* return sort order for position in admin menu
*/
function getMenuSort() {
return 20;
}
/**
* handle user request
*/
function handle() {
if ($this->disabled) return;
// enable direct access to language strings
$this->setupLocale();
// $this->plugin = $_REQUEST['plugin'];
// $this->cmd = $_REQUEST['fn'];
// if (is_array($this->cmd)) $this->cmd = key($this->cmd);
$fn = $_REQUEST['fn'];
if (is_array($fn)) {
$this->cmd = key($fn);
$this->plugin = is_array($fn[$this->cmd]) ? key($fn[$this->cmd]) : null;
} else {
$this->cmd = $fn;
$this->plugin = null;
}
$this->plugin_list = plugin_list('', true);
sort($this->plugin_list);
// verify $_REQUEST vars
if (in_array($this->cmd, $this->commands)) {
$this->plugin = '';
} else if (!in_array($this->cmd, $this->functions) || !in_array($this->plugin, $this->plugin_list)) {
$this->cmd = 'manage';
$this->plugin = '';
}
// create object to handle the command
$class = "ap_".$this->cmd;
if (!class_exists($class)) $class = 'ap_manage';
$this->handler = & new $class($this, $this->plugin);
$this->msg = $this->handler->process();
}
/**
* output appropriate html
*/
function html() {
if ($this->disabled) return;
// enable direct access to language strings
$this->setupLocale();
if ($this->handler === NULL) $this->handler = & new ap_manage($this, $this->plugin);
if (!$this->plugin_list) {
$this->plugin_list = plugin_list('',true);
sort($this->plugin_list);
}
ptln('
');
$this->handler->html();
ptln('
');
}
}
class ap_manage {
var $manager = NULL;
var $lang = array();
var $plugin = '';
var $downloaded = array();
function ap_manage(&$manager, $plugin) {
$this->manager = & $manager;
$this->plugin = $plugin;
$this->lang = & $manager->lang;
}
function process() {
return '';
}
function html() {
print $this->manager->locale_xhtml('admin_plugin');
$this->html_menu();
}
// build our standard menu
function html_menu($listPlugins = true) {
global $ID;
ptln('
');
ptln('
');
ptln('
'.$this->lang['download'].'
');
ptln(' ');
ptln('
');
if ($listPlugins) {
ptln('
'.$this->lang['manage'].'
');
ptln('');
}
ptln('
');
}
function html_pluginlist() {
global $ID;
global $plugin_protected;
foreach ($this->manager->plugin_list as $plugin) {
$disabled = plugin_isdisabled($plugin);
$protected = in_array($plugin,$plugin_protected);
$checked = ($disabled) ? '' : ' checked="checked"';
$check_disabled = ($protected) ? ' disabled="disabled"' : '';
// determine display class(es)
$class = array();
if (in_array($plugin, $this->downloaded)) $class[] = 'new';
if ($disabled) $class[] = 'disabled';
if ($protected) $class[] = 'protected';
$class = count($class) ? ' class="'.join(' ', $class).'"' : '';
ptln(' ');
}
}
function html_button($plugin, $btn, $disabled=false, $indent=0) {
$disabled = ($disabled) ? 'disabled="disabled"' : '';
ptln('',$indent);
}
/**
* Refresh plugin list
*/
function refresh() {
$this->manager->plugin_list = plugin_list('',true);
sort($this->manager->plugin_list);
// expire dokuwiki caches
// touching local.php expires wiki page, JS and CSS caches
@touch(DOKU_CONF.'local.php');
// update latest plugin date - FIXME
return (!$this->manager->error);
}
function download($url, $overwrite=false) {
global $lang;
// check the url
$matches = array();
if (!preg_match("/[^\/]*$/", $url, $matches) || !$matches[0]) {
$this->manager->error = $this->lang['error_badurl']."\n";
return false;
}
$file = $matches[0];
$folder = "p".md5($file.date('r')); // tmp folder name - will be empty (should really make sure it doesn't already exist)
$tmp = DOKU_PLUGIN."tmp/$folder";
if (!ap_mkdir($tmp)) {
$this->manager->error = $this->lang['error_dir_create']."\n";
return false;
}
if (!$file = io_download($url, "$tmp/", true, $file)) {
$this->manager->error = sprintf($this->lang['error_download'],$url)."\n";
}
if (!$this->manager->error && !ap_decompress("$tmp/$file", $tmp)) {
$this->manager->error = sprintf($this->lang['error_decompress'],$file)."\n";
}
// search tmp/$folder for the folder(s) that has been created
// move that folder(s) to lib/plugins/
if (!$this->manager->error) {
if ($dh = @opendir("$tmp/")) {
while (false !== ($f = readdir($dh))) {
if ($f == '.' || $f == '..' || $f == 'tmp') continue;
if (!is_dir("$tmp/$f")) continue;
// check to make sure we aren't overwriting anything
if (!$overwrite && @file_exists(DOKU_PLUGIN."/$f")) {
// remember our settings, ask the user to confirm overwrite, FIXME
continue;
}
$instruction = @file_exists(DOKU_PLUGIN."/$f") ? 'update' : 'install';
if (ap_copy("$tmp/$f", DOKU_PLUGIN.$f)) {
$this->downloaded[] = $f;
$this->plugin_writelog($f, $instruction, array($url));
} else {
$this->manager->error .= sprintf($lang['error_copy']."\n", $f);
}
}
closedir($dh);
} else {
$this->manager->error = $this->lang['error']."\n";
}
}
// cleanup
if ($folder && is_dir(DOKU_PLUGIN."tmp/$folder")) ap_delete(DOKU_PLUGIN."tmp/$folder");
if (!$this->manager->error) {
$this->refresh();
return true;
}
return false;
}
// log
function plugin_writelog($plugin, $cmd, $data) {
$file = DOKU_PLUGIN.$plugin.'/manager.dat';
switch ($cmd) {
case 'install' :
$url = $data[0];
$date = date('r');
if (!$fp = @fopen($file, 'w')) return;
fwrite($fp, "installed=$date\nurl=$url\n");
fclose($fp);
break;
case 'update' :
$date = date('r');
if (!$fp = @fopen($file, 'a')) return;
fwrite($fp, "updated=$date\n");
fclose($fp);
break;
}
}
function plugin_readlog($plugin, $field) {
static $log = array();
$file = DOKU_PLUGIN.$plugin.'/manager.dat';
if (!isset($log[$plugin])) {
$tmp = @file_get_contents($file);
if (!$tmp) return '';
$log[$plugin] = & $tmp;
}
if ($field == 'ALL') {
return $log[$plugin];
}
$match = array();
if (preg_match_all('/'.$field.'=(.*)$/m',$log[$plugin], $match))
return implode("\n", $match[1]);
return '';
}
}
class ap_download extends ap_manage {
var $overwrite = false;
function process() {
global $lang;
$plugin_url = $_REQUEST['url'];
$this->download($plugin_url, $this->overwrite);
return '';
}
function html() {
parent::html();
ptln('
');
ptln('
'.$this->lang['downloading'].'
');
if ($this->manager->error) {
ptln('
'.str_replace("\n"," ",$this->manager->error).'
');
} else if (count($this->downloaded) == 1) {
ptln('
");
}
// simple output filter, make html entities safe and convert new lines to
function out($text) {
return str_replace("\n",' ',htmlentities($text));
}
}
//--------------[ to do ]---------------------------------------
class ap_update extends ap_manage {
var $overwrite = true;
function process() {
global $lang;
$plugin_url = $this->plugin_readlog($this->plugin, 'url');
$this->download($plugin_url, $this->overwrite);
return '';
}
function html() {
parent::html();
ptln('
');
ptln('
'.$this->lang['updating'].'
');
if ($this->manager->error) {
ptln('
'.str_replace("\n"," ", $this->manager->error).'
');
} else if (count($this->downloaded) == 1) {
ptln('