<?

// File Type Constants
define('FT_FILE'			, 4);
define('FT_DIRECTORY'		, 3);
define('FT_DIRECTORYUP'		, 2);
define('FT_DIRECTORYREFRESH', 1);

// Sort Type Constants
define('SORT_TYPE'		, 'Description');
define('SORT_NAME'		, 'Char');
define('SORT_SIZE'		, 'SizeGroup');
define('SORT_MODIFY'	, 'ModifyGrp');
define('SORT_ACCESS'	, 'AccessGrp');
define('SORT_OWNER'		, 'Owner');
define('SORT_GROUP'		, 'Group');
define('SORT_PERMISSION', 'Permission');

// Readme File Constants
define('RF_TEXT', 1);
define('RF_HTML', 2);

// Define version
define('XPindex_Author',	'Micha&euml;l Hompus');
define('XPindex_AuthorMail','xpindex@hompus.nl');
define('XPindex_URL',		'http://www.hompus.nl/xpindex/');
define('XPindex_Version',	'1.70');
define('XPindex_Date',		'2003-02-23T00:16:00+01:00');

// Global vars
$RequestURI	= '';
$Directory		= '';
$SortField		= '';
$FileArray		= array();
$bTaskBar		= false;
$fDirSize		= 0;

// Check if there is an entry for 'sort' in the $_GET array
$GetSort = (array_key_exists('sort', $_GET)) ? $_GET['sort'] : '' ;

// Only accept valid sort items, else it will be defaulted to SORT_TYPE
switch ($GetSort) {
	case 'char':
	case 'name':
		$sSortField = SORT_NAME;
		break;
	case 'size':
		$sSortField = SORT_SIZE;
		break;
	case 'modify':
		$sSortField = SORT_MODIFY;
		break;
	case 'access':
		$sSortField = SORT_ACCESS;
		break;
	case 'owner':
		$sSortField = SORT_OWNER;
		break;
	case 'group':
		$sSortField = SORT_GROUP;
		break;
	case 'permission':
		$sSortField = SORT_PERMISSION;
		break;
	case 'description':
	case 'type':
	default:
		$sSortField = SORT_TYPE;
}

// Parse the url to the physical directory
ParseURL($RequestURI, $Directory);

// The title of the page, should be the same as the address displayed by the browser
// Tricky part: Forwarded servers
$title = ((array_key_exists('HTTP_X_FORWARDED_SERVER', $_SERVER)) ? $_SERVER['HTTP_X_FORWARDED_SERVER'] : $_SERVER['SERVER_NAME']) . rawurldecode($_SERVER['REQUEST_URI']);

function ParseURL(&$RequestURI, &$Directory) {
	global $XPIndexConf, $ApacheConf;

	if ($XPIndexConf['Hide XPindex Dir'] == true) {
		// Hide the XPindex source
		$iPos = strpos(rawurldecode($_SERVER['REQUEST_URI']), $XPIndexConf['Web Directory']);
		if (is_integer($iPos) && ($iPos == 0)) {
			// Make the browser understand it's an error
			header("HTTP/1.0 404 Not Found");
			header("Status: 404 Not Found");
			// Do some advertising, the apache 404 page would be nicer
			echo '<a href="' . XPindex_URL . '">XPindex ' . XPindex_Version . '</a> by <a href="mailto:' . XPindex_AuthorMail . '">' . XPindex_Author . '</a>.';
	    	exit();
		}
	}

	$DocumentRoot = rawurldecode($_SERVER['DOCUMENT_ROOT']);
	$RequestURI = $_SERVER['REQUEST_URI'];
	$RequestURI = rawurldecode(substr($_SERVER['REQUEST_URI'], 0, (strpos($RequestURI, '?')) ? strpos($RequestURI, '?') : strlen($RequestURI)));
	$Directory = $DocumentRoot . $RequestURI;

	$d = @dir($Directory);

	if ($d === false) {
		$RequestedDir	= substr($RequestURI, 2);
		$UserDir		= substr($RequestedDir, 0, strpos($RequestedDir, '/'));
		$RequestedDir	= substr($RequestedDir, strpos($RequestedDir, '/'));

		$Directory = rawurldecode($ApacheConf['User Directories'] . '/' . $UserDir . '/' . $ApacheConf['User HTML Directory'] . $RequestedDir);
	} else {
		$d->close();
	}
}

