logsShowChanges();
$search = trim(@$_REQUEST['search']);
$dosearch = strlen($search) > 0;
$words = preg_split('#\s+#', $search);
$fromRev = (int)@$_REQUEST['fr'];
$startrev = strtoupper(trim(@$_REQUEST['sr']));
$endrev = strtoupper(trim(@$_REQUEST['er']));
$max = isset($_REQUEST['max']) ? (int)$_REQUEST['max'] : false;
// Max number of results to find at a time
$numSearchResults = 20;
if ($search == '') {
$dosearch = false;
}
// removeAccents
//
// Remove all the accents from a string. This function doesn't seem
// ideal, but expecting everyone to install 'unac' seems a little
// excessive as well...
function removeAccents($string) {
$string = htmlentities($string, ENT_QUOTES, 'ISO-8859-1');
$string = preg_replace('/&([A-Za-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron);/', '$1', $string);
return $string;
}
// Normalise the search words
foreach ($words as $index => $word) {
$words[$index] = strtolower(removeAccents($word));
// Remove empty string introduced by multiple spaces
if (empty($words[$index]))
unset($words[$index]);
}
if (empty($page))
$page = 1;
// If searching, display all the results
if ($dosearch)
$all = true;
$maxperpage = 20;
// Make sure that we have a repository
if ($rep) {
$svnrep = new SVNRepository($rep);
$history = $svnrep->getLog($path, 'HEAD', '', false, 1, ($path == '/') ? '' : $peg);
if (!$history) {
unset($vars['error']);
$history = $svnrep->getLog($path, '', '', false, 1, ($path == '/') ? '' : $peg);
if (!$history) {
header('HTTP/1.x 404 Not Found', true, 404);
$vars['error'] = $lang['NOPATH'];
}
}
$youngest = ($history && isset($history->entries[0])) ? $history->entries[0]->rev : 0;
if (empty($startrev)) {
//$startrev = ($rev) ? $rev : 'HEAD';
$startrev = $rev;
} else if ($startrev != 'HEAD' && $startrev != 'BASE' && $startrev != 'PREV' && $startrev != 'COMMITTED') {
$startrev = (int)$startrev;
}
if (empty($endrev)) {
$endrev = 1;
} else if ($endrev != 'HEAD' && $endrev != 'BASE' && $endrev != 'PREV' && $endrev != 'COMMITTED') {
$endrev = (int)$endrev;
}
if (empty($rev)) {
$rev = $youngest;
}
if (empty($startrev)) {
$startrev = $rev;
}
// make sure path is prefixed by a /
$ppath = $path;
if ($path == '' || $path{0} != '/') {
$ppath = '/'.$path;
}
$vars['action'] = $lang['LOG'];
$vars['rev'] = $rev;
$vars['peg'] = $peg;
$vars['path'] = escape($ppath);
if ($history && isset($history->entries[0])) {
$vars['log'] = xml_entities($history->entries[0]->msg);
$vars['date'] = $history->entries[0]->date;
$vars['age'] = datetimeFormatDuration(time() - strtotime($history->entries[0]->date));
$vars['author'] = $history->entries[0]->author;
}
if ($max === false) {
$max = ($dosearch) ? 0 : 40;
} else if ($max < 0) {
$max = 40;
}
// TODO: If the rev is less than the head, get the path (may have been renamed!)
// Will probably need to call `svn info`, parse XML output, and substring a path
createPathLinks($rep, $ppath, $passrev, $peg);
$passRevString = createRevAndPegString($rev, $peg);
$isDirString = ($isDir) ? 'isdir=1&' : '';
unset($queryParams['repname']);
unset($queryParams['path']);
// Toggle 'showchanges' param for link to switch from the current behavior
if ($showchanges == $rep->logsShowChanges())
$queryParams['showchanges'] = (int)!$showchanges;
else
unset($queryParams['showchanges']);
$vars['changesurl'] = $config->getURL($rep, $path, 'log').buildQuery($queryParams);
$vars['changeslink'] = ''.$lang[($showchanges ? 'HIDECHANGED' : 'SHOWCHANGED')].'';
$vars['showchanges'] = $showchanges;
// Revert 'showchanges' param to propagate the current behavior
if ($showchanges == $rep->logsShowChanges())
unset($queryParams['showchanges']);
else
$queryParams['showchanges'] = (int)$showchanges;
$vars['revurl'] = $config->getURL($rep, $path, 'revision').$isDirString.$passRevString;
if ($isDir) {
$vars['directoryurl'] = $config->getURL($rep, $path, 'dir').$passRevString.'#'.anchorForPath($path);
$vars['directorylink'] = ''.$lang['LISTING'].'';
} else {
$vars['filedetailurl'] = $config->getURL($rep, $path, 'file').$passRevString;
$vars['filedetaillink'] = ''.$lang['FILEDETAIL'].'';
$vars['blameurl'] = $config->getURL($rep, $path, 'blame').$passRevString;
$vars['blamelink'] = ''.$lang['BLAME'].'';
$vars['diffurl'] = $config->getURL($rep, $path, 'diff').$passRevString;
$vars['difflink'] = ''.$lang['DIFFPREV'].'';
}
if ($rep->isRssEnabled()) {
$vars['rssurl'] = $config->getURL($rep, $path, 'rss').$isDirString.createRevAndPegString('', $peg);
$vars['rsslink'] = ''.$lang['RSSFEED'].'';
}
if ($rev != $youngest) {
if ($path == '/') {
$vars['goyoungesturl'] = $config->getURL($rep, '', 'log').$isDirString;
} else {
$vars['goyoungesturl'] = $config->getURL($rep, $path, 'log').$isDirString.'peg='.($peg ? $peg : $rev);
}
$vars['goyoungestlink'] = ''.$lang['GOYOUNGEST'].'';
}
// We get the bugtraq variable just once based on the HEAD
$bugtraq = new Bugtraq($rep, $svnrep, $ppath);
$vars['logsearch_moreresultslink'] = '';
$vars['pagelinks'] = '';
$vars['showalllink'] = '';
if ($history) {
$history = $svnrep->getLog($path, $startrev, $endrev, true, $max, $peg);
if (empty($history)) {
unset($vars['error']);
$vars['warning'] = 'Revision '.$startrev.' of this resource does not exist.';
}
}
if (!empty($history)) {
// Get the number of separate revisions
$revisions = count($history->entries);
if ($all) {
$firstrevindex = 0;
$lastrevindex = $revisions - 1;
$pages = 1;
} else {
// Calculate the number of pages
$pages = floor($revisions / $maxperpage);
if (($revisions % $maxperpage) > 0) $pages++;
if ($page > $pages) $page = $pages;
// Work out where to start and stop
$firstrevindex = ($page - 1) * $maxperpage;
$lastrevindex = min($firstrevindex + $maxperpage - 1, $revisions - 1);
}
$frev = isset($history->entries[0]) ? $history->entries[0]->rev : false;
$brev = isset($history->entries[$firstrevindex]) ? $history->entries[$firstrevindex]->rev : false;
$erev = isset($history->entries[$lastrevindex]) ? $history->entries[$lastrevindex]->rev : false;
$entries = array();
if ($brev && $erev) {
$history = $svnrep->getLog($path, $brev, $erev, false, 0, $peg);
if ($history)
$entries = $history->entries;
}
$row = 0;
$index = 0;
$found = false;
foreach ($entries as $revision) {
// Assume a good match
$match = true;
$thisrev = $revision->rev;
// Check the log for the search words, if searching
if ($dosearch) {
if ((empty($fromRev) || $fromRev > $thisrev)) {
// Turn all the HTML entities into real characters.
// Make sure that each word in the search in also in the log
foreach ($words as $word) {
if (strpos(strtolower(removeAccents($revision->msg)), $word) === false && strpos(strtolower(removeAccents($revision->author)), $word) === false) {
$match = false;
break;
}
}
if ($match) {
$numSearchResults--;
$found = true;
}
} else {
$match = false;
}
}
$thisRevString = createRevAndPegString($thisrev, ($peg ? $peg : $thisrev));
if ($match) {
// Add the trailing slash if we need to (svnlook history doesn't return trailing slashes!)
$rpath = $revision->path;
if (empty($rpath)) {
$rpath = '/';
} else if ($isDir && $rpath{strlen($rpath) - 1} != '/') {
$rpath .= '/';
}
$precisePath = $revision->precisePath;
if (empty($precisePath)) {
$precisePath = '/';
} else if ($isDir && $precisePath{strlen($precisePath) - 1} != '/') {
$precisePath .= '/';
}
// Find the parent path (or the whole path if it's already a directory)
$pos = strrpos($rpath, '/');
$parent = substr($rpath, 0, $pos + 1);
$compareValue = (($isDir) ? $parent : $rpath).'@'.$thisrev;
$listing[$index]['compare_box'] = '';
$url = $config->getURL($rep, $rpath, 'revision').$thisRevString;
$listing[$index]['revlink'] = ''.$thisrev.'';
$url = $config->getURL($rep, $precisePath, ($isDir ? 'dir' : 'file')).$thisRevString;
$listing[$index]['revpathlink'] = ''.$precisePath.'';
$listing[$index]['revpath'] = $precisePath;
$listing[$index]['revauthor'] = $revision->author;
$listing[$index]['revdate'] = $revision->date;
$listing[$index]['revage'] = $revision->age;
$listing[$index]['revlog'] = nl2br($bugtraq->replaceIDs(create_anchors(xml_entities($revision->msg))));
$listing[$index]['rowparity'] = $row;
$listing[$index]['compareurl'] = $config->getURL($rep, '', 'comp').'compare[]='.$rpath.'@'.($thisrev - 1).'&compare[]='.$rpath.'@'.$thisrev;
if ($showchanges) {
// Aggregate added/deleted/modified paths for display in table
$modpaths = array();
foreach ($revision->mods as $mod) {
$modpaths[$mod->action][] = $mod->path;
}
ksort($modpaths);
foreach ($modpaths as $action => $paths) {
sort($paths);
$modpaths[$action] = $paths;
}
$listing[$index]['revadded'] = (isset($modpaths['A'])) ? implode('
', $modpaths['A']) : '';
$listing[$index]['revdeleted'] = (isset($modpaths['D'])) ? implode('
', $modpaths['D']) : '';
$listing[$index]['revmodified'] = (isset($modpaths['M'])) ? implode('
', $modpaths['M']) : '';
}
$row = 1 - $row;
$index++;
}
// If we've reached the search limit, stop here...
if (!$numSearchResults) {
$url = $config->getURL($rep, $path, 'log').$isDirString.$thisRevString;
$vars['logsearch_moreresultslink'] = ''.$lang['MORERESULTS'].'';
break;
}
}
$vars['logsearch_resultsfound'] = true;
if ($dosearch && !$found) {
if ($fromRev == 0) {
$vars['logsearch_nomatches'] = true;
$vars['logsearch_resultsfound'] = false;
} else {
$vars['logsearch_nomorematches'] = true;
}
} else if ($dosearch && $numSearchResults > 0) {
$vars['logsearch_nomorematches'] = true;
}
// Work out the paging options, create links to pages of results
if ($pages > 1) {
$prev = $page - 1;
$next = $page + 1;
unset($queryParams['page']);
$logurl = $config->getURL($rep, $path, 'log').buildQuery($queryParams);
if ($page > 1) {
$vars['pagelinks'] .= '←'.$lang['PREV'].'';
} else {
$vars['pagelinks'] .= '←'.$lang['PREV'].'';
}
for ($p = 1; $p <= $pages; $p++) {
if ($p != $page) {
$vars['pagelinks'] .= ''.$p.'';
} else {
$vars['pagelinks'] .= ''.$p.'';
}
}
if ($page < $pages) {
$vars['pagelinks'] .= ''.$lang['NEXT'].'→';
} else {
$vars['pagelinks'] .= ''.$lang['NEXT'].'→';
}
$vars['showalllink'] = ''.$lang['SHOWALL'].'';
}
}
// Create form elements for filtering and searching log messages
if ($config->multiViews) {
$hidden = '';
} else {
$hidden = '';
$hidden .= '';
}
if ($isDir)
$hidden .= '';
if ($peg)
$hidden .= '';
if ($showchanges != $rep->logsShowChanges())
$hidden .= '';
$vars['logsearch_form'] = '