<?php
# vim:et:ts=3:sts=3:sw=3:fdm=marker:
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright © 2004-2006 Tim Armes, Matt Sicker
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// 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
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// configclass.inc4
//
// General class for handling configuration options
require_once("include/command.inc");
require_once("include/auth.inc");
require_once("include/version.inc");
// Auxillary functions used to sort repositories by name/group
// {{{ cmpReps($a, $b)
function cmpReps($a, $b)
{
// First, sort by group
$g = strcasecmp($a->group, $b->group);
if ($g)
return $g;
// Same group? Sort by name
return strcasecmp($a->name, $b->name);
}
// }}}
// {{{ cmpGroups($a, $b)
function cmpGroups($a, $b)
{
$g = strcasecmp($a->group, $b->group);
if ($g)
return $g;
return 0;
}
// }}}
// {{{ mergesort(&$array, [$cmp_function])
function mergesort(&$array, $cmp_function = 'strcmp')
{
// Arrays of size < 2 require no action
if (count($array) < 2)
return;
// Split the array in half
$halfway = count($array) / 2;
$array1 = array_slice($array, 0, $halfway);
$array2 = array_slice($array, $halfway);
// Recurse to sort the two halves
mergesort($array1, $cmp_function);
mergesort($array2, $cmp_function);
// If all of $array1 is <= all of $array2, just append them.
if (call_user_func($cmp_function, end($array1), $array2[0]) < 1)
{
$array = array_merge($array1, $array2);
return;
}
// Merge the two sorted arrays into a single sorted array
$array = array();
$ptr1 = $ptr2 = 0;
while ($ptr1 < count($array1) && $ptr2 < count($array2))
{
if (call_user_func($cmp_function, $array1[$ptr1], $array2[$ptr2]) < 1)
{
$array[] = $array1[$ptr1++];
}
else
{
$array[] = $array2[$ptr2++];
}
}
// Merge the remainder
while ($ptr1 < count($array1)) $array[] = $array1[$ptr1++];
while ($ptr2 < count($array2)) $array[] = $array2[$ptr2++];
return;
}
// }}}
// A Repository configuration class
Class Repository
{
// {{{ Properties
var $name;
var $svnName;
var $path;
var $group;
var $username;
var $password;
// Local configuration options must start off unset
var $allowDownload;
var $minDownloadLevel;
var $allowedExceptions = array();
var $disallowedExceptions = array();
var $rss;
var $spaces;
var $ignoreSvnMimeTypes;
var $ignoreWebSVNContentTypes;
var $bugtraq;
var $auth;
var $contentEnc;
var $templatePath;
// }}}
// {{{ __construct($name, $svnName, $path, [$group, [$username, [$password]]])
function Repository($name, $svnName, $path, $group = NULL, $username = NULL, $password = NULL)
{
$this->name = $name;
$this->svnName = $svnName;
$this->path = $path;
$this->group = $group;
$this->username = $username;
$this->password = $password;
}
// }}}
// {{{ getDisplayName()
function getDisplayName()
{
if(!empty($this->group))
return $this->group.".".$this->name;
else
return $this->name;
}
// }}}
// {{{ svnParams
function svnParams()
{
if (!empty($this->username))
return " --username ".$this->username." --password ".$this->password." ";
else
return " ";
}
// }}}
// Local configuration accessors
// {{{ RSS Feed
function hideRSS()
{
$this->rss = false;
}
function showRSS()
{
$this->rss = true;
}
function getHideRSS()
{
global $config;
if (isset($this->rss))
return $this->rss;
return $config->getHideRSS();
}
// }}}
// {{{ Download
function allowDownload()
{
$this->allowDownload = true;
}
function disallowDownload()
{
$this->allowDownload = false;
}
function getAllowDownload()
{
global $config;
if (isset($this->allowDownload))
return $this->allowDownload;
return $config->getAllowDownload();
}
function setMinDownloadLevel($level)
{
$this->minDownloadLevel = $level;
}
function getMinDownloadLevel()
{
global $config;
if (isset($this->minDownloadLevel))
return $this->minDownloadLevel;
return $config->getMinDownloadLevel();
}
function addAllowedDownloadException($path)
{
if ($path{strlen($path) - 1} != "/")
$path .= "/";
$this->allowedExceptions[] = $path;
}
function addDisallowedDownloadException($path)
{
if ($path{strlen($path) - 1} != "/")
$path .= "/";
$this->disallowedExceptions[] = $path;
}
function isDownloadAllowed($path)
{
global $config;
// Check global download option
if (!$this->getAllowDownload())
return false;
// Check with access module
if (!$this->hasUnrestrictedReadAccess($path))
return false;
$subs = explode("/", $path);
$level = count($subs) - 2;
if ($level >= $this->getMinDownloadLevel())
{
// Level OK, search for disallowed exceptions
if ($config->findException($path, $this->disallowedExceptions))
return false;
if ($config->findException($path, $config->disallowedExceptions))
return false;
return true;
}
else
{
// Level not OK, search for disallowed exceptions
if ($config->findException($path, $this->allowedExceptions))
return true;
if ($config->findException($path, $config->allowedExceptions))
return true;
return false;
}
}
// }}}
// {{{ Templates
function setTemplatePath($path)
{
$lastchar = substr($path, -1, 1);
if (!($lastchar == DIRECTORY_SEPARATOR ||
$lastchar == '/' ||
$lastchar == '\\'))
$path .= DIRECTORY_SEPARATOR;
$this->templatePath = $path;
}
function getTemplatePath()
{
global $config;
if (!empty($this->templatePath))
return $this->templatePath;
else
return $config->getTemplatePath();
}
// }}}
// {{{ Tab expansion
function expandTabsBy($sp)
{
$this->spaces = $sp;
}
function getExpandTabsBy()
{
global $config;
if (isset($this->spaces))
return $this->spaces;
return $config->getExpandTabsBy();
}
// }}}
// {{{ MIME-Type Handing
function ignoreSvnMimeTypes()
{
$this->ignoreSvnMimeTypes = true;
}
function useSvnMimeTypes()
{
$this->ignoreSvnMimeTypes = false;
}
function getIgnoreSvnMimeTypes()
{
global $config;
if (isset($this->ignoreSvnMimeTypes))
return $this->ignoreSvnMimeTypes;
return $config->getIgnoreSvnMimeTypes();
}
function ignoreWebSVNContentTypes()
{
$this->ignoreWebSVNContentTypes = true;
}
function useWebSVNContentTypes()
{
$this->ignoreWebSVNContentTypes = false;
}
function getIgnoreWebSVNContentTypes()
{
global $config;
if (isset($this->ignoreWebSVNContentTypes))
return $this->ignoreWebSVNContentTypes;
return $config->getIgnoreWebSVNContentTypes();
}
// }}}
// {{{ Issue Tracking
function useBugtraqProperties()
{
$this->bugtraq = true;
}
function ignoreBugtraqProperties()
{
$this->bugtraq = false;
}
function getBugtraq()
{
global $config;
if (isset($this->bugtraq))
return $this->bugtraq;
return $config->getBugtraq();
}
// }}}
// {{{ Encodings
function setContentEncoding($contentEnc)
{
$this->contentEnc = $contentEnc;
}
function getContentEncoding()
{
global $config;
if (isset($this->contentEnc))
return $this->contentEnc;
return $config->getContentEncoding();
}
function useAuthenticationFile($file)
{
if (is_readable($file))
$this->auth =& new Authentication($file);
else
die('Unable to read authentication file "'.$file.'"');
}
function hasReadAccess($path, $checkSubFolders = false)
{
global $config;
$a = null;
if (isset($this->auth))
$a =& $this->auth;
else
$a =& $config->getAuth();
if (!empty($a))
return $a->hasReadAccess($this->svnName, $path, $checkSubFolders);
// No auth file - free access...
return true;
}
function hasUnrestrictedReadAccess($path)
{
global $config;
$a = null;
if (isset($this->auth))
$a =& $this->auth;
else
$a =& $config->getAuth();
if (!empty($a))
return $a->hasUnrestrictedReadAccess($this->svnName, $path);
// No auth file - free access...
return true;
}
// }}}
}
// The general configuration class
Class Config
{
// {{{ Properties
// Tool path locations
var $svnlook = "svnlook";
var $svn = "svn --non-interactive --config-dir /tmp";
var $svn_noparams = "svn --config-dir /tmp";
var $diff = "diff";
var $enscript ="enscript";
var $sed = "sed";
var $gzip = "gzip";
var $tar = "tar";
// Other configuration items
var $treeView = true;
var $flatIndex = true;
var $openTree = false;
var $serverIsWindows = false;
var $cacheResults = false;
var $multiViews = false;
var $useEnscript = false;
var $allowDownload = false;
var $minDownloadLevel = 0;
var $allowedExceptions = array();
var $disallowedExceptions = array();
var $rss = true;
var $spaces = 8;
var $bugtraq = false;
var $auth = "";
var $templatePath = "./templates/Standard/";
var $phpCompatPath = './include/PHP/Compat.php';
var $ignoreSvnMimeTypes = false;
var $ignoreWebSVNContentTypes = false;
var $subversionMajorVersion = "";
var $subversionMinorVersion = "";
// Default character encodings
var $inputEnc = ""; // Encoding of output returned from command line
var $contentEnc = ""; // Encoding of repository content
var $outputEnc = "UTF-8"; // Encoding of web page. Now forced to UTF-8
var $quote = "'";
var $_repositories;
// }}}
// {{{ __construct()
function Config()
{
}
// }}}
// {{{ Repository configuration
function addRepository($name, $url, $group = NULL, $username = NULL, $password = NULL)
{
$url = str_replace(DIRECTORY_SEPARATOR, "/", $url);
if ($url{strlen($url) - 1} == "/")
$url = substr($url, 0, -1);
$svnName = substr($url, strrpos($url, "/") + 1);
$this->_repositories[] = new Repository($name, $svnName, $url, $group, $username, $password);
}
function getRepositories()
{
return $this->_repositories;
}
function &findRepository($name)
{
foreach ($this->_repositories as $index => $rep)
{
if (strcmp($rep->getDisplayName(), $name) == 0)
{
$repref =& $this->_repositories[$index];
return $repref;
}
}
print "ERROR: Unable to find repository '$name'";
exit;
}
// }}}
// {{{ setServerIsWindows
//
// The server is running on Windows
function setServerIsWindows()
{
$this->serverIsWindows = true;
// Try to set the input encoding intelligently
$cp = 0;
if ($cp = @shell_exec("CHCP"))
{
$cp = trim(substr($cp, strpos($cp, ":") + 1));
settype($cp, "integer");
}
// Use the most sensible default value if that failed
if ($cp == 0) $cp = 850;
// We assume, as a default, that the encoding of the repository contents is
// in iso-8859-1, to be compatible with compilers and the like.
$this->setInputEncoding("CP$cp", "iso-8859-1");
// On Windows machines, use double quotes around command line parameters
$this->quote = '"';
}
// }}}
// {{{ Caching
// setCachingOn
//
// Set result caching on
function setCachingOn()
{
$this->cacheResults = true;
}
function isCachingOn()
{
return $this->cacheResults;
}
// }}}
// {{{ MultiViews
// useMultiViews
//
// Use MultiViews to access the repository
function useMultiViews()
{
$this->multiViews = true;
}
function getUseMultiViews()
{
return $this->multiViews;
}
// }}}
// {{{ Enscript
// useEnscript
//
// Use Enscript to colourise listings
function useEnscript()
{
$this->useEnscript = true;
}
function getUseEnscript()
{
return $this->useEnscript;
}
// }}}
// {{{ RSS
// offerRSS
//
// Use Enscript to colourise listings
function hideRSS($myrep = 0)
{
if (empty($myrep))
$this->rss = false;
else
{
$repo =& $this->findRepository($myrep);
$repo->hideRSS();
}
}
function getHideRSS()
{
return $this->rss;
}
// }}}
// {{{ Downloads
// allowDownload
//
// Allow download of tarballs
function allowDownload($myrep = 0)
{
if (empty($myrep))
$this->allowDownload = true;
else
{
$repo =& $this->findRepository($myrep);
$repo->allowDownload();
}
}
function disallowDownload($myrep = 0)
{
if (empty($myrep))
$this->allowDownload = false;
else
{
$repo =& $this->findRepository($myrep);
$repo->disallowDownload();
}
}
function getAllowDownload()
{
return $this->allowDownload;
}
function setMinDownloadLevel($level, $myrep = 0)
{
if (empty($myrep))
$this->minDownloadLevel = $level;
else
{
$repo =& $this->findRepository($myrep);
$repo->setMinDownloadLevel($level);
}
}
function getMinDownloadLevel()
{
return $this->minDownloadLevel;
}
function addAllowedDownloadException($path, $myrep = 0)
{
if ($path{strlen($path) - 1} != "/")
$path .= "/";
if (empty($myrep))
$this->allowedExceptions[] = $path;
else
{
$repo =& $this->findRepository($myrep);
$repo->addAllowedDownloadException($path);
}
}
function addDisallowedDownloadException($path, $myrep = 0)
{
if ($path{strlen($path) - 1} != "/")
$path .= "/";
if (empty($myrep))
$this->disallowedExceptions[] = $path;
else
{
$repo =& $this->findRepository($myrep);
$repo->addDisallowedDownloadException($path);
}
}
function findException($path, $exceptions)
{
foreach ($exceptions As $key => $exc)
{
if (strncmp($exc, $path, strlen($exc)) == 0)
return true;
}
return false;
}
// }}}
// {{{ getURL
//
// Get the URL to a path name based on the current config
function getURL($rep, $path, $op)
{
$base = $_SERVER["SCRIPT_NAME"];
if ($this->multiViews)
{
// Remove the .php
if (eregi(".php$", $base))
{
// Remove the .php
$base = substr($base, 0, -4);
}
if ($path && $path{0} != "/") $path = "/".$path;
$url = $base;
if (is_object($rep))
{
$url .= "/".$rep->getDisplayName().str_replace('%2F', '/', urlencode($path));
if ($op != "dir" && $op != "file")
$url .= "?op=$op&";
else
$url .= "?";
}
return $url;
}
else
{
switch ($op)
{
case "dir":
$fname = "listing.php";
break;
case "file":
$fname = "filedetails.php";
break;
case "log":
$fname = "log.php";
break;
case "diff":
$fname = "diff.php";
break;
case "blame":
$fname = "blame.php";
break;
case "form":
$fname = "form.php";
break;
case "rss":
$fname = "rss.php";
break;
case "dl":
$fname = "dl.php";
break;
case "comp":
$fname = "comp.php";
break;
}
if ($rep == -1)
return $fname."?path=".urlencode($path)."&";
else
return $fname."?repname=".urlencode($rep->getDisplayName())."&path=".urlencode($path)."&";
}
}
// }}}
// {{{ Paths and Commands
// setPath
//
// Set the location of the given path
function setPath(&$var, $path, $name, $params = "")
{
$lastchar = substr($path, -1, 1);
$isDir = ($lastchar == DIRECTORY_SEPARATOR ||
$lastchar == "/" ||
$lastchar == "\\");
if (!$isDir)
{
$path .= DIRECTORY_SEPARATOR;
}
// On a windows machine we need to put spaces around the entire command
// to allow for spaces in the path
if ($this->serverIsWindows)
$var = "\"$path$name\"";
else
$var = "$path$name";
$var .= " ".$params;
}
// setSVNCommandPath
//
// Define the location of the svn and svnlook commands
function setSVNCommandPath($path)
{
$this->setPath($this->svn, $path, "svn", "--non-interactive --config-dir /tmp");
$this->setPath($this->svn_noparams, $path, "svn", " --config-dir /tmp");
$this->setPath($this->svnlook, $path, "svnlook");
}
function getSvnCommand()
{
return $this->svn;
}
function getCleanSvnCommand()
{
return $this->svn_noparams;
}
function getSvnlookCommand()
{
return $this->svnlook;
}
// setDiffPath
//
// Define the location of the diff command
function setDiffPath($path)
{
$this->setPath($this->diff, $path, "diff");
}
function getDiffCommand()
{
return $this->diff;
}
// setEnscriptPath
//
// Define the location of the enscript command
function setEnscriptPath($path)
{
$this->setPath($this->enscript, $path, "enscript");
}
function getEnscriptCommand()
{
return $this->enscript;
}
// setSedPath
//
// Define the location of the sed command
function setSedPath($path)
{
$this->setPath($this->sed, $path, "sed");
}
function getSedCommand()
{
return $this->sed;
}
// setTarPath
//
// Define the location of the tar command
function setTarPath($path)
{
$this->setPath($this->tar, $path, "tar");
}
function getTarCommand()
{
return $this->tar;
}
// setGzipPath
//
// Define the location of the GZip command
function setGzipPath($path)
{
$this->setPath($this->gzip, $path, "gzip");
}
function getGzipCommand()
{
return $this->gzip;
}
// Templates
function setTemplatePath($path, $myrep = 0)
{
if (empty($myrep))
{
$lastchar = substr($path, -1, 1);
if (!($lastchar == DIRECTORY_SEPARATOR ||
$lastchar == '/' ||
$lastchar == '\\'))
$path .= DIRECTORY_SEPARATOR;
$this->templatePath = $path;
}
else
{
$repo =& $this->findRepository($myrep);
$repo->setTemplatePath($path);
}
}
function getTemplatePath()
{
return $this->templatePath;
}
// PHP Compat file (from PEAR)
function setPHPCompatPath($path)
{
$this->setPath($this->phpCompatPath, $path, 'Compat.php');
}
function getPHPCompatFile()
{
return trim($this->phpCompatPath);
}
// }}}
// {{{ parentPath
//
// Automatically set up the repositories based on a parent path
function parentPath($path, $group = NULL)
{
if ($handle = @opendir($path))
{
// For each file...
while (false !== ($file = readdir($handle)))
{
// That's also a non hidden directory
if (is_dir($path.DIRECTORY_SEPARATOR.$file) && $file{0} != ".")
{
// And that contains a db directory (in an attempt to not include
// non svn repositories.
if (is_dir($path.DIRECTORY_SEPARATOR.$file.DIRECTORY_SEPARATOR."db"))
{
// We add the repository to the list
$this->addRepository($file, "file:///".$path.DIRECTORY_SEPARATOR.$file, $group);
}
}
}
closedir($handle);
}
// Sort the repositories into alphabetical order
if (!empty($this->_repositories))
usort($this->_repositories, "cmpReps");
}
// }}}
// {{{ Encoding functions
function setInputEncoding($systemEnc)
{
$this->inputEnc = $systemEnc;
if (!isset($this->contentEnc))
$this->contentEnc = $systemEnc;
}
function getInputEncoding()
{
return $this->inputEnc;
}
function setContentEncoding($contentEnc, $myrep = 0)
{
if (empty($myrep))
$this->contentEnc = $contentEnc;
else
{
$repo =& $this->findRepository($myrep);
$repo->setContentEncoding($contentEnc);
}
}
function getContentEncoding()
{
return $this->contentEnc;
}
// }}}
// {{{ Tab expansion functions
function expandTabsBy($sp, $myrep = 0)
{
if (empty($myrep))
$this->spaces = $sp;
else
{
$repo =& $this->findRepository($myrep);
$repo->expandTabsBy($sp);
}
}
function getExpandTabsBy()
{
return $this->spaces;
}
// }}}
// {{{ Misc settings
function ignoreSvnMimeTypes()
{
$this->ignoreSvnMimeTypes = true;
}
function getIgnoreSvnMimeTypes()
{
return $this->ignoreSvnMimeTypes;
}
function ignoreWebSVNContentTypes()
{
$this->ignoreWebSVNContentTypes = true;
}
function getIgnoreWebSVNContentTypes()
{
return $this->ignoreWebSVNContentTypes;
}
function useBugtraqProperties($myrep = 0)
{
if (empty($myrep))
$this->bugtraq = true;
else
{
$repo =& $this->findRepository($myrep);
$repo->useBugtraqProperties();
}
}
function getBugtraq()
{
return $this->bugtraq;
}
function useAuthenticationFile($file, $myrep = 0)
{
if (empty($myrep))
{
if (is_readable($file))
$this->auth = new Authentication($file);
else
{
echo "Unable to read authentication file '$file'";
exit;
}
}
else
{
$repo =& $this->findRepository($myrep);
$repo->useAuthenticationFile($file);
}
}
function &getAuth()
{
return $this->auth;
}
function useTreeView()
{
$this->treeView = true;
}
function getUseTreeView()
{
return $this->treeView;
}
function useFlatView()
{
$this->treeView = false;
}
function useTreeIndex($open)
{
$this->flatIndex = false;
$this->openTree = $open;
}
function getUseFlatIndex()
{
return $this->flatIndex;
}
function getOpenTree()
{
return $this->openTree;
}
// setSubversionMajorVersion
//
// Set subversion major version
function setSubversionMajorVersion($subversionMajorVersion)
{
$this->subversionMajorVersion = $subversionMajorVersion;
}
function getSubversionMajorVersion()
{
return $this->subversionMajorVersion;
}
// setSubversionMinorVersion
//
// Set subversion minor version
function setSubversionMinorVersion($subversionMinorVersion)
{
$this->subversionMinorVersion = $subversionMinorVersion;
}
function getSubversionMinorVersion()
{
return $this->subversionMinorVersion;
}
// }}}
// {{{ Sort the repostories
//
// This function sorts the repositories by group name. The contents of the
// group are left in there original order, which will either be sorted if the
// group was added using the parentPath function, or defined for the order in
// which the repositories were included in the user's config file.
//
// Note that as of PHP 4.0.6 the usort command no longer preserves the order
// of items that are considered equal (in our case, part of the same group).
// The mergesort function preserves this order.
function sortByGroup()
{
if (!empty($this->_repositories))
mergesort($this->_repositories, "cmpGroups");
}
// }}}
}
?>