function ParseDir(&$Directory) {
	global $ApacheConf, $sSortField, $FileArray;

	$d = @dir($Directory);

	while ($Entry = $d->read()) {
		if (!((array_key_exists($Entry, $ApacheConf['Readme Files'])) && ($ApacheConf['Readme Files'][$Entry][1] == false))) {
			// Entry is not a (hidden) Readme file
			AddFileToArray($FileArray, $Directory, $Entry);
		}
	}

	$d->close();

	aasort($FileArray, 'Type');

	if ($FileArray[0]['Type'] == FT_DIRECTORYREFRESH|FT_DIRECTORYUP) {
		$Dots = array_splice($FileArray, 0, 1);
		PrintFile($Dots[0], NULL, FT_DIRECTORYREFRESH);
		PrintFile($Dots[0], NULL, FT_DIRECTORYUP);
	}

	if ($FileArray[0]['Type'] == FT_DIRECTORYREFRESH|FT_DIRECTORYUP) {
		$Dots = array_splice($FileArray, 0, 1);
		PrintFile($Dots[0], NULL, FT_DIRECTORYUP);
	}

	aasort($FileArray, $sSortField);

	$CurrentGroup = array();
	$CurrentGroup['Sortvalue'] = '';
	$CurrentGroup['Items'] = array();

	array_walk($FileArray, 'WalkGroups', &$CurrentGroup);

	if (count($CurrentGroup['Items']) > 0) {
		aasort($CurrentGroup['Items'], 'Name');

		array_walk($CurrentGroup['Items'], 'PrintFile', FT_DIRECTORY);
		array_walk($CurrentGroup['Items'], 'PrintFile', FT_FILE);
	}
}

function AddFileToArray(&$FileArray, $FileDirectory, $File) {
	global $FileExtensions, $IncrementalFileExtensions, $XPIndexConf, $Captions;

	$FilePath = $FileDirectory . '/' . $File;

	if (!is_dir($FilePath)) {
		$FileType = FT_FILE;
	} else if ($File == '.') {
		$FileType = FT_DIRECTORYREFRESH;
	} else if ($File == '..') {
		$FileType = FT_DIRECTORYUP;
	} else {
		$FileType = FT_DIRECTORY;
	}

	$FileExtension = split('\.', $File);
	$FileExtension = (($FileExtension[count($FileExtension) - 1] != $File) ? $FileExtension[count($FileExtension) - 1] : '');

	$FileDescription = '';

	if ($FileType == FT_DIRECTORYREFRESH) {
		$FileExtension = 'Refresh';
	} else if ($FileType == FT_DIRECTORYUP) {
		$FileExtension = 'Directory Up';
	} else if ($FileType == FT_DIRECTORY) {
		$FileExtension = 'Directory';
		$FileDescription = $FileExtensions[$FileExtension][$XPIndexConf['Language']];
	} else if (preg_match('/^(\D{1})\d{2}$/', $FileExtension, $matches)) {
		if (array_key_exists($matches[1], $IncrementalFileExtensions)) {
			$FileExtension = $IncrementalFileExtensions[$matches[1]];
			$FileDescription = $FileExtensions[$FileExtension][$XPIndexConf['Language']];
		} else if (array_key_exists($FileExtension, $FileExtensions)) {
			$FileDescription = $FileExtensions[$FileExtension][$XPIndexConf['Language']];
		} else if ($FileExtension != '') {
			$FileDescription = strtoupper($FileExtension) . '-' . $Captions['file'][$XPIndexConf['Language']];
		} else {
			$FileDescription = ucfirst($Captions['file'][$XPIndexConf['Language']]);
		}
	} else if (array_key_exists($FileExtension, $FileExtensions)) {
		$FileDescription = $FileExtensions[$FileExtension][$XPIndexConf['Language']];
	} else if ($FileExtension != '') {
		$FileDescription = strtoupper($FileExtension) . '-' . $Captions['file'][$XPIndexConf['Language']];
	} else {
		$FileDescription = ucfirst($Captions['file'][$XPIndexConf['Language']]);
	}

	if ($FileType == FT_FILE) {
		$FileSize = filesize($FilePath);
		$GLOBALS['fDirSize'] += $FileSize;
	} else {
	 	$FileSize = '';
	}

	if (!(($FileType == FT_FILE) && ($File[0] == '.'))) {
		// Skip files which have a . as first character of the name
		$FileArray[] = Array(
			'Name'			=> $File,
			'Type'			=> $FileType,
			'Extension'		=> $FileExtension,
			'Description'	=> $FileDescription,
			'Char'			=> strtoupper($File[0]),
			'Size'			=> $FileSize,
			'SizeGroup'		=> GetSizeGroup($FileSize/1024, $FileType),
			'Owner'			=> GetFileOwner($FilePath),
			'Group'			=> GetFileGroup($FilePath),
			'Permission'	=> fileperms($FilePath),
			'Modify'		=> filemtime($FilePath),
			'ModifyGrp'		=> GetDateGroup(filemtime($FilePath)),
			'Access'		=> fileatime($FilePath),
			'AccessGrp'		=> GetDateGroup(fileatime($FilePath))
		);
	}
}

