From 11e2ce226d64ac98b82ddc93a81eea66160bcc21 Mon Sep 17 00:00:00 2001
From: chris <chris@teacherscpd.co.uk>
Date: Thu, 25 Aug 2005 00:47:18 +0200
Subject: [PATCH] admin plugin i/face + acl plugin

darcs-hash:20050824224718-50fdc-6d27ff70e60e6fe547aff6c2b305507c4ab3f669.gz
---
 inc/actions.php           |  17 +-
 inc/html.php              |  39 +++-
 inc/template.php          |  32 ++-
 lib/plugins/acl/admin.php | 436 ++++++++++++++++++++++++++++++++++++++
 lib/plugins/admin.php     | 151 +++++++++++++
 5 files changed, 660 insertions(+), 15 deletions(-)
 create mode 100644 lib/plugins/acl/admin.php
 create mode 100644 lib/plugins/admin.php

diff --git a/inc/actions.php b/inc/actions.php
index 3322a81aa..97374578c 100644
--- a/inc/actions.php
+++ b/inc/actions.php
@@ -70,10 +70,21 @@ function act_dispatch(){
 
   //handle admin tasks
   if($ACT == 'admin'){
-		if($_REQUEST['page'] == 'acl'){
-			require_once(DOKU_INC.'inc/admin_acl.php');
-			admin_acl_handler();
+    // retrieve admin plugin name from $_REQUEST['page']
+    if ($_REQUEST['page']) {
+        $pluginlist = plugin_list('admin');
+        if (in_array($_REQUEST['page'], $pluginlist)) {     
+          // attempt to load the plugin
+          if ($plugin =& plugin_load('admin',$_REQUEST['page']) !== NULL)
+              $plugin->handle();
+        }
+    }         
+/*
+        if($_REQUEST['page'] == 'acl'){
+            require_once(DOKU_INC.'inc/admin_acl.php');
+            admin_acl_handler();
     }
+*/
   }
 
   //call template FIXME: all needed vars available?
diff --git a/inc/html.php b/inc/html.php
index 478770d3b..8ec445248 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -1065,11 +1065,6 @@ function html_debug(){
   print '</body></html>';
 }
 
-/**
- * Print the admin overview page
- *
- * @author  Andreas Gohr <andi@splitbrain.org>
- */
 function html_admin(){
   global $ID;
   global $lang;
@@ -1077,15 +1072,45 @@ function html_admin(){
 
   print p_locale_xhtml('admin');
 
-  ptln('<ul class="admin">');
+  // build menu of admin functions from the plugins that handle them
+  $pluginlist = plugin_list('admin');
+  $menu = array();
+  foreach ($pluginlist as $p) {
+    if($obj =& plugin_load('admin',$p) === NULL) continue;
+    $menu[] = array('plugin' => $p, 
+                    'prompt' => $obj->getMenuText($conf['lang']),
+                    'sort' => $obj->getMenuSort()
+                   );
+  }
+
+  usort($menu, p_sort_modes);
+
+  // output the menu
+  ptln('<ul>');
+
+  foreach ($menu as $item) {
+    if (!$item['prompt']) continue;
+    ptln('  <li><a href="'.wl($ID, 'do=admin&amp;page='.$item['plugin']).'">'.$item['prompt'].'</a></li>');
+  }
+
+  // add in non-plugin functions
+  if (!$conf['openregister']){
+    ptln('<li><a href="'.wl($ID,'do=register').'">'.$lang['admin_register'].'</a></li>');
+  }
+  
+  ptln('</ul>');
+
+/*
+  ptln('<ul>');  ptln('<ul class="admin">');
 
   // currently ACL only - more to come
   ptln('<li><a href="'.wl($ID,'do=admin&amp;page=acl').'">'.$lang['admin_acl'].'</a></li>');
   if (!$conf['openregister']){
     ptln('<li><a href="'.wl($ID,'do=register').'">'.$lang['admin_register'].'</a></li>');
   }
-  
+    
   ptln('</ul>');
+*/
 }
 
 
diff --git a/inc/template.php b/inc/template.php
index 518087e50..b033a82e0 100644
--- a/inc/template.php
+++ b/inc/template.php
@@ -129,13 +129,35 @@ function tpl_content(){
  * @author Andreas Gohr <andi@splitbrain.org>
  */
 function tpl_admin(){
+
+    $plugin = NULL;
+    if ($_REQUEST['page']) {
+        $pluginlist = plugin_list('admin');
+
+        if (in_array($_REQUEST['page'], $pluginlist)) {
+
+          // attempt to load the plugin
+          $plugin =& plugin_load('admin',$_REQUEST['page']);
+        }
+    }
+
+    if ($plugin !== NULL)
+        $plugin->html();
+    else
+        html_admin();
+/*
   switch($_REQUEST['page']){
-		case 'acl':
-			admin_acl_html();
-			break;
+        case 'acl':
+            admin_acl_html();
+            break;
+        case 'plugin':
+            require_once(DOKU_INC.'inc/admin_plugin.php');
+            admin_plugin_html();
+            break;
     default:
-			html_admin();
-	}
+            html_admin();
+    }
+*/    
 }
 
 /**
diff --git a/lib/plugins/acl/admin.php b/lib/plugins/acl/admin.php
new file mode 100644
index 000000000..c122edfe6
--- /dev/null
+++ b/lib/plugins/acl/admin.php
@@ -0,0 +1,436 @@
+<?php
+/**
+ * ACL administration functions
+ *
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Frank Schubert <frank@schokilade.de>
+ */
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
+require_once(DOKU_PLUGIN.'admin.php');
+ 
+/**
+ * All DokuWiki plugins to extend the admin function
+ * need to inherit from this class
+ */
+class admin_plugin_acl extends DokuWiki_Admin_Plugin {
+ 
+    /**
+     * return some info
+     */
+    function getInfo(){
+      return array(
+        'author' => 'Frank Schubert',
+        'email'  => 'frank@schokilade.de',
+        'date'   => '2005-08-08',
+        'name'   => 'ACL',
+        'desc'   => 'Manage Page Access Control Lists',
+        'url'    => 'http://wiki.splitbrain.org/wiki:acl',
+      );
+    }
+ 
+    /**
+     * return prompt for admin menu
+     */
+    function getMenuText($language) {
+        global $lang;
+        return $lang['admin_acl'];
+    }
+ 
+    /**
+     * return sort order for position in admin menu
+     */
+    function getMenuSort() {
+      return 1;
+    }
+ 
+    /**
+     * handle user request
+     */
+    function handle() {
+      global $AUTH_ACL;
+    
+      $cmd   = $_REQUEST['acl_cmd'];
+      $scope = $_REQUEST['acl_scope'];
+      $type  = $_REQUEST['acl_type'];
+      $user  = $_REQUEST['acl_user'];
+      $perm  = $_REQUEST['acl_perm'];
+    
+      if(is_array($perm)){
+        //use the maximum
+        sort($perm);
+        $perm = array_pop($perm);
+      }else{
+        $perm = 0;
+      }
+    
+      //sanitize
+      $user  = cleanID($user);
+      if($type == '@') $user = '@'.$user;
+      if($user == '@all') $user = '@ALL'; //special group! (now case insensitive)
+      $perm  = (int) $perm;
+      if($perm > AUTH_DELETE) $perm = AUTH_DELETE;
+      //FIXME sanitize scope!!!
+    
+      //nothing to do?
+      if(empty($cmd) || empty($scope) || empty($user)) return;
+    
+    
+      if($cmd == 'save'){
+        $this->admin_acl_del($scope, $user);
+        $this->admin_acl_add($scope, $user, $perm);  
+      }elseif($cmd == 'delete'){
+        $this->admin_acl_del($scope, $user);
+      }
+    
+      // reload ACL config
+      $AUTH_ACL = file(DOKU_CONF.'acl.auth.php');
+    }
+ 
+    /**
+     * ACL Output function
+     *
+     * print a table with all significant permissions for the
+     * current id
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     * @author  Andreas Gohr <andi@splitbrain.org>
+     */
+    function html() {
+      global $ID;
+    
+      print p_locale_xhtml('admin_acl');
+    
+      ptln('<div class="acladmin">');
+      ptln('<table class="inline">');
+    
+      //new
+      $this->admin_acl_html_new();
+    
+      //current config
+      $acls = $this->get_acl_config($ID);
+      foreach ($acls as $id => $acl){
+        $this->admin_acl_html_current($id,$acl); 
+      }
+    
+      ptln('</table>');
+      ptln('</div>');
+    }
+    
+ 
+    /**
+     * Get matching ACL lines for a page
+     *
+     * $ID is pagename, reads matching lines from $AUTH_ACL,
+     * also reads acls from namespace
+     * returns multi-array with key=pagename and value=array(user, acl)
+     *
+     * @todo    Fix comment to make sense
+     * @todo    should this moved to auth.php?
+     * @todo    can this be combined with auth_aclcheck to avoid duplicate code?
+     * @author  Frank Schubert <frank@schokilade.de>
+     */
+    function get_acl_config($id){
+      global $AUTH_ACL;
+      
+      $acl_config=array();
+      
+      // match exact name
+      $matches = preg_grep('/^'.$id.'\s+.*/',$AUTH_ACL);
+      if(count($matches)){
+        foreach($matches as $match){
+          $match = preg_replace('/#.*$/','',$match); //ignore comments
+          $acl   = preg_split('/\s+/',$match);
+          //0 is pagename, 1 is user, 2 is acl
+          $acl_config[$acl[0]][] = array( 'name' => $acl[1], 'perm' => $acl[2]);
+        }
+      }
+      
+      $specific_found=array();
+      // match ns
+      while(($id=getNS($id)) !== false){
+        $matches = preg_grep('/^'.$id.':\*\s+.*/',$AUTH_ACL);
+        if(count($matches)){
+          foreach($matches as $match){
+            $match = preg_replace('/#.*$/','',$match); //ignore comments
+            $acl   = preg_split('/\s+/',$match);
+            //0 is pagename, 1 is user, 2 is acl
+            $acl_config[$acl[0]][] = array( 'name' => $acl[1], 'perm' => $acl[2]);
+            $specific_found[]=$acl[1];
+          }
+        }
+      }
+      
+      //include *-config
+      $matches = preg_grep('/^\*\s+.*/',$AUTH_ACL);
+      if(count($matches)){
+        foreach($matches as $match){
+          $match = preg_replace('/#.*$/','',$match); //ignore comments
+          $acl   = preg_split('/\s+/',$match);
+          // only include * for this user if not already found in ns
+          if(!in_array($acl[1], $specific_found)){
+            //0 is pagename, 1 is user, 2 is acl
+            $acl_config[$acl[0]][] = array( 'name' => $acl[1], 'perm' => $acl[2]);
+          }
+        }
+      }
+      
+      //sort
+      //FIXME: better sort algo: first sort by key, then sort by first value
+      krsort($acl_config, SORT_STRING);
+     
+      return($acl_config);
+    }
+    
+    
+    /**
+     * adds new acl-entry to conf/acl.auth.php
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     */
+    function admin_acl_add($acl_scope, $acl_user, $acl_level){
+      $acl_config = join("",file(DOKU_CONF.'acl.auth.php'));
+      
+      // max level for pagenames is edit
+      if(strpos($acl_scope,'*') === false) {
+        if($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
+      }
+      
+      $new_acl = "$acl_scope\t$acl_user\t$acl_level\n";
+      
+      $new_config = $acl_config.$new_acl;
+      
+      return io_saveFile(DOKU_CONF.'acl.auth.php', $new_config);
+    }
+    
+    /**
+     * remove acl-entry from conf/acl.auth.php
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     */
+    function admin_acl_del($acl_scope, $acl_user){
+      $acl_config = file(DOKU_CONF.'acl.auth.php');
+    
+      $acl_pattern = '^'.preg_quote($acl_scope,'/').'\s+'.$acl_user.'\s+[0-8].*$';
+      
+      // save all non!-matching #FIXME invert is available from 4.2.0 only!
+      $new_config = preg_grep("/$acl_pattern/", $acl_config, PREG_GREP_INVERT);
+      
+      return io_saveFile(DOKU_CONF.'acl.auth.php', join('',$new_config));
+    }
+    
+    // --- HTML OUTPUT FUNCTIONS BELOW --- //
+    
+    /**
+     * print tablerows with the current permissions for one id
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     * @author  Andreas Gohr <andi@splitbrain.org>
+     */
+    function admin_acl_html_dropdown($id){
+      global $lang;
+      $cur = $id;
+      $ret = '';
+      $opt = array();
+    
+      //prepare all options
+    
+      // current page
+      $opt[] = array('key'=> $id, 'val'=> $id.' ('.$lang['page'].')');
+    
+      // additional namespaces
+      while(($id=getNS($id)) !== false){
+        $opt[] = array('key'=> $id.':*', 'val'=> $id.':* ('.$lang['namespace'].')');
+      }
+    
+      // the top namespace
+      $opt[] = array('key'=> '*', 'val'=> '* ('.$lang['namespace'].')');
+    
+      // set sel on second entry (current namespace)
+      $opt[1]['sel'] = ' selected="selected"';
+    
+      // flip options
+      $opt = array_reverse($opt);
+    
+      // create HTML
+      $att = array( 'name'  => 'acl_scope',
+                    'class' => 'edit',
+                    'title' => $lang['page'].'/'.$lang['namespace']);
+      $ret .= '<select '.html_attbuild($att).'>';
+      foreach($opt as $o){
+        $ret .= '<option value="'.$o['key'].'"'.$o['sel'].'>'.$o['val'].'</option>';
+      }
+      $ret .= '</select>';
+    
+      return $ret;
+    }
+    
+    /**
+     * print tablerows with the current permissions for one id
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     * @author  Andreas Gohr <andi@splitbrain.org>
+     */
+    function admin_acl_html_new(){
+      global $lang;
+      global $ID;
+    
+      // table headers
+      ptln('<tr>',2);
+      ptln('  <th class="leftalign" colspan="3">'.$lang['acl_new'].'</th>',2);
+      ptln('</tr>',2);
+    
+      ptln('<tr>',2);
+    
+      ptln('<td class="centeralign" colspan="3">',4);
+    
+      ptln('  <form method="post" action="'.wl($ID).'">',4);
+      ptln('    <input type="hidden" name="do"   value="admin" />',4);
+      ptln('    <input type="hidden" name="page" value="acl" />',4);
+      ptln('    <input type="hidden" name="acl_cmd" value="save" />',4);
+     
+      //scope select
+      ptln($lang['acl_perms'],4);
+      ptln($this->admin_acl_html_dropdown($ID),4); 
+    
+      $att = array( 'name'  => 'acl_type',
+                    'class' => 'edit',
+                    'title' => $lang['acl_user'].'/'.$lang['acl_group']);
+      ptln('    <select '.html_attbuild($att).'>',4);
+      ptln('      <option value="@">'.$lang['acl_group'].'</option>',4);
+      ptln('      <option value="">'.$lang['acl_user'].'</option>',4);
+      ptln('    </select>',4);
+    
+      $att = array( 'name'  => 'acl_user',
+                    'type'  => 'text',
+                    'class' => 'edit',
+                    'title' => $lang['acl_user'].'/'.$lang['acl_group']);
+      ptln('    <input '.html_attbuild($att).' />',4);
+      ptln('    <br />');
+    
+      ptln(     $this->admin_acl_html_checkboxes(0,false),8);
+    
+      ptln('    <input type="submit" class="edit" value="'.$lang['btn_save'].'" />',4);
+      ptln('  </form>');
+      ptln('</tr>',2);
+    }
+    
+    /**
+     * print tablerows with the current permissions for one id
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     * @author  Andreas Gohr <andi@splitbrain.org>
+     */
+    function admin_acl_html_current($id,$permissions){
+      global $lang;
+      global $ID;
+    
+      //is it a page?
+      if(substr($id,-1) == '*'){
+        $ispage = false;
+      }else{
+        $ispage = true;
+      }
+    
+      // table headers
+      ptln('  <tr>');
+      ptln('    <th class="leftalign" colspan="3">');
+      ptln($lang['acl_perms'],6);
+      if($ispage){
+        ptln($lang['page'],6);
+      }else{
+        ptln($lang['namespace'],6);
+      }
+      ptln('<em>'.$id.'</em>',6);
+      ptln('    </th>');
+      ptln('  </tr>');
+    
+      sort($permissions);
+    
+      foreach ($permissions as $conf){
+        //userfriendly group/user display
+        if(substr($conf['name'],0,1)=="@"){
+          $group = $lang['acl_group'];
+          $name  = substr($conf['name'],1);
+          $type  = '@';
+        }else{
+          $group = $lang['acl_user'];
+          $name  = $conf['name'];
+          $type  = '';
+        }
+    
+        ptln('<tr>',2);
+        ptln('<td class="leftalign">'.$group.' '.$name.'</td>',4);
+    
+        // update form
+        ptln('<td class="centeralign">',4);
+        ptln('  <form method="post" action="'.wl($ID).'">',4);
+        ptln('    <input type="hidden" name="do"   value="admin" />',4);
+        ptln('    <input type="hidden" name="page" value="acl" />',4);
+        ptln('    <input type="hidden" name="acl_cmd"   value="save" />',4);
+        ptln('    <input type="hidden" name="acl_scope" value="'.formtext($id).'" />',4);
+        ptln('    <input type="hidden" name="acl_type" value="'.$type.'" />',4);
+        ptln('    <input type="hidden" name="acl_user"  value="'.formtext($name).'" />',4);
+        ptln(     $this->admin_acl_html_checkboxes($conf['perm'],$ispage),8);
+        ptln('    <input type="submit" class="edit" value="'.$lang['btn_update'].'" />',4);
+        ptln('  </form>');
+        ptln('</td>',4);
+    
+    
+        // deletion form
+    
+        $ask  = $lang['del_confirm'].'\\n';
+        $ask .= $id.'  '.$conf['name'].'  '.$conf['perm'];
+        ptln('<td class="centeralign">',4);
+        ptln('  <form method="post" action="'.wl($ID).'" onsubmit="return confirm(\''.$ask.'\')">',4);
+        ptln('    <input type="hidden" name="do"        value="admin" />',4);
+        ptln('    <input type="hidden" name="page"      value="acl" />',4);
+        ptln('    <input type="hidden" name="acl_cmd"   value="delete" />',4);
+        ptln('    <input type="hidden" name="acl_scope" value="'.formtext($id).'" />',4);
+        ptln('    <input type="hidden" name="acl_type" value="'.$type.'" />',4);
+        ptln('    <input type="hidden" name="acl_user"  value="'.formtext($name).'" />',4);
+        ptln('    <input type="submit" class="edit" value="'.$lang['btn_delete'].'" />',4);
+        ptln('  </form>',4);
+        ptln('</td>',4);
+    
+        ptln('</tr>',2);
+      }
+    
+    }
+    
+    
+    /**
+     * print the permission checkboxes
+     *
+     * @author  Frank Schubert <frank@schokilade.de>
+     * @author  Andreas Gohr <andi@splitbrain.org>
+     */
+    function admin_acl_html_checkboxes($setperm,$ispage){
+      global $lang;
+    
+      static $label = 0; //number labels
+      $ret = '';
+    
+      foreach(array(AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm){
+        $label += 1;
+    
+        //general checkbox attributes
+        $atts = array( 'type'  => 'checkbox',
+                       'id'    => 'pbox'.$label,
+                       'name'  => 'acl_perm[]',
+                       'value' => $perm );
+        //dynamic attributes
+        if($setperm >= $perm) $atts['checked']  = 'checked';
+    #        if($perm > AUTH_READ) $atts['onchange'] = #FIXME JS to autoadd lower perms
+        if($ispage && $perm > AUTH_EDIT) $atts['disabled'] = 'disabled';
+    
+        //build code
+        $ret .= '<label for="pbox'.$label.'" title="'.$lang['acl_perm'.$perm].'">';
+        $ret .= '<input '.html_attbuild($atts).' />';
+        $ret .= $lang['acl_perm'.$perm];
+        $ret .= "</label>\n";
+      }
+      return $ret;
+    }
+    
+}
\ No newline at end of file
diff --git a/lib/plugins/admin.php b/lib/plugins/admin.php
new file mode 100644
index 000000000..805689f2a
--- /dev/null
+++ b/lib/plugins/admin.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * Admin Plugin Prototype
+ * 
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Christopher Smith <chris@jalakai.co.uk>
+ */
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
+
+/**
+ * All DokuWiki plugins to extend the admin function
+ * need to inherit from this class
+ */
+class DokuWiki_Admin_Plugin {
+
+  var $localised = false;
+  var $lang = array();
+
+  /**
+   * General Info
+   *
+   * Needs to return a associative array with the following values:
+   *
+   * author - Author of the plugin
+   * email  - Email address to contact the author
+   * date   - Last modified date of the plugin in YYYY-MM-DD format
+   * name   - Name of the plugin
+   * desc   - Short description of the plugin (Text only)
+   * url    - Website with more information on the plugin (eg. syntax description)
+   */
+  function getInfo(){
+    trigger_error('getInfo() not implemented in '.get_class($this), E_USER_WARNING);
+  }
+
+  function getMenuText($language) {
+      return $this->getLang('menu');
+  }
+
+  function getMenuSort() {
+    return 1000;
+  }
+
+  function handle() {
+    trigger_error('handle() not implemented in '.get_class($this), E_USER_WARNING); 
+  }
+
+  function html() {
+    trigger_error('html() not implemented in '.get_class($this), E_USER_WARNING); 
+  }
+  
+  // private methods (maybe a dokuwiki plugin base class is required for these)
+  
+  // plugin introspection methods
+  // extract from class name, format = <plugin type>_plugin_<name>[_<component name>]
+  function getPluginType() { list($t) = explode('_', get_class($this), 2); return $t;  }
+  function getPluginName() { list($t, $p, $n) = explode('_', get_class($this), 4); return $n; }
+  function getPluginComponent() { list($t, $p, $n, $c) = explode('_', get_class($this), 4); return (isset($c)?$c:''); }
+  
+  function setupLocale() {
+    global $conf;            // definitely don't invoke "global $lang"
+    $path = DOKU_PLUGIN.$this->getPluginName().'/lang/';
+    
+    // don't include once, in case several plugin components require the same language file
+    @include($path.'en/lang.php');    
+    if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
+    
+    $this->lang = $lang;
+    $this->localised = true;
+  }
+  
+  // plugin equivalent of localFN()
+  function plugin_localFN($id) {
+    global $conf;
+    $plugin = $this->getPluginName();
+    $file = DOKU_PLUGIN.$plugin.'/lang/'.$conf['lang'].'/'.$id.'.txt';
+    if(!@file_exists($file)){
+      //fall back to english
+      $file = DOKU_PLUGIN.$plugin.'inc/lang/en/'.$id.'.txt';
+    }
+  return $file;
+  }
+  
+  // use this function to access plugin language strings
+  // to try to minimise unnecessary loading of the strings when the plugin doesn't require them
+  // e.g. when info plugin is querying plugins for information about themselves.
+  function getLang($id) {
+    if (!$this->localised) $this->setupLocale();
+    
+    return (isset($this->lang[$id]) ? $this->lang[$id] : '');
+  }
+  
+  // plugin equivalent of p_locale_xhtml()
+  function plugin_locale_xhtml($id) {
+    return p_cached_xhtml($this->plugin_localFN($id));
+  }
+  
+  // standard functions for outputing email addresses and links
+  // use these to avoid having to duplicate code to produce links in line with the installation configuration
+  function plugin_email($email, $name='', $class='', $more='') {
+    if (!$email) return $name;
+    $email = $this->obfuscate($email);
+    if (!$name) $name = $email;
+    $class = "class='".($class ? $class : 'mail')."'";
+    return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
+  }
+  
+  function plugin_link($link, $title='', $class='', $target='', $more='') {
+    global $conf;
+    
+    $link = htmlentities($link);
+    if (!$title) $title = $link;
+    if (!$target) $target = $conf['target']['extern'];
+    if ($conf['relnofollow']) $more .= ' rel="nofollow"';
+    
+    if ($class) $class = " class='$class'";
+    if ($target) $target = " target='$target'";
+    if ($more) $more = " ".trim($more);
+                
+    return "<a href='$link'$class$target$more>$title</a>";
+  }
+                
+  // output text string through the parser, allows dokuwiki markup to be used
+  // very ineffecient for small pieces of data - try not to use
+  function plugin_render($text, $format='xhtml') {
+    return p_render($format, p_get_instructions($text),$info); 
+  }
+    
+  // return an obfuscated email address in line with $conf['mailguard'] setting
+  // FIXME?? this should really be a common function, used by the renderer as well - no point maintaining two!
+  function obfuscate($email) {
+    global $conf;
+    
+    switch ($conf['mailguard']) {
+        case 'visible' :
+            $obfuscate = array('@' => '[at]', '.' => '[dot]', '-' => '[dash]');
+            return strtr($email, $obfuscate);
+            
+        case 'hex' :
+            $encode = '';
+            for ($x=0; $x < strlen($email); $x++) $encode .= '&#x' . bin2hex($email{$x}).';';
+            return $encode;
+            
+        case 'none' :
+        default :
+            return $email;
+    }            
+  }
+
+}
+//Setup VIM: ex: et ts=4 enc=utf-8 :
-- 
GitLab