<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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
//
// --
//
// setup.php
//
// Global setup

// --- DON'T CHANGE THIS FILE ---
//
// User changes should be done in config.php

// Include the configuration class
require_once 'include/configclass.php';

// Register Composer autoloader if available
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
        require_once __DIR__ . '/../vendor/autoload.php';
        define('USE_AUTOLOADER', true);
}

// Create the config
$config = new WebSvnConfig();

if (DIRECTORY_SEPARATOR == '\\') {
        $config->setServerIsWindows();
}

// Set up locwebsvnhttp
// Note: we will use nothing in MultiViews mode so that the URLs use the root
//               directory by default.
if (empty($locwebsvnhttp)) {
        $locwebsvnhttp = defined('WSVN_MULTIVIEWS') ? '' : '.';
}
if (empty($locwebsvnreal)) {
        $locwebsvnreal = '.';
}

$vars['locwebsvnhttp'] = $locwebsvnhttp;

// {{{ Content Types
// Set up the default content-type extension handling

$contentType = array(
        '.dwg'          => 'application/acad',                  // AutoCAD Drawing files
        '.arj'          => 'application/arj',
        '.ccad'         => 'application/clariscad',             // ClarisCAD files
        '.drw'          => 'application/drafting',              // MATRA Prelude drafting
        '.dxf'          => 'application/dxf',                   // DXF (AutoCAD)
        '.xls'          => 'application/excel',                 // Microsoft Excel
        '.unv'          => 'application/i-deas',                //SDRC I-DEAS files
        '.igs'          => 'application/iges',                  // IGES graphics format
        '.iges'         => 'application/iges',                  // IGES graphics format
        '.hqx'          => 'application/mac-binhex40',  // Macintosh BinHex format
        '.word'         => 'application/msword',                // Microsoft Word
        '.w6w'          => 'application/msword',                // Microsoft Word
        '.doc'          => 'application/msword',                // Microsoft Word
        '.wri'          => 'application/mswrite',               // Microsoft Write
        '.bin'          => 'application/octet-stream',  // Uninterpreted binary
        '.exe'          => 'application/x-msdownload',  // Windows EXE
        '.oda'          => 'application/oda',
        '.pdf'          => 'application/pdf',                   // PDF (Adobe Acrobat)
        '.ai'           => 'application/postscript',    // PostScript
        '.ps'           => 'application/postscript',    // PostScript
        '.eps'          => 'application/postscript',    // PostScript
        '.prt'          => 'application/pro_eng',               // PTC Pro/ENGINEER
        '.part'         => 'application/pro_eng',               // PTC Pro/ENGINEER
        '.rtf'          => 'application/rtf',                   // Rich Text Format
        '.set'          => 'application/set',                   // SET (French CAD standard)
        '.stl'          => 'application/sla',                   // Stereolithography
        '.sol'          => 'application/solids',                // MATRA Prelude Solids
        '.stp'          => 'application/STEP',                  // ISO-10303 STEP data files
        '.step'         => 'application/STEP',                  // ISO-10303 STEP data files
        '.vda'          => 'application/vda',                   // VDA-FS Surface data
        '.dir'          => 'application/x-director',    // Macromedia Director
        '.dcr'          => 'application/x-director',    // Macromedia Director
        '.dxr'          => 'application/x-director',    // Macromedia Director
        '.mif'          => 'application/x-mif',                 // FrameMaker MIF Format
        '.csh'          => 'application/x-csh',                 // C-shell script
        '.dvi'          => 'application/x-dvi',                 // TeX DVI
        '.gz'           => 'application/gzip',                  // GNU Zip
        '.gzip'         => 'application/gzip',                  // GNU Zip
        '.hdf'          => 'application/x-hdf',                 // ncSA HDF Data File
        '.latex'        => 'application/x-latex',               // LaTeX source
        '.nc'           => 'application/x-netcdf',              // Unidata netCDF
        '.cdf'          => 'application/x-netcdf',              // Unidata netCDF
        '.sit'          => 'application/x-stuffit',             // Stiffut Archive
        '.tcl'          => 'application/x-tcl',                 // TCL script
        '.texinfo'      => 'application/x-texinfo',             // Texinfo (Emacs)
        '.texi'         => 'application/x-texinfo',             // Texinfo (Emacs)
        '.t'            => 'application/x-troff',               // Troff
        '.tr'           => 'application/x-troff',               // Troff
        '.roff'         => 'application/x-troff',               // Troff
        '.man'          => 'application/x-troff-man',   // Troff with MAN macros
        '.me'           => 'application/x-troff-me',    // Troff with ME macros
        '.ms'           => 'application/x-troff-ms',    // Troff with MS macros
        '.src'          => 'application/x-wais-source', // WAIS source
        '.bcpio'        => 'application/x-bcpio',               // Old binary CPIO
        '.cpio'         => 'application/x-cpio',                // POSIX CPIO
        '.gtar'         => 'application/x-gtar',                // GNU tar
        '.shar'         => 'application/x-shar',                // Shell archive
        '.sv4cpio'      => 'application/x-sv4cpio',             // SVR4 CPIO
        '.sv4crc'       => 'application/x-sv4crc',              // SVR4 CPIO with CRC
        '.tar'          => 'application/x-tar',                 // 4.3BSD tar format
        '.ustar'        => 'application/x-ustar',               // POSIX tar format
        '.hlp'          => 'application/x-winhelp',             // Windows Help
        '.zip'          => 'application/zip',                   // ZIP archive

        '.au'   => 'audio/basic',       // Basic audio (usually m-law)
        '.snd'  => 'audio/basic',       // Basic audio (usually m-law)
        '.aif'  => 'audio/x-aiff',      // AIFF audio
        '.aiff' => 'audio/x-aiff',      // AIFF audio
        '.aifc' => 'audio/x-aiff',      // AIFF audio
        '.ra'   => 'audio/x-pn-realaudio',                      // RealAudio
        '.ram'  => 'audio/x-pn-realaudio',                      // RealAudio
        '.rpm'  => 'audio/x-pn-realaudio-plugin',       // RealAudio (plug-in)
        '.wav'  => 'audio/x-wav',       // Windows WAVE audio
        '.mp3'  => 'audio/x-mp3',       // MP3 files

        '.gif'  => 'image/gif',         // gif image
        '.ief'  => 'image/ief',         // Image Exchange Format
        '.jpg'  => 'image/jpeg',        // JPEG image
        '.jpe'  => 'image/jpeg',        // JPEG image
        '.jpeg' => 'image/jpeg',        // JPEG image
        '.pict' => 'image/pict',        // Macintosh PICT
        '.png'  => 'image/png',         // PNG image
        '.svg'  => 'image/svg+xml',     // Scalable vector graphics
        '.tiff' => 'image/tiff',        // TIFF image
        '.tif'  => 'image/tiff',        // TIFF image
        '.ras'  => 'image/x-cmu-raster',                // CMU raster
        '.pnm'  => 'image/x-portable-anymap',   // PBM Anymap format
        '.pbm'  => 'image/x-portable-bitmap',   // PBM Bitmap format
        '.pgm'  => 'image/x-portable-graymap',  // PBM Graymap format
        '.ppm'  => 'image/x-portable-pixmap',   // PBM Pixmap format
        '.rgb'  => 'image/x-rgb',                       // RGB Image
        '.xbm'  => 'image/x-xbitmap',           // X Bitmap
        '.xpm'  => 'image/x-xpixmap',           // X Pixmap
        '.xwd'  => 'image/x-xwindowdump',       // X Windows dump (xwd) format

        '.mpeg'         => 'video/mpeg',                // MPEG video
        '.mpg'          => 'video/mpeg',                // MPEG video
        '.mpe'          => 'video/mpeg',                // MPEG video
        '.mpeg'         => 'video/mpeg',                // MPEG video
        '.qt'           => 'video/quicktime',   // QuickTime Video
        '.mov'          => 'video/quicktime',   // QuickTime Video
        '.avi'          => 'video/msvideo',             // Microsoft Windows Video
        '.movie'        => 'video/x-sgi-movie', // SGI Movieplayer format
        '.wrl'          => 'x-world/x-vrml',    // VRML Worlds

        '.ods'  => 'application/vnd.oasis.opendocument.spreadsheet',                    // OpenDocument Spreadsheet
        '.ots'  => 'application/vnd.oasis.opendocument.spreadsheet-template',   // OpenDocument Spreadsheet Template
        '.odp'  => 'application/vnd.oasis.opendocument.presentation',                   // OpenDocument Presentation
        '.otp'  => 'application/vnd.oasis.opendocument.presentation-template',  // OpenDocument Presentation Template
        '.odg'  => 'application/vnd.oasis.opendocument.graphics',                               // OpenDocument Drawing
        '.otg'  => 'application/vnd.oasis.opendocument.graphics-template',              // OpenDocument Drawing Template
        '.odc'  => 'application/vnd.oasis.opendocument.chart',                                  // OpenDocument Chart
        '.otc'  => 'application/vnd.oasis.opendocument.chart-template',                 // OpenDocument Chart Template
        '.odf'  => 'application/vnd.oasis.opendocument.formula',                                // OpenDocument Formula
        '.otf'  => 'application/vnd.oasis.opendocument.formula-template',               // OpenDocument Formula Template
        '.odi'  => 'application/vnd.oasis.opendocument.image',                                  // OpenDocument Image
        '.oti'  => 'application/vnd.oasis.opendocument.image-template',                 // OpenDocument Image Template
        '.odb'  => 'application/vnd.oasis.opendocument.database',                               // OpenDocument Database
        '.odt'  => 'application/vnd.oasis.opendocument.text',                                   // OpenDocument Text
        '.ott'  => 'application/vnd.oasis.opendocument.text-template',                  // OpenDocument Text Template
        '.odm'  => 'application/vnd.oasis.opendocument.text-master',                    // OpenDocument Master Document
        '.oth'  => 'application/vnd.oasis.opendocument.text-web',                               // OpenDocument HTML Template
);