function GetFileOwner($File) {
	$File = posix_getpwuid(fileowner($File));

	return $File['name'];
}

function GetFileGroup($File) {
	$File = posix_getgrgid(filegroup($File));

	return $File['name'];
}

function aasort(&$FileArray, $SortColumn, $SortFlags = 'strcasecmp') {
	if (is_string($SortColumn)) $SortColumn = "'$SortColumn'";

	uasort($FileArray, create_function('$a, $b', 'return ' . $SortFlags . ' ($a[' . $SortColumn . '], $b[' . $SortColumn . ']);'));
}

function GetSizeGroup($Value, $FileType) {
	if ($FileType != FT_FILE) {
		return 9;
	} else if ($Value == 0) {
		return 1;
	} else if ($Value < pow(2, 5)) {
		return 2;
	} else if ($Value < pow(2, 7)) {
		return 3;
	} else if ($Value < pow(2, 10)) {
		return 4;
	} else if ($Value < pow(2, 14)) {
		return 5;
	} else if ($Value < pow(2, 17)) {
		return 6;
	} else {
		return 7;
	}
}

function GetDateGroup($Value) {
	$Date = getdate($Value);

	$Today = getdate();

	if ($Date[0] > $Today[0]) {
		// Future
		if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['mday'] == $Today['mday'])) {
			return '01';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['mday'] == $Today['mday'] + 1)) {
			return '13';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['mday'] == $Today['mday'] + 2)) {
			return '14';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['yday'] <= ($Today['yday'] + (7 - $Today['wday'])))) {
			return '15';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon'])) {
			return '16';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon'] + 1)) {
			return '17';
		} else if ($Date['year'] == $Today['year']) {
			return '18';
		} else if ($Date['year'] == $Today['year'] + 1) {
			return '19';
		} else if ($Date['year'] == $Today['year'] + 2) {
			return '20';
		} else {
			return '21';
		}
	} else {
		// Past
		if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['mday'] == $Today['mday'])) {
			return '01';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['mday'] == $Today['mday'] - 1)) {
			return '02';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['yday'] >= ($Today['yday'] - $Today['wday']))) {
			return '03';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['yday'] >= ($Today['yday'] - $Today['wday'] - 7))) {
			return '04';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon']) && ($Date['yday'] >= ($Today['yday'] - $Today['wday'] - 14))) {
			return '05';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon'])) {
			return '06';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon'] - 1)) {
			return '07';
		} else if (($Date['year'] == $Today['year']) && ($Date['mon'] == $Today['mon'] - 2)) {
			return '08';
		} else if ($Date['year'] == $Today['year']) {
			return '09';
		} else if ($Date['year'] == ($Today['year'] - 1)) {
			return '10';
		} else if ($Date['year'] == ($Today['year'] - 2)) {
			return '11';
		} else {
			return '12';
		}
	}
}

