changeset 309:e39e57029aa9

php-admin
author mmj
date Wed, 01 Sep 2004 18:19:00 +1000
parents 5582a75b0a2a
children 659a9d0d932f
files contrib/web/php-admin/README contrib/web/php-admin/conf/config.php contrib/web/php-admin/conf/tunables.php contrib/web/php-admin/htdocs/class.FastTemplate.php contrib/web/php-admin/htdocs/dot.htaccess contrib/web/php-admin/htdocs/edit.php contrib/web/php-admin/htdocs/index.php contrib/web/php-admin/htdocs/save.php contrib/web/php-admin/templates/edit.html contrib/web/php-admin/templates/edit_boolean.html contrib/web/php-admin/templates/edit_list.html contrib/web/php-admin/templates/edit_string.html contrib/web/php-admin/templates/index.html contrib/web/php-admin/templates/save.html
diffstat 14 files changed, 1123 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/README	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,28 @@
+mlmmj-1.0.0                                                  August 31th 2004
+
+To use this web-interface you have to:
+
+1) Copy the files from the php-admin directory of the mlmmj distribution to a
+   suitable location and point your webroot to the htdocs directory. If you
+   don't want the webinterface in the root of your website it is recommended to
+   make an alias in your web server configuration in order to keep the conf
+   directory at the same level as the htdocs directory and still outside
+   webscope.
+
+2) Change the permissions of the listdir/control directories of any list you
+   want to control using the web-interface, so the web server can write in it:
+
+     # chown -R wwwrun /var/spool/mlmmj/mlmmj-test/control/
+
+To enable access control on Apache you have to:
+
+3) Rename dot.htaccess to .htaccess and edit the path inside the file to point
+   to a htpasswd file somewhere outside the webscope.
+
+   If you don't have one already, you can create one like this
+
+      htpasswd -c /home/mlmmj/htpasswd USER
+
+   It will then ask you for a password for the given username.
+
+4) That is it, you are ready to use the interface.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/conf/config.php	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,6 @@
+<?php
+
+$topdir = "/var/spool/mlmmj";
+$templatedir = "/home/mlmmj/templates";
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/conf/tunables.php	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,65 @@
+<?php
+
+mlmmj_boolean("closedlist",
+			  "Closed list",
+			  "If this option is set, subscribtion and unsubscription via mail is disabled.");
+
+mlmmj_boolean("moderated",
+			  "Moderated",
+			  "If this option is set, the emailaddresses in the file listdir/control/moderators will act as moderators for the list.");
+
+mlmmj_list("moderators",
+		   "Moderators",
+		   "If the list is moderated, this is the list of moderators.");
+
+mlmmj_boolean("tocc",
+			  "To: Cc:",
+			  "If this option is set, the list address does not have to be in the To: or Cc: header of the email to the list.");
+
+mlmmj_boolean("addtohdr",
+			  "Add To: header",
+			  "If this option is set, a To: header including the recipients emailaddress will be added to outgoing mail. ".
+			  "Recommended usage is to remove existing To: headers with delheaders (see below) first.");
+
+mlmmj_boolean("subonlypost",
+			  "Subscribers only post",
+			  "If this option is set, only people who are subscribed to the list, are allowed to post to it. ".
+			  "The check is made against the \"From:\" header.");
+
+mlmmj_string("prefix",
+			 "Prefix",
+			 "The prefix for the Subject: line of mails to the list. This will alter the Subject: line, ".
+			 "and add a prefix if it's not present elsewhere.");
+
+mlmmj_list("owner",
+		   "Owner",
+		   "The emailaddresses in this list will get mails to ".htmlentities($list)."+owner");
+
+mlmmj_list("delheaders",
+		   "Delete headers",
+		   "In this file is specified *ONE* headertoken to match pr. line. ".
+		   "If the file consists of: Received: Message-ID: Then all occurences of these headers in incoming list mail will be deleted. ".
+		   "\"From \" and \"Return-Path:\" are deleted no matter what.");
+
+mlmmj_list("access",
+		   "Access",
+		   "If this option is set, all headers of a post to the list is matched against the rules. The first rule to match wins. ".
+		   "See README.access for syntax and examples. NOTE: If this field is empty access control is *disabled*, ".
+		   "unlike having an empty control/access file.");
+
+mlmmj_string("memorymailsize",
+			 "Memory mail size",
+			 "Here is specified in bytes how big a mail can be and still be prepared for sending in memory. ".
+			 "It's greatly reducing the amount of write system calls to prepare it in memory before sending it, ".
+			 "but can also lead to denial of service attacks. Default is 16k (16384 bytes).");
+
+mlmmj_string("relayhost",
+			 "Relay host",
+			 "The host specified (IP address og domainname, both works) in this file will be used for relaying the mail sent to the list. ".
+			 "Defaults to 127.0.0.1.");
+
+mlmmj_boolean("notifysub",
+			  "Notify subscribers",
+			  "If this option is set, the owner(s) will get a mail with the address of someone sub/unsubscribing to a mailinglist.");
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/htdocs/class.FastTemplate.php	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,737 @@
+<?php
+
+/* class.FastTemplate.php
+ *
+ * Original Perl module CGI::FastTemplate by Jason Moore
+ * Copyright (c) 1998, Jason Moore <jmoore at sober dot com>
+ *
+ * PHP3 port by CDI
+ * Copyright (c) 1999 CDI <cdi at thewebmasters dot net>
+ *
+ * PHP4 support added by Christoph Thiel for mlmmj's php-admin
+ * Copyright (c) 2004 Christoph Thiel <ct at kki dot org>
+ *
+ * This program is released under the General Artistic License.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the GNU General Artistic License, with the following stipulations;
+ *
+ * Changes or modifications must retain these Copyright statements. Changes or
+ * modifications must be submitted to all AUTHORS.
+ *
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the Artistic License for more
+ * details. This software is distributed AS-IS.
+ */
+
+class FastTemplate {
+
+    var $FILELIST = array();   /* Holds the array of filehandles
+				* FILELIST[HANDLE] == "fileName" 
+				*/
+
+    var $DYNAMIC = array();    /* Holds the array of dynamic
+				* blocks, and the fileHandles they
+				* live in. 
+				*/
+
+    var $PARSEVARS = array();	/* Holds the array of Variable
+				 * handles.
+				 * PARSEVARS[HANDLE] == "value"
+				 */
+
+    var $LOADED	= array();	/* We only want to load a template
+				 * once - when it's used.
+				 * LOADED[FILEHANDLE] == 1 if loaded
+				 * undefined if not loaded yet.
+				 */
+   
+    var	$HANDLE	= array();	/* Holds the handle names assigned
+				 * by a call to parse()
+				 */
+    
+    var	$ROOT =	"";             /* Holds path-to-templates */
+    
+    var $ERROR = "";		/* Holds the last error message */
+    
+    var $LAST =	"";		/* Holds the HANDLE to the last
+				 * template parsed by parse()
+				 */
+    
+    var $STRICT	= true;		/* Strict template checking.
+				 * Unresolved vars in templates will
+				 * generate a warning when found.
+				 */
+    
+/******************************************************************************/
+    
+    function FastTemplate($pathToTemplates = "")
+	{
+	    global $php_errormsg;
+	    
+	    if(!empty($pathToTemplates))
+	    {
+		$this->set_root($pathToTemplates);
+	    }
+	    
+	}
+    
+    /* 
+     * All templates will be loaded from this "root" directory
+     * Can be changed in mid-process by re-calling with a new
+     * value.
+     */
+    
+    function set_root($root)
+	{
+	    $trailer = substr($root,-1);
+	    
+	    if( (ord($trailer)) != 47 )
+	    {
+		$root = "$root". chr(47);
+	    }
+	    
+	    if(is_dir($root))
+	    {
+		$this->ROOT = $root;
+	    }
+	    else
+	    {
+		$this->ROOT = "";
+		$this->error("Specified ROOT dir [$root] is not a directory");
+	    }
+	}
+
+
+    /* Calculates current microtime
+     * I throw this into all my classes for benchmarking purposes
+     * It's not used by anything in this class and can be removed
+     * if you don't need it.
+     */
+
+    function utime()
+	{
+	    $time = explode( " ", microtime());
+	    $usec = (double)$time[0];
+	    $sec = (double)$time[1];
+	    return $sec + $usec;
+	}
+
+
+    /* Strict template checking, if true sends warnings to STDOUT when
+     * parsing a template with undefined variable references
+     * Used for tracking down bugs-n-such. Use no_strict() to disable.
+     */
+    
+    function strict()
+	{
+	    $this->STRICT = true;
+	}
+
+    
+    /* Silently discards (removes) undefined variable references
+     * found in templates
+     */
+    
+    function no_strict()
+	{
+	    $this->STRICT = false;
+	}
+
+
+    /* A quick check of the template file before reading it.
+     * This is -not- a reliable check, mostly due to inconsistencies
+     * in the way PHP determines if a file is readable.
+     */
+    
+    function is_safe($filename)
+	{
+	    if(!file_exists($filename))
+	    {
+		$this->error("[$filename] does not exist",0);
+		return false;
+	    }
+	    return true;
+	}
+
+
+    /* Grabs a template from the root dir and 
+     * reads it into a (potentially REALLY) big string
+     */
+
+    function get_template($template)
+	{
+	    if(empty($this->ROOT))
+	    {
+		$this->error("Cannot open template. Root not valid.",1);
+		return false;
+	    }
+	    
+	    $filename	=	"$this->ROOT"."$template";
+	    
+	    $contents = implode("",(@file($filename)));
+	    if( (!$contents) or (empty($contents)) )
+	    {
+		$this->error("get_template() failure: [$filename] $php_errormsg",1);
+	    }
+	    
+	    return $contents;
+	    
+	}
+
+
+    /* Prints the warnings for unresolved variable references
+     * in template files. Used if STRICT is true
+     */
+
+    function show_unknowns($Line)
+	{
+	    $unknown = array();
+	    if (ereg("(\{[A-Z0-9_]+\})",$Line,$unknown))
+	    {
+		$UnkVar = $unknown[1];
+		if(!(empty($UnkVar)))
+		{
+		    @error_log("[FastTemplate] Warning: no value found for variable: $UnkVar ",0);
+		}
+	    }
+	}
+    
+
+    /* This routine get's called by parse() and does the actual
+     * {VAR} to VALUE conversion within the template.
+     */
+
+    function parse_template($template, $tpl_array)
+	{
+	    while ( list ($key,$val) = each ($tpl_array) )
+	    {
+		if (!(empty($key)))
+		{
+		    if(gettype($val) != "string")
+		    {
+			settype($val,"string");
+		    }
+		    
+		    $template = ereg_replace("\{$key\}","$val","$template");
+		    //$template = str_replace("{$key}","$val","$template");
+		}
+	    }
+	    
+	    if(!$this->STRICT)
+	    {
+		// Silently remove anything not already found
+		
+		$template = ereg_replace("\{([A-Z0-9_]+)\}","",$template);
+	    }
+	    else
+	    {
+		// Warn about unresolved template variables
+		if (ereg("({[A-Z0-9_]+})",$template))
+		{
+		    $unknown = split("\n",$template);
+		    while (list ($Element,$Line) = each($unknown) )
+		    {
+			$UnkVar = $Line;
+			if(!(empty($UnkVar)))
+			{
+			    $this->show_unknowns($UnkVar);
+			}
+		    }
+		}
+	    }
+	    return $template;
+	    
+	}
+    
+
+    /* The meat of the whole class. The magic happens here. */
+
+    function parse($ReturnVar, $FileTags)
+	{
+	    $append = false;
+	    $this->LAST = $ReturnVar;
+	    $this->HANDLE[$ReturnVar] = 1;
+	    
+	    if (gettype($FileTags) == "array")
+	    {
+		unset($this->$ReturnVar);	// Clear any previous data
+		
+		while ( list ( $key , $val ) = each ( $FileTags ) )
+		{
+		    if ( (!isset($this->$val)) || (empty($this->$val)) )
+		    {
+			$this->LOADED["$val"] = 1;
+			if(isset($this->DYNAMIC["$val"]))
+			{
+			    $this->parse_dynamic($val,$ReturnVar);
+			}
+			else
+			{
+			    $fileName = $this->FILELIST["$val"];
+			    $this->$val = $this->get_template($fileName);
+			}
+		    }
+		    
+		    //	Array context implies overwrite
+		    
+		    $this->$ReturnVar = $this->parse_template($this->$val,$this->PARSEVARS);
+		    
+		    //	For recursive calls.
+		    
+		    $this->assign( array( $ReturnVar => $this->$ReturnVar ) );
+		    
+		}
+	    }	// end if FileTags is array()
+	    else
+	    {
+		// FileTags is not an array
+		
+		$val = $FileTags;
+		
+		if( (substr($val,0,1)) == '.' )
+		{
+		    // Append this template to a previous ReturnVar
+		    
+		    $append = true;
+		    $val = substr($val,1);
+		}
+		
+		if ( (!isset($this->$val)) || (empty($this->$val)) )
+		{
+		    $this->LOADED["$val"] = 1;
+		    if(isset($this->DYNAMIC["$val"]))
+		    {
+			$this->parse_dynamic($val,$ReturnVar);
+		    }
+		    else
+		    {
+			$fileName = $this->FILELIST["$val"];
+			$this->$val = $this->get_template($fileName);
+		    }
+		}
+		
+		if($append)
+		{
+		    $this->$ReturnVar .= $this->parse_template($this->$val,$this->PARSEVARS);
+		}
+		else
+		{
+		    $this->$ReturnVar = $this->parse_template($this->$val,$this->PARSEVARS);
+		}
+		
+		//	For recursive calls.
+		
+		$this->assign(array( $ReturnVar => $this->$ReturnVar) );
+		
+	    }
+	    return;
+	}
+    
+    
+    function FastPrint($template = "")
+	{
+	    if(empty($template))
+	    {
+		$template = $this->LAST;
+	    }
+	    
+	    if( (!(isset($this->$template))) || (empty($this->$template)) )
+	    {
+		$this->error("Nothing parsed, nothing printed",0);
+		return;
+	    }
+	    else
+	    {
+		print $this->$template;
+	    }
+	    return;
+	}
+
+
+    function fetch($template = "")
+	{
+	    if(empty($template))
+	    {
+		$template = $this->LAST;
+	    }
+	    if( (!(isset($this->$template))) || (empty($this->$template)) )
+	    {
+		$this->error("Nothing parsed, nothing printed",0);
+		return "";
+	    }
+	    
+	    return($this->$template);
+	}
+
+
+    function define_dynamic($Macro, $ParentName)
+	{
+	    //	A dynamic block lives inside another template file.
+	    //	It will be stripped from the template when parsed
+	    //	and replaced with the {$Tag}.
+	    
+	    $this->DYNAMIC["$Macro"] = $ParentName;
+	    return true;
+	}
+    
+
+    function parse_dynamic($Macro,$MacroName)
+	{
+	    // The file must already be in memory.
+	    
+	    $ParentTag = $this->DYNAMIC["$Macro"];
+	    if( (!$this->$ParentTag) or (empty($this->$ParentTag)) )
+	    {
+		$fileName = $this->FILELIST[$ParentTag];
+		$this->$ParentTag = $this->get_template($fileName);
+		$this->LOADED[$ParentTag] = 1;
+	    }
+	    if($this->$ParentTag)
+	    {
+		$template = $this->$ParentTag;
+		$DataArray = split("\n",$template);
+		$newMacro = "";
+		$newParent = "";
+		$outside = true;
+		$start = false;
+		$end = false;
+		while ( list ($lineNum,$lineData) = each ($DataArray) )
+		{
+		    $lineTest = trim($lineData);
+		    if("<!-- BEGIN DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
+		    {
+			$start = true;
+			$end = false;
+			$outside = false;
+		    }
+		    if("<!-- END DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
+		    {
+			$start = false;
+			$end = true;
+			$outside = true;
+		    }
+		    if( (!$outside) and (!$start) and (!$end) )
+		    {
+			$newMacro .= "$lineData\n"; // Restore linebreaks
+		    }
+		    if( ($outside) and (!$start) and (!$end) )
+		    {
+			$newParent .= "$lineData\n"; // Restore linebreaks
+		    }
+		    if($end)
+		    {
+			$newParent .= "{$MacroName}\n";
+		    }
+		    // Next line please
+		    if($end) { $end = false; }
+		    if($start) { $start = false; }
+		}	// end While
+		
+		$this->$Macro = $newMacro;
+		$this->$ParentTag = $newParent;
+		return true;
+		
+	    }	// $ParentTag NOT loaded - MAJOR oopsie
+	    else
+	    {
+		@error_log("ParentTag: [$ParentTag] not loaded!",0);
+		$this->error("ParentTag: [$ParentTag] not loaded!",0);
+	    }
+	    return false;
+	}
+    
+    
+    /* Strips a DYNAMIC BLOCK from a template. */
+    
+    function clear_dynamic($Macro="")
+	{
+	    if(empty($Macro)) { return false; }
+	    
+	    // The file must already be in memory.
+	    
+	    $ParentTag = $this->DYNAMIC["$Macro"];
+	    
+	    if( (!$this->$ParentTag) or (empty($this->$ParentTag)) )
+	    {
+		$fileName = $this->FILELIST[$ParentTag];
+		$this->$ParentTag = $this->get_template($fileName);
+		$this->LOADED[$ParentTag] = 1;
+	    }
+	    
+	    if($this->$ParentTag)
+	    {
+		$template = $this->$ParentTag;
+		$DataArray = split("\n",$template);
+		$newParent = "";
+		$outside = true;
+		$start = false;
+		$end = false;
+		while ( list ($lineNum,$lineData) = each ($DataArray) )
+		{
+		    $lineTest = trim($lineData);
+		    if("<!-- BEGIN DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
+		    {
+			$start = true;
+			$end = false;
+			$outside = false;
+		    }
+		    if("<!-- END DYNAMIC BLOCK: $Macro -->" == "$lineTest" )
+		    {
+			$start = false;
+			$end = true;
+			$outside = true;
+		    }
+		    if( ($outside) and (!$start) and (!$end) )
+		    {
+			$newParent .= "$lineData\n"; // Restore linebreaks
+		    }
+		    // Next line please
+		    if($end) { $end = false; }
+		    if($start) { $start = false; }
+		}	// end While
+		
+		$this->$ParentTag = $newParent;
+		return true;
+		
+	    }	// $ParentTag NOT loaded - MAJOR oopsie
+	    else
+	    {
+		@error_log("ParentTag: [$ParentTag] not loaded!",0);
+		$this->error("ParentTag: [$ParentTag] not loaded!",0);
+	    }
+	    return false;
+	}
+    
+    
+    function define($fileList)
+	{
+	    while ( list ($FileTag,$FileName) = each ($fileList) )
+	    {
+		$this->FILELIST["$FileTag"] = $FileName;
+	    }
+	    return true;
+	}
+    
+    
+    function clear_parse($ReturnVar = "")
+	{
+	    $this->clear($ReturnVar);
+	}
+    
+    
+    function clear($ReturnVar="")
+	{
+	    // Clears out hash created by call to parse()
+	    
+	    if(!empty($ReturnVar))
+	    {
+		if( (gettype($ReturnVar)) != "array")
+		{
+		    unset($this->$ReturnVar);
+		    return;
+		}
+		else
+		{
+		    while ( list ($key,$val) = each ($ReturnVar) )
+		    {
+			unset($this->$val);
+		    }
+		    return;
+		}
+	    }
+	    
+	    // Empty - clear all of them
+	    
+	    while ( list ( $key,$val) = each ($this->HANDLE) )
+	    {
+		$KEY = $key;
+		unset($this->$KEY);
+	    }
+	    return;
+	    
+	}
+    
+
+    function clear_all ()
+	{
+	    $this->clear();
+	    $this->clear_assign();
+	    $this->clear_define();
+	    $this->clear_tpl();
+	    
+	    return;
+	    
+	}
+
+
+    function clear_tpl ($fileHandle = "")
+	{
+	    if(empty($this->LOADED))
+	    {
+		// Nothing loaded, nothing to clear
+		
+		return true;
+	    }
+	    if(empty($fileHandle))
+	    {
+		// Clear ALL fileHandles
+		
+		while ( list ($key, $val) = each ($this->LOADED) )
+		{
+		    unset($this->$key);
+		}
+		unset($this->LOADED);
+		
+		return true;
+	    }
+	    else
+	    {
+		if( (gettype($fileHandle)) != "array")
+		{
+		    if( (isset($this->$fileHandle)) || (!empty($this->$fileHandle)) )
+		    {
+			unset($this->LOADED[$fileHandle]);
+			unset($this->$fileHandle);
+			return true;
+		    }
+		}
+		else
+		{
+		    while ( list ($Key, $Val) = each ($fileHandle) )
+		    {
+			unset($this->LOADED[$Key]);
+			unset($this->$Key);
+		    }
+		    return true;
+		}
+	    }
+	    
+	    return false;
+	    
+	}
+    
+    
+    function clear_define ( $FileTag = "" )
+	{
+	    if(empty($FileTag))
+	    {
+		unset($this->FILELIST);
+		return;
+	    }
+	    
+	    if( (gettype($Files)) != "array")
+	    {
+		unset($this->FILELIST[$FileTag]);
+		return;
+	    }
+	    else
+	    {
+		while ( list ( $Tag, $Val) = each ($FileTag) )
+		{
+		    unset($this->FILELIST[$Tag]);
+		}
+		return;
+	    }
+	}
+
+    /* Clears all variables set by assign() */
+    
+    function clear_assign ()
+	{
+	    if(!(empty($this->PARSEVARS)))
+	    {
+		while(list($Ref,$Val) = each ($this->PARSEVARS) )
+		{
+		    unset($this->PARSEVARS["$Ref"]);
+		}
+	    }
+	}
+    
+    
+    function clear_href ($href)
+	{
+	    if(!empty($href))
+	    {
+		if( (gettype($href)) != "array")
+		{
+		    unset($this->PARSEVARS[$href]);
+		    return;
+		}
+		else
+		{
+		    while (list ($Ref,$val) = each ($href) )
+		    {
+			unset($this->PARSEVARS[$Ref]);
+		    }
+		    return;
+		}
+	    }
+	    else
+	    {
+		// Empty - clear them all
+		
+		$this->clear_assign();
+	    }
+	    return;
+	}
+    
+
+    function assign ($tpl_array, $trailer="")
+	{
+	    if(gettype($tpl_array) == "array")
+	    {
+		while ( list ($key,$val) = each ($tpl_array) )
+		{
+		    if (!(empty($key)))
+		    {
+			//	Empty values are allowed
+			//	Empty Keys are NOT
+			
+			$this->PARSEVARS["$key"] = $val;
+		    }
+		}
+	    }
+	    else
+	    {
+		// Empty values are allowed in non-array context now.
+		if (!empty($tpl_array))
+		{
+		    $this->PARSEVARS["$tpl_array"] = $trailer;
+		}
+	    }
+	}
+    
+    /* Return the value of an assigned variable.
+     * Christian Brandel cbrandel@gmx.de
+     */
+    
+    function get_assigned($tpl_name = "")
+	{
+	    
+	    if(empty($tpl_name)) { return false; }
+	    if(isset($this->PARSEVARS["$tpl_name"]))
+	    {
+		return ($this->PARSEVARS["$tpl_name"]);
+	    }
+	    else
+	    {
+		return false;
+	    }
+	}
+    
+
+    function error ($errorMsg, $die = 0)
+	{
+	    $this->ERROR = $errorMsg;
+
+	    if($die == 1)
+		die("ERROR: $this->ERROR <BR> \n");
+	    else
+		echo "ERROR: ".$this->ERROR."<BR>\n";
+	}
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/htdocs/dot.htaccess	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,4 @@
+Require valid-user
+AuthType Basic
+AuthName "mlmmj web-interface"
+AuthUserFile /home/mlmmj/htpasswd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/htdocs/edit.php	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,115 @@
+<?php
+
+/* mlmmj/php-admin:
+ * Copyright (C) 2004 Christoph Thiel <ct at kki dot org>
+ *
+ * mlmmj/php-perl:
+ * Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk>
+ * Copyright (C) 2004 Christian Laursen <christian@pil.dk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+require("../conf/config.php");
+require("class.FastTemplate.php");
+
+function mlmmj_boolean($name, $nicename, $text) 
+{
+    global $tpl, $topdir, $list;
+
+    if(is_file($topdir."/".$list."/control/".$name))
+	$checked = TRUE;
+    else
+	$checked = FALSE;
+
+    $tpl->assign(array("NAME" => htmlentities($name),
+		       "NICENAME" => htmlentities($nicename),
+		       "TEXT" => htmlentities($text)));
+    $tpl->assign(array("CHECKED" => $checked ? " checked" : ""));
+
+    $tpl->parse("ROWS",".boolean");
+}
+
+function mlmmj_string($name, $nicename, $text)
+{
+    global $tpl, $topdir, $list;
+
+    $file = $topdir."/".$list."/control/".$name;
+    $value = "";
+
+    if(!is_file($file))
+	$lines = "";
+    else
+	$lines = file($file);
+
+    $value = $lines[0];
+    
+    $tpl->assign(array("NAME" => htmlentities($name),
+		       "NICENAME" => htmlentities($nicename),
+		       "TEXT" => htmlentities($text),
+		       "VALUE" => htmlentities($value)));
+    
+    $tpl->parse("ROWS",".string");
+}
+
+function mlmmj_list($name, $nicename, $text)
+{
+    global $tpl, $topdir, $list;
+    
+    $file = "$topdir/$list/control/$name";
+    $value = "";
+
+    if(!is_file($file))
+	$lines = array();
+    else
+	$lines = file($file);
+
+    foreach ($lines as $line) 
+    {
+	$value .= $line;
+    }
+
+    $tpl->assign(array("NAME" => htmlentities($name),
+		       "NICENAME" => htmlentities($nicename),
+		       "TEXT" => htmlentities($text),
+		       "VALUE" => htmlentities($value)));
+
+    $tpl->parse("ROWS",".list");
+}
+
+$tpl = new FastTemplate($templatedir);
+
+$list = $HTTP_GET_VARS["list"];
+
+if(!is_dir($topdir."/".$list))
+die("non-existent list");
+
+$tpl->define(array("main" => "edit.html",
+		   "boolean" => "edit_boolean.html",
+		   "string" => "edit_string.html",
+		   "list" => "edit_list.html"));
+
+$tpl->assign(array("LIST" =>htmlentities($list)));
+
+require("../conf/tunables.php");
+
+$tpl->parse("MAIN","main");
+$tpl->FastPrint("MAIN");
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/htdocs/index.php	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,53 @@
+<?php
+
+/* mlmmj/php-admin:
+ * Copyright (C) 2004 Christoph Thiel <ct at kki dot org>
+ *
+ * mlmmj/php-perl:
+ * Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk>
+ * Copyright (C) 2004 Christian Laursen <christian@pil.dk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+require("class.FastTemplate.php");
+require("../conf/config.php");
+
+$tpl = new FastTemplate($templatedir);
+
+$tpl->define(array("main" => "index.html"));
+
+$lists = "";
+
+$dir = opendir($topdir);
+while ($file = readdir($dir)) {
+    if (!ereg("^\.",$file))
+    {
+	$lists .= "<a href=\"edit.php?list=".urlencode($file)."\">".htmlentities($file)."</a><br />\n";
+    }
+}
+closedir($dir); 
+
+$tpl->assign(array("LISTS" => $lists));
+
+
+$tpl->parse("MAIN","main");
+$tpl->FastPrint("MAIN");
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/htdocs/save.php	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,86 @@
+<?php
+
+/* mlmmj/php-admin:
+ * Copyright (C) 2004 Christoph Thiel <ct at kki dot org>
+ *
+ * mlmmj/php-perl:
+ * Copyright (C) 2004 Morten K. Poulsen <morten at afdelingp.dk>
+ * Copyright (C) 2004 Christian Laursen <christian@pil.dk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+require("../conf/config.php");
+require("class.FastTemplate.php");
+
+function mlmmj_boolean($name, $nicename, $text)
+{
+    global $tpl, $topdir, $list, $HTTP_POST_VARS;
+    
+    $file = $topdir."/".$list."/control/".$name;
+    
+    if (isset($HTTP_POST_VARS[$name])) 
+    {
+	if(!touch($file))
+	    die("Couldn't open ".$file." for writing");
+    }
+    else
+	@unlink($file);
+}
+
+function mlmmj_string ($name, $nicename, $text) 
+{
+    mlmmj_list($name, $nicename, $text);
+}   
+
+function mlmmj_list($name, $nicename, $text) 
+{
+    global $tpl, $topdir, $list,$HTTP_POST_VARS;
+
+    $file = $topdir."/".$list."/control/".$name;
+    
+    if(!empty($HTTP_POST_VARS[$name]))
+    {
+	if (!$fp = fopen($file, "w"))
+	    die("Couldn't open ".$file." for writing");
+
+	fwrite($fp, $HTTP_POST_VARS[$name]);
+	fclose($fp);
+    }
+    else
+	@unlink($file);
+    
+}
+
+$tpl = new FastTemplate($templatedir);
+
+$list = $HTTP_POST_VARS["list"];
+
+if(!is_dir($topdir."/".$list))
+die("non-existent list");
+
+$tpl->define(array("main" => "save.html"));
+$tpl->assign(array("LIST" => htmlentities($list)));
+
+require("../conf/tunables.php");
+
+$tpl->parse("MAIN","main");
+$tpl->FastPrint("MAIN");
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/templates/edit.html	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,13 @@
+<html><head><title>mlmmj config</title></head><body>
+<h1>mlmmj config</h1>
+<form method="post" action="save.php">
+<input type="hidden" name="list" value="{LIST}">
+<table border="1">
+{ROWS}
+</table>
+<input type="submit" name="submit" />
+</form>
+<p>
+<a href="index.php">Index</a>
+</p>
+</body></html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/templates/edit_boolean.html	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,1 @@
+<tr><td>{NICENAME}</td><td><input type="checkbox" name="{NAME}" value="1"{CHECKED}></td><td>{TEXT}</td></tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/templates/edit_list.html	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,1 @@
+<tr><td>{NICENAME}</td><td><textarea name="{NAME}" columns="40">{VALUE}</textarea></td><td>{TEXT}</td></tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/templates/edit_string.html	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,1 @@
+<tr><td>{NICENAME}</td><td><input type="text" name="{NAME}" value="{VALUE}"></td><td>{TEXT}</td></tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/templates/index.html	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,4 @@
+<html><head><title>mlmmj config</title></head><body>
+<h1>mlmmj config</h1>
+{LISTS}
+</body></html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/web/php-admin/templates/save.html	Wed Sep 01 18:19:00 2004 +1000
@@ -0,0 +1,9 @@
+<html><head><title>mlmmj config</title></head><body>
+<h1>mlmmj config</h1>
+<p>
+{LIST} control values saved!
+</p>
+<p>
+<a href="index.php">Index</a> | <a href="edit.php?list={LIST}">{LIST}</a>
+</p>
+</body></html>