// }}}

// {{{ Enscript file extensions

// List of extensions recognised by enscript.

$extEnscript = array(
        '.ada'                          => 'ada',
        '.adb'                          => 'ada',
        '.ads'                          => 'ada',
        '.awk'                          => 'awk',
        '.c'                            => 'c',
        '.c++'                          => 'cpp',
        '.cc'                           => 'cpp',
        '.cmake'                        => 'cmake',
        'CMakeLists.txt'        => 'cmake',
        '.cpp'                          => 'cpp',
        '.csh'                          => 'csh',
        '.cxx'                          => 'cpp',
        '.diff'                         => 'diffu',
        '.dpr'                          => 'delphi',
        '.e'                            => 'eiffel',
        '.el'                           => 'elisp',
        '.eps'                          => 'postscript',
        '.f'                            => 'fortran',
        '.for'                          => 'fortran',
        '.gs'                           => 'haskell',
        '.h'                            => 'c',
        '.hpp'                          => 'cpp',
        '.hs'                           => 'haskell',
        '.htm'                          => 'html',
        '.html'                         => 'html',
        '.idl'                          => 'idl',
        '.java'                         => 'java',
        '.js'                           => 'javascript',
        '.json'                         => 'javascript',
        '.lgs'                          => 'haskell',
        '.lhs'                          => 'haskell',
        '.m'                            => 'objc',
        '.m4'                           => 'm4',
        '.man'                          => 'nroff',
        '.nr'                           => 'nroff',
        '.p'                            => 'pascal',
        '.pas'                          => 'delphi',
        '.patch'                        => 'diffu',
        '.pkg'                          => 'sql',
        '.pl'                           => 'perl',
        '.pm'                           => 'perl',
        '.pp'                           => 'pascal',
        '.ps'                           => 'postscript',
        '.s'                            => 'asm',
        '.scheme'                       => 'scheme',
        '.scm'                          => 'scheme',
        '.scr'                          => 'synopsys',
        '.sh'                           => 'sh',
        '.shtml'                        => 'html',
        '.sql'                          => 'sql',
        '.st'                           => 'states',
        '.syn'                          => 'synopsys',
        '.synth'                        => 'synopsys',
        '.tcl'                          => 'tcl',
        '.tex'                          => 'tex',
        '.texi'                         => 'tex',
        '.texinfo'                      => 'tex',
        '.v'                            => 'verilog',
        '.vba'                          => 'vba',
        '.vh'                           => 'verilog',
        '.vhd'                          => 'vhdl',
        '.vhdl'                         => 'vhdl',
        '.py'                           => 'python',
);