function DisplayFilePermissions($Mode) {
	// Determine Type
	if ($Mode & 0x1000) {
		$Type = 'p';	// FIFO pipe
	} else if ($Mode & 0x2000) {
		$Type = 'c';	// Character special
	} else if ($Mode & 0x4000) {
		$Type = 'd';	// Directory
	} else if ($Mode & 0x6000) {
		$Type = 'b';	// Block special
	} else if ($Mode & 0x8000) {
		$Type = '-';	// Regular
	} else if ($Mode & 0xA000) {
		$Type = 'l';	// Symbolic Link
	} else if ($Mode & 0xC000) {
		$Type = 's';	// Socket
	} else {
		$Type = 'u';	// UNKNOWN
	}

	// Determine permissions
	$Owner['read']    = ($Mode & 00400) ? 'r' : '-';
	$Owner['write']   = ($Mode & 00200) ? 'w' : '-';
	$Owner['execute'] = ($Mode & 00100) ? 'x' : '-';
	$Group['read']    = ($Mode & 00040) ? 'r' : '-';
	$Group['write']   = ($Mode & 00020) ? 'w' : '-';
	$Group['execute'] = ($Mode & 00010) ? 'x' : '-';
	$World['read']    = ($Mode & 00004) ? 'r' : '-';
	$World['write']   = ($Mode & 00002) ? 'w' : '-';
	$World['execute'] = ($Mode & 00001) ? 'x' : '-';

	// Adjust for SUID, SGID and sticky bit
	if ($Mode & 0x800) $Owner['execute'] = ($Owner['execute'] == 'x') ? 's' : 'S';
	if ($Mode & 0x400) $Group['execute'] = ($Group['execute'] == 'x') ? 's' : 'S';
	if ($Mode & 0x200) $World['execute'] = ($World['execute'] == 'x') ? 't' : 'T';

	return
		$Type
		. $Owner['read'] . $Owner['write'] . $Owner['execute']
		. $Group['read'] . $Group['write'] . $Group['execute']
		. $World['read'] . $World['write'] . $World['execute'];
}

function DisplayFileSize($Value) {
	if ($Value === '') {
		return '';
	} else if ($Value < pow(2, 10)) {
		return number_format($Value, 0, ',', '.') . ' B';
	} else if ($Value < pow(2, 20)) {
		return number_format($Value/pow(2, 10), 0, ',', '.') . ' kB';
	} else if ($Value < pow(2, 30)) {
		return number_format($Value/pow(2, 20), 0, ',', '.') . ' MB';
	} else {
		$return = number_format($Value/pow(2, 30), 0, ',', '.') . ' GB';
	}
}

function DisplayTotalFileSize($Value) {
	if ($Value === '') {
		return '';
	} else if ($Value < pow(2, 10)) {
		$return = number_format($Value, 0, ',', '.') . ' bytes';
	} else if ($Value < pow(2, 10) * 100) {
		$return = number_format($Value/pow(2, 10), 2, ',', '.') . ' kB';
	} else if ($Value < pow(2, 20)) {
		$return = number_format($Value/pow(2, 10), 0, ',', '.') . ' kB';
	} else if ($Value < pow(2, 20) * 100) {
		$return = number_format($Value/pow(2, 10), 1, ',', '.') . ' MB';
	} else if ($Value < pow(2, 30)) {
		$return = number_format($Value/pow(2, 20), 0, ',', '.') . ' MB';
	} else {
		$return = number_format($Value/pow(2, 30), 2, ',', '.') . ' GB';
	}

	return preg_replace('/,00/', '', $return);
}

function WalkGroups($File, $Counter, $CurrentGroup) {
	global $sSortField;

	if ($CurrentGroup['Sortvalue'] != $File[$sSortField]) {
		if (count($CurrentGroup['Items']) > 0) {
			aasort($CurrentGroup['Items'], 'Name');

			array_walk($CurrentGroup['Items'], 'PrintFile', FT_DIRECTORY);
			array_walk($CurrentGroup['Items'], 'PrintFile', FT_FILE);
		}

		$CurrentGroup['Items'] = Array();

		$CurrentGroup['Sortvalue'] = $File[$sSortField];
		PrintGroup($CurrentGroup['Sortvalue']);
	}

	$CurrentGroup['Items'][$File['Name']] = $File;
}

function PrintGroup($GroupName) {
	global $sSortField, $FileSizeGroups, $FileDateGroups, $XPIndexConf;

	switch($sSortField) {
		case SORT_SIZE:
			$GroupName = $FileSizeGroups[$GroupName][$XPIndexConf['Language']];
			break;
		case SORT_MODIFY:
		case SORT_ACCESS:
			$GroupName = $FileDateGroups[$GroupName][$XPIndexConf['Language']];
			break;
		case SORT_PERMISSION:
			$GroupName = DisplayFilePermissions($GroupName);
			break;
	}

?>								<tr>
									<td colspan="7">&nbsp;</td>
								</tr>
								<tr>
									<td colspan="7" class="group-<?=$XPIndexConf['Theme']?>"><?=$GroupName?></td>
								</tr>
<?
}