// }}}

// {{{ GeSHi file extensions

// List of extensions recognised by GeSHi.

$extGeshi = array(
        'actionscript3' => array('as'),
        'ada'                   => array('ada', 'adb', 'ads'),
        'asm'                   => array('ash', 'asi', 'asm'),
        'asp'                   => array('asp'),
        'bash'                  => array('sh'),
        'bibtex'                => array('bib'),
        'c'                             => array('c'),
        'cfm'                   => array('cfm', 'cfml'),
        'cmake'                 => array('cmake', 'CMakeLists.txt'),
        'cobol'                 => array('cbl'),
        'cpp'                   => array('cc', 'cpp', 'cxx', 'c++', 'h', 'hpp'),
        'csharp'                => array('cs'),
        'css'                   => array('css'),
        'd'                             => array('d'),
        'delphi'                => array('dpk', 'dpr', 'pas'),
        'diff'                  => array('diff', 'patch'),
        'dos'                   => array('bat', 'cmd'),
        'eiffel'                => array('e'),
        'erlang'                => array('erl'),
        'email'                 => array('eml'),
        'fortran'               => array('f', 'for', 'f90'),
        'gettext'               => array('po', 'pot'),
        'gml'                   => array('gml'),
        'gnuplot'               => array('plt'),
        'groovy'                => array('groovy'),
        'haskell'               => array('gs', 'hs', 'lgs', 'lhs'),
        'html4strict'   => array('html', 'htm'),
        'idl'                   => array('idl'),
        'ini'                   => array('desktop', 'ini'),
        'java5'                 => array('java'),
        'javascript'    => array('js', 'json'),
        'latex'                 => array('tex'),
        'lisp'                  => array('lisp'),
        'lua'                   => array('lua'),
        'make'                  => array('make'),
        'matlab'                => array('m'),
        'perl'                  => array('pl', 'pm'),
        'php'                   => array('php', 'php3', 'php4', 'php5', 'phps', 'phtml'),
        'povray'                => array('pov'),
        'properties'    => array('properties'),
        'providex'              => array('pvc', 'pvx'),
        'python'                => array('py'),
        'reg'                   => array('reg'),
        'ruby'                  => array('rb'),
        'scala'                 => array('scala'),
        'scheme'                => array('scm', 'scheme'),
        'scilab'                => array('sci'),
        'smalltalk'             => array('st'),
        'sql'                   => array('sql'),
        'tcl'                   => array('tcl'),
        'vb'                    => array('bas'),
        'vbnet'                 => array('vb'),
        'vh'                    => array('v', 'verilog'),
        'vhdl'                  => array('vhd', 'vhdl'),
        'vim'                   => array('vim'),
        'whitespace'    => array('ws'),
        'xml'                   => array('xml', 'xsl', 'xsd', 'xib', 'wsdl', 'svg', 'plist', 'jmx'),
        'z80'                   => array('z80'),
);