function PrintFile($File, $Counter, $FileType) {
	if ($File['Type'] == $FileType) {
		global $XPIndexConf, $FileIcons;

		$FileIcon = '';

		if (array_key_exists($File['Extension'], $FileIcons)) {
			$FileIcon = $XPIndexConf['Web Directory'] . '/icons/' . $FileIcons[$File['Extension']];
		} else {
			$FileIcon = $XPIndexConf['Web Directory'] . '/icons/none.png';
		}
?>								<tr>
									<td class="left">
										<a href="./<?=$File['Name']?>" title="<?=$File['Name']?>" class="<?=$XPIndexConf['Theme']?>"><img src="<?=$FileIcon?>" class="icon" alt="" />&nbsp;<?=$File['Name']?></a>
									</td>
									<td class="right"><?=DisplayFileSize($File['Size'])?></td>
									<td class="left"><?=$File['Description']?></td>
									<td class="left"><?=date("d-m-Y H:m", $File['Modify'])?></td>
									<td class="left"><?=$File['Owner']?></td>
									<td class="left"><?=$File['Group']?></td>
									<td class="left"><?=DisplayFilePermissions($File['Permission'])?></td>
								</tr>
<?
	}
}

function CheckForReadme($Readme, $File, $aReadme) {
	if (file_exists($GLOBALS['Directory'] . $File)) {
		$aReadme[] = Array("$File", $Readme);
	}
}

function PrintReadme($Readme, $Priority) {
	global $Directory, $ApacheConf, $XPIndexConf, $Captions;

	$fReadme = @fopen($Directory . $Readme[0], r);
?>						<table cellspacing="0" cellpadding="0" class="task">
							<tr>
								<th class="task-<?=$XPIndexConf['Theme']?>"><?=$Captions[$Readme[1][2]][$XPIndexConf['Language']]?></th>
							</tr>
							<tr>
								<td class="task-<?=$XPIndexConf['Theme']?>">
<?
	if ($Readme[1][0] == 'RF_TEXT') {
?>									<div class="task-text"><?=preg_replace('/[\s]+/', '<br />', preg_replace('/[ ]/', '&nbsp;', fread($fReadme, filesize($Directory . $Readme[0]))))?></div>
<?
	} else {
?>									<div class="task-html"><?=fread($fReadme, filesize($Directory . $Readme[0]))?></div>
<?
	}
?>								</td>
							</tr>
						</table>
<?
}

function DrawTaskBar(&$Directory) {
	global $XPIndexConf, $ApacheConf, $bTaskBar, $Captions;

	array_walk($ApacheConf['Readme Files'], 'CheckForReadme', &$aReadme);

	if (($XPIndexConf['TaskBar'] == 'always') || (($XPIndexConf['TaskBar'] == 'readme') && (count($aReadme) > 0))) {
		$bTaskBar = true;
?>
					<td class="taskbar-<?=$XPIndexConf['Theme']?>">
<?
	}

	if (count($aReadme) > 0) {
		array_walk($aReadme, 'PrintReadme');
	}

	if (($XPIndexConf['TaskBar'] == 'always') || (($XPIndexConf['TaskBar'] == 'readme') && (count($aReadme) > 0))) {
?>
						<div style="width: 240px">&nbsp;</div>
					</td>
<?
	}
}


function DrawStatusBar() {
	global $XPIndexConf, $Captions, $FileArray, $fDirSize;
?>			<tr>
				<td class="statusbar" colspan="2">
					<table cellspacing="0" cellpadding="0" class="status-<?=$XPIndexConf['Theme']?>">
						<tr>
							<td class="status-<?=$XPIndexConf['Theme']?>" style="width: 74%"><?=count($FileArray) . ' ' . $Captions['objects'][$XPIndexConf['Language']]?></td>
							<td class="status-<?=$XPIndexConf['Theme']?>" style="width: 7%"><?=DisplayTotalFileSize($fDirSize)?></td>
							<td style="width: 19%">&nbsp;</td>
						</tr>
					</table>
				</td>
			</tr>
<?
}

?>