// }}}

// Loads English localized strings by default (must go before config.php)
require 'languages/english.php';

// Support one WebSVN installation hosting multiple different SVNParentPaths, distinguished by their
// location. Per location, the web server needs to set some environment variable providing the path
// to the config to either exclusively or additionally include, implementing a simple layered config
// this way. That allows, e.g., changing paths to repos per location only and share everything else.
//
// The following implementation deals with multiple most likely problems in such an environment, like
// HTTP redirects influencing the name of the environment variable set and "preg_grep" indexing its
// results depending on the input, so optionally changing between requests.
//
// https://stackoverflow.com/q/3050444/696632
// https://bz.apache.org/bugzilla/show_bug.cgi?id=58739
$confSuccess = 0;
$envPathConf = preg_grep('/^(?:REDIRECT_)*WEBSVN_PATH_CONF$/', array_keys($_SERVER));
$envPathConf = array_values($envPathConf);
$envPathConf = array_key_exists(0, $envPathConf)
                                ? $_SERVER[$envPathConf[0]]
                                : '';

// Get the user's personalised config (requires the locwebsvnhttp stuff above).
if (file_exists('include/config.php')) {
        require_once 'include/config.php';
        $confSuccess = 1;
}
if (!empty($envPathConf)) {
        require_once $envPathConf;
        $confSuccess = 1;
}
if (!$confSuccess) {
        die('No config applied, either create "include/config.php" or use environment variable '        .
                '"WEBSVN_PATH_CONF". The example file "include/distconfig.php" should be copied and '   .
                'modified as needed.');
}

// Make sure that the input locale is set up correctly
putenv("LANG=".setlocale(LC_ALL, $config->getLocale()));

$vars['showageinsteadofdate'] = $config->showAgeInsteadOfDate();

// Initialize the version of SVN that is being used by WebSVN internally.
require_once 'include/svnlook.php';
$vars['svnversion'] = $config->getSubversionVersion();

// Initialize an array with all query parameters except language and template.
$queryParams = $_GET + $_POST;
unset($queryParams['language']);
unset($queryParams['template']);
$hidden = '';
foreach ($queryParams as $key => $value) {
        if (is_array($value)) {
                for ($i = 0; $i < count($value); $i++) {
                        $hidden .= '<input type="hidden" name="'.escape($key).'[]" value="'.escape($value[$i]).'"/>';
                }
        } else {
                $hidden .= '<input type="hidden" name="'.escape($key).'" value="'.escape($value).'"/>';
        }
}

// If the request specifies a language, store in a cookie. Otherwise, check for cookies specifying a
// particular language already.
$language = ''; // RFC 4646 language tag for representing the selected language.
if (!empty($_REQUEST['language'])) {
        $language = $_REQUEST['language'];
        setcookie('storedlang', $language, time() + (60 * 60 * 24 * 356 * 10));
        setcookie('storedsesslang', $language);
} else if (isset($_COOKIE['storedlang'])) {
        $language = $_COOKIE['storedlang'];
} else if (isset($_COOKIE['storedsesslang'])) {
        $language = $_COOKIE['storedsesslang'];
}

// Load available languages (populates $languages array)
require 'languages/languages.php';
// Get the default language as defined by config.php
$defaultLanguage = $config->getDefaultLanguage();
if (!isset($languages[$defaultLanguage]))
        $defaultLanguage = 'en';
// Determine which language to actually use
$language = getUserLanguage($languages, $defaultLanguage, $language);
$vars['language_code'] = $language;
// For languages other than English, load translated strings over existing ones.
if ($language != 'en')
        require 'languages/'.$languages[$language][0].'.php';
// Generate the HTML form for selecting a different language
$vars['language_form'] = '<form method="get" action="" id="language">'.$hidden;
$vars['language_select'] = '<select name="language" onchange="javascript:this.form.submit();">';
foreach ($languages as $code => $names) {
        $sel = ($code == $language) ? '" selected="selected' : '';
        $vars['language_select'] .= '<option value="'.$code.$sel.'">'.$names[2].' &ndash; '.$names[1].'</option>';
}
$vars['language_select'] .= '</select>';
$vars['language_submit'] = '<noscript><input type="submit" value="'.$lang['GO'].'" /></noscript>';
$vars['language_endform'] = '</form>';

// Load repository if possible
if ($config->multiViews) {
        $rep = null; // MultiViews has custom code to load a repository
} else {
        // Load repository matching 'repname' parameter (if set) or the default.
        $repname = @$_REQUEST['repname'];
        if (isset($repname)) {
                $rep = $config->findRepository($repname);
        } else {
                $reps = $config->getRepositories();
                $rep = (isset($reps[0]) ? $reps[0] : null);
        }
        // Make sure that the user has set up a repository
        if ($rep == null) {
                $vars['error'] = $lang['SUPPLYREP'];
        } else if (is_string($rep)) {
                $vars['error'] = $rep;
                $rep = null;
        } else {
                $vars['repurl'] = $config->getURL($rep, '', 'dir');
                $vars['clientrooturl'] = $rep->clientRootURL;
                $vars['repname'] = escape($rep->getDisplayName());
                $vars['allowdownload'] = $rep->getAllowDownload();
        }
}

// If the request specifies a template, store in a cookie. Otherwise, check for cookies specifying a
// particular template already.
$template = '';
if (!empty($_REQUEST['template'])) {
        $template = $_REQUEST['template'];
        setcookie('storedtemplate', $template, time() + (60 * 60 * 24 * 365 * 10));
        setcookie('storedsesstemplate', $template);
} else if (isset($_COOKIE['storedtemplate'])) {
        $template = $_COOKIE['storedtemplate'];
} else if (isset($_COOKIE['storedsesstemplate'])) {
        $template = $_COOKIE['storedsesstemplate'];
}

$templates = array();
// Skip creating template list when selected repository has specific template.
if ($rep == null || $rep->templatePath === false) {
        // Get all templates defined in config.php; use last path component as name.
        foreach ($config->templatePaths as $path) {
                $templates[$path] = basename($path);
        }
        $selectedTemplatePath = $config->getTemplatePath();
        if ($template != '' && in_array($template, $templates)) {
                $selectedTemplatePath = array_search($template, $templates);
                $config->userTemplate = $selectedTemplatePath;
        }
}

// Generate the HTML form for selecting a different template
if (count($templates) > 1) {
        $vars['template_form'] = '<form method="get" action="" id="template">'.$hidden;
        $vars['template_select'] = '<select name="template" onchange="javascript:this.form.submit();">';
        natcasesort($templates);
        foreach ($templates as $path => $name) {
                $sel = ($path == $selectedTemplatePath) ? ' selected="selected"' : '';
                $vars['template_select'] .= '<option value="'.$name.'"'.$sel.'>'.$name.'</option>';
        }
        $vars['template_select'] .= '</select>';
        $vars['template_submit'] = '<noscript><input type="submit" value="'.$lang['GO'].'" /></noscript>';
        $vars['template_endform'] = '</form>';
} else {
        $vars['template_form'] = '';
        $vars['template_select'] = '';
        $vars['template_submit'] = '';
        $vars['template_endform'] = '';
}

$vars['indexurl'] = $config->getURL('', '', 'index');
$vars['validationurl'] = getFullURL($_SERVER['SCRIPT_NAME']).'?'.buildQuery($queryParams + array('template' => $template, 'language' => $language), '%26');

$path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : null;
if ($path === null || $path === '')
        $path = '/';
$vars['path'] = str_replace('%2F', '/', rawurlencode($path));
$vars['safepath'] = escape($path);
// Set operative and peg revisions (if specified) and save passed-in revision
$rev = (int)@$_REQUEST['rev'];
$peg = (int)@$_REQUEST['peg'];
$search = (string)@$_REQUEST['search'];
if ($peg === 0)
        $peg = '';
$passrev = $rev;

if (!$config->multiViews) {
        // With MultiViews, browse creates the form once the current project is found.
        createProjectSelectionForm();
        createRevisionSelectionForm();
        createSearchSelectionForm();
}

// set flag if robots should be blocked
$vars['blockrobots'] = $config->areRobotsBlocked();

$listing = array();

// Set up response headers
header('Content-Type: text/html; charset=UTF-8');
header('Content-Language: '.$language);

// Function to create the project selection HTML form
function createProjectSelectionForm() {
        global $config, $vars, $rep, $lang;

        $vars['projects_form'] = '';
        $vars['projects_select'] = '';
        $vars['projects_submit'] = '';
        $vars['projects_endform'] = '';

        if (!$config->showRepositorySelectionForm() || count($config->getRepositories()) < 2)
                return;

        if ($rep) {
                $currentRepoName = $rep->getDisplayName();
                $options = '';
        } else {
                $currentRepoName = '';
                $options = '<option value="" selected="selected"></option>';
        }
        foreach ($config->getRepositories() as $repository) {
                if ($repository->hasReadAccess('/')) {
                        $repoName = $repository->getDisplayName();
                        $sel = ($repoName == $currentRepoName) ? ' selected="selected"' : '';
                        $options .= '<option value="'.escape($repoName).'"'.$sel.'>'.escape($repoName).'</option>';
                }
        }
        if (strlen($options) === 0)
                return;

        $vars['projects_form'] = '<form method="get" action="" id="project">';
        if ($config->multiViews)
                $vars['projects_form'] .= '<input type="hidden" name="op" value="rep" />';
        $vars['projects_select'] = '<select name="repname" onchange="javascript:this.form.submit();">'.$options.'</select>';
        $vars['projects_submit'] = '<noscript><input type="submit" value="'.$lang['GO'].'" /></noscript>';
        $vars['projects_endform'] = '</form>';
}

// Function to create the revision selection HTML form
function createRevisionSelectionForm() {
        global $config, $lang, $vars, $rep, $path, $rev, $peg;

        if ($rep == null)
                return;

        $params = array();
        if (!$config->multiViews) {
                $params['repname'] = $rep->getDisplayName();
                if ($path === null)
                        $path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : null;
                if ($path && $path != '/')
                        $params['path'] = $path;
        }
        if ($peg || $rev)
                $params['peg'] = ($peg ? $peg : $rev);
        $hidden = '';
        foreach ($params as $key => $value) {
                $hidden .= '<input type="hidden" name="'.$key.'" value="'.escape($value).'" />';
        }
        // The blank "action" attribute makes form link back to the containing page.
        $vars['revision_form'] = '<form method="get" action="" id="revision">'.$hidden;
        if ($rev === null)
                $rev = (int)@$_REQUEST['rev'];
        $vars['revision_input'] = '<input type="text" size="5" name="rev" placeholder="'.($rev ? $rev : 'HEAD').'" />';
        $vars['revision_submit'] = '<input type="submit" value="'.$lang['GO'].'" />';
        $vars['revision_endform'] = '</form>';
}

function createSearchSelectionForm() {
        global $config, $lang, $vars, $rep, $path, $rev, $peg, $search;
        if ($rep === null)
                return;
        $params = array();
        if (!$config->multiViews) {
                $params['repname'] = $rep->getDisplayName();
                if ($path === null)
                        $path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : null;
                if ($path && $path != '/')
                        $params['path'] = $path;
        }
        if ($peg || $rev)
                $params['rev'] = ($peg ? $peg : $rev);
        $hidden = '';
        foreach ($params as $key => $value) {
                $hidden .= '<input type="hidden" name="'.$key.'" value="'.escape($value).'" />';
        }
        $vars['search'] = true;
        $vars['search_form'] = '<form method="get" action="'.$config->getURL($rep, '', 'search').'" id="search">'.$hidden;
        $search = $search? $search : $lang['SEARCH_PLACEHOLDER'];
        $vars['search_input'] = '<input type="text" size="20" name="search" placeholder="'.$search.'" />';
        $vars['search_submit'] = '<input type="submit" value="'.$lang['SEARCH'].'" />';
        $vars['search_endform'] = '</form>';
}
function sendHeaderForbidden() {
        http_response_code(403);
}