[projects/buildlogs] This is garbage app... anyway few changes how data is displayed on page.

arekm arekm at pld-linux.org
Mon Apr 20 16:15:02 CEST 2026


commit 166f87ba777bdf92412dccf4b6e825ff1e0b4f99
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Mon Apr 20 15:13:43 2026 +0200

    This is garbage app... anyway few changes how data is displayed on page.

 buildlogs.inc                                      |    1 -
 index.php                                          | 1138 ++++++++++++++------
 lib.php                                            |   26 +
 obsolete/buildlogs.sql/PRZECZYTAJ.TO               |   32 -
 obsolete/buildlogs.sql/addlog.php                  |   80 --
 obsolete/buildlogs.sql/buildlogs.inc               |   76 --
 obsolete/buildlogs.sql/index.php                   | 1111 -------------------
 obsolete/buildlogs.sql/init.sql                    |   82 --
 obsolete/buildlogs.sql/migration.php               |   73 --
 obsolete/buildlogs/index.php                       | 1071 ------------------
 .../buildlogs/locale/pl_PL/LC_MESSAGES/messages.mo |  Bin 3338 -> 0 bytes
 .../buildlogs/locale/pl_PL/LC_MESSAGES/messages.po |  259 -----
 obsolete/buildlogs/powpld.png                      |  Bin 1097 -> 0 bytes
 pld-buildlogs/scripts/addlog.php                   |   57 +-
 pld-buildlogs/scripts/migration.php                |    3 +-
 15 files changed, 859 insertions(+), 3150 deletions(-)
---
diff --git a/buildlogs.inc b/buildlogs.inc
index 4b4a94b..3ce4ebb 100644
--- a/buildlogs.inc
+++ b/buildlogs.inc
@@ -7,4 +7,3 @@ $addr = array(
 	"ac" => array("SRPMS", "i386", "i586", "i686", "alpha", "amd64", "athlon",
 		"ppc", "sparc", "sparc64")
 );
-?>
diff --git a/index.php b/index.php
index c3fd3b1..c96c0c0 100644
--- a/index.php
+++ b/index.php
@@ -48,6 +48,64 @@ function like_escape(string $s): string {
     return str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $s);
 }
 
+// Natural (first-click) direction per ns; others default to 'd' (descending).
+const SORT_DIR_DEFAULT = [0=>'d', 1=>'a', 2=>'d', 3=>'a', 4=>'a', 5=>'a', 6=>'d'];
+
+function effective_dir($cur_ns, $cur_dir): string {
+    $ns = ($cur_ns === '' || $cur_ns === null) ? 0 : (int)$cur_ns;
+    if ($cur_dir === 'a' || $cur_dir === 'd') return $cur_dir;
+    return SORT_DIR_DEFAULT[$ns] ?? 'd';
+}
+
+function sort_target(int $col_ns, $cur_ns, $cur_dir): string {
+    $ns = ($cur_ns === '' || $cur_ns === null) ? 0 : (int)$cur_ns;
+    if ($col_ns === $ns) {
+        // Clicking the active column flips direction.
+        $new_dir = effective_dir($cur_ns, $cur_dir) === 'd' ? 'a' : 'd';
+    } else {
+        $new_dir = SORT_DIR_DEFAULT[$col_ns] ?? 'd';
+    }
+    return "ns={$col_ns}&dir={$new_dir}";
+}
+
+function sort_arrow(int $col_ns, $cur_ns, $cur_dir): string {
+    $ns = ($cur_ns === '' || $cur_ns === null) ? 0 : (int)$cur_ns;
+    if ($col_ns !== $ns) return '';
+    return effective_dir($cur_ns, $cur_dir) === 'a' ? ' &#x25B4;' : ' &#x25BE;';
+}
+
+const SORT_ORDER_BY = [
+    '0a' => 'mtime ASC',
+    '0d' => 'mtime DESC',
+    '1a' => 'name ASC',
+    '1d' => 'name DESC',
+    '2a' => 'size ASC',
+    '2d' => 'size DESC',
+    '3a' => 'ok ASC, mtime DESC',
+    '3d' => 'ok DESC, mtime DESC',
+    '4a' => 'arch ASC, mtime DESC',
+    '4d' => 'arch DESC, mtime DESC',
+    '5a' => 'dist ASC, arch ASC, mtime DESC',
+    '5d' => 'dist DESC, arch DESC, mtime DESC',
+    '6a' => 'runtime ASC NULLS LAST',
+    '6d' => 'runtime DESC NULLS LAST',
+];
+
+function format_runtime($sec): string {
+    if ($sec === null || $sec === '') return '—';
+    $sec = (int)$sec;
+    if ($sec < 0) return '—';
+    if ($sec < 60)   return $sec . 's';
+    if ($sec < 3600) {
+        $m = intdiv($sec, 60);
+        $s = $sec % 60;
+        return $s ? "{$m}m {$s}s" : "{$m}m";
+    }
+    $h = intdiv($sec, 3600);
+    $m = intdiv($sec % 3600, 60);
+    return $m ? "{$h}h {$m}m" : "{$h}h";
+}
+
 function one_item(string $h, string $t): void {
     echo "<tr><td bgcolor=\"#ccccff\">$h:</td>".
          "<td bgcolor=\"#cccccc\">$t</td></tr>";
@@ -63,6 +121,7 @@ $fail_or_ok = ["FAIL", "OK"];
 
 // $database, $root_directory and others are taken from buildlogs.inc
 include('buildlogs.inc');
+include('lib.php');
 
 session_set_cookie_params([
     'lifetime' => 0,
@@ -152,14 +211,17 @@ if ($ns_raw === null || $ns_raw === '') {
     $ns = '';
 } else {
     $ns = (int)$ns_raw;
-    if ($ns < 0 || $ns > 2) {
+    if ($ns < 0 || $ns > 6) {
         $ns = 0;
     }
 }
 
+$dir_raw = $_GET["dir"] ?? '';
+$dir = ($dir_raw === 'a') ? 'a' : (($dir_raw === 'd') ? 'd' : '');
+
 $cnt = isset($_GET["cnt"]) ? (int)$_GET["cnt"] : 50;
 if ($cnt < 1) $cnt = 1;
-if ($cnt > 500) $cnt = 500;
+if ($cnt > 10000) $cnt = 10000;
 
 $off = isset($_GET["off"]) ? (int)$_GET["off"] : 0;
 if ($off < 0) $off = 0;
@@ -177,6 +239,20 @@ if (isset($_POST["str"])) {
     }
 }
 
+$q = '';
+$q_raw = $_GET["q"] ?? $_POST["q"] ?? '';
+if (is_string($q_raw) && $q_raw !== ''
+    && strlen($q_raw) <= 64
+    && preg_match('/^[A-Za-z0-9_.+\-*?]+$/', $q_raw)) {
+    $q = $q_raw;
+}
+
+function glob_to_like(string $g): string {
+    $s = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $g);
+    $s = str_replace(['*', '?'], ['%', '_'], $s);
+    return $s;
+}
+
 function myheader()
 {
     header("Content-Type: text/html; charset=UTF-8");
@@ -197,6 +273,7 @@ H2 { font-family: arial,helvetica,sans-serif;
      font-weight: bold;}
 BODY,TD { font-family: arial,helvetica,sans-serif;
           font-size: 13pt; }
+TD, TH { vertical-align: middle; }
 TH { font-family: arial,helvetica,sans-serif;
      font-size: 13pt;
      font-weight: bold; }
@@ -221,6 +298,18 @@ TH { font-family: arial,helvetica,sans-serif;
       this page is autogenerated and it might be misleading after some
       build log changes. -->
  <body bgcolor="#ffffff" text="#000000" link="#5f26cd" vlink="#5f26cd">
+<table width="100%" cellpadding="4" cellspacing="0" border="0"><tr>
+<td bgcolor="#CCCCFF"><b>[<a href="index.php">main()</a>]</b></td>
+<td bgcolor="#CCCCFF" align="right">
+<form action="index.php" method="get" style="display:inline;margin:0">
+<?=_("Package")?>:
+<input type="text" name="q" size="24" maxlength="64"
+ value="<?=h($GLOBALS['q'] ?? '')?>"
+ placeholder="glob e.g. foo*" />
+<input type="submit" value="<?=_("Search")?>" />
+</form>
+</td>
+</tr></table>
 <?php
 }
 
@@ -251,47 +340,90 @@ function mydie($msg)
 function list_logs()
 {
 	global $database;
-	global $arch, $dist, $ok;
-	global $big_url, $ns;
+	global $arch, $dist, $ok, $q;
+	global $big_url, $ns, $dir;
 	global $off, $cnt, $root_directory, $url;
 
 	$query_data = array(
-		'dist' => $dist,
-		'arch' => $arch,
-		'ok' => $ok,
-		'ns' => $ns,
 		'cnt' => $cnt);
+	if ($ns !== '' && $ns !== 0) {
+		$query_data['ns'] = $ns;
+	}
+	if ($dir !== '') {
+		$query_data['dir'] = $dir;
+	}
+	if ($dist !== null) {
+		$query_data['dist'] = $dist;
+	}
+	if ($arch !== null) {
+		$query_data['arch'] = $arch;
+	}
+	if ($ok !== '') {
+		$query_data['ok'] = $ok;
+	}
+	if ($q !== '') {
+		$query_data['q'] = $q;
+	}
 	$big_url = $url . '?' . http_build_query($query_data);
 
-	$dist_arch = h($dist . '/' . $arch);
-	if ($ok == 1) {
-		echo "<h1>"._("Listing of")." $dist_arch/OK "
-			."(<a href=\"" . h($big_url) . "&ok=0\">"._("fail")."</a>)</h1>\n";
+	if ($q !== '') {
+		$scope = $dist !== null
+			? h(($arch !== null ? ($dist . '/' . $arch) : $dist))
+			: _("all");
+		echo "<h1>"._("Search")." <code>".h($q)."</code> "._("in")." $scope</h1>\n";
 	} else {
-		echo "<h1>"._("Listing of")." $dist_arch/FAIL "
-			."(<a href=\"" . h($big_url) . "&ok=1\">"._("ok")."</a>)</h1>\n";
-	}
-
-	echo "<div align=\"center\"><table cols=\"4\" border=\"0\" cellspacing=\"1\" ".
-		"cellpadding=\"3\" bgcolor=\"#000000\" width=\"90%\">\n";
-	$big_url_esc = h($big_url);
-	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" width=\"1%\">"._("No.")."</th>".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\" width=\"80%\">"._("Log File").
-			"[<a href=\"$big_url_esc&ns=1\">"._("sort")."</a>]</th>".
-		 "<th bgcolor=\"#CCCCFF\" align=\"right\" width=\"15%\">"._("Size")."</th> ".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\">"._("Age").
-			 "[<a href=\"$big_url_esc&ns=0\">"._("sort")."</a>]</th>".
+		$dist_arch = h($arch !== null ? ($dist . '/' . $arch) : $dist);
+		if ($ok === '') {
+			echo "<h1>"._("Listing of")." $dist_arch/ALL "
+				."(<a href=\"" . h($big_url) . "&ok=0\">"._("fail")."</a> | "
+				."<a href=\"" . h($big_url) . "&ok=1\">"._("ok")."</a>)</h1>\n";
+		} elseif ($ok == 1) {
+			echo "<h1>"._("Listing of")." $dist_arch/OK "
+				."(<a href=\"" . h($big_url) . "&ok=0\">"._("fail")."</a>)</h1>\n";
+		} else {
+			echo "<h1>"._("Listing of")." $dist_arch/FAIL "
+				."(<a href=\"" . h($big_url) . "&ok=1\">"._("ok")."</a>)</h1>\n";
+		}
+	}
+
+	$show_status = ($ok === '');
+	$show_arch = ($arch === null);
+	echo "<div align=\"center\"><table border=\"0\" cellspacing=\"1\" ".
+		"cellpadding=\"6\" bgcolor=\"#000000\" width=\"90%\">\n";
+	$sort_qd = $query_data;
+	unset($sort_qd['ns'], $sort_qd['dir']);
+	$sort_base = h($url . '?' . http_build_query($sort_qd));
+	$sl = function(int $col_ns, string $label) use ($sort_base, $ns, $dir) {
+		return "<a href=\"$sort_base&" . sort_target($col_ns, $ns, $dir) . "\">$label</a>"
+			. sort_arrow($col_ns, $ns, $dir);
+	};
+	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"middle\" width=\"1%\">"._("No.")."</th>";
+	if ($show_status) {
+		echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(3, _("Status"))."</th>";
+	}
+	if ($show_arch) {
+		echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(5, _("Dist"))."</th>";
+		echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(4, _("Arch"))."</th>";
+	}
+	echo "<th bgcolor=\"#CCCCFF\" align=\"left\" valign=\"middle\" width=\"80%\">".$sl(1, _("Log File"))."</th>".
+		 "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(6, _("Runtime"))."</th>".
+		 "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\" width=\"15%\">".$sl(2, _("Size"))."</th>".
+		 "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(0, _("Date"))."</th>".
+		 "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(0, _("Age"))."</th>".
 		 "</tr>";
 
-	if ($ns != 1) $ns = 0;
-	if (!isset($ok)) $ok = 0;
-//	if (!isset($off)) $off = 0;
-//	if (!isset($cnt)) $cnt = 50;
-	if ($ns == 0) $order = "mtime DESC";
-	else $order = "name";
+	$ns_int = ($ns === '') ? 0 : (int)$ns;
+	$key = $ns_int . effective_dir($ns, $dir);
+	$order = SORT_ORDER_BY[$key] ?? 'mtime DESC';
 
-	$query = "SELECT log_id, dist, arch, ok, name, mtime, size, id FROM logs WHERE
-			  dist = :dist AND arch = :arch AND ok = :ok ORDER BY $order LIMIT :limitnr OFFSET :offset ";
+	$conds = [];
+	if ($dist !== null) $conds[] = "dist = :dist";
+	if ($arch !== null) $conds[] = "arch = :arch";
+	if ($ok !== '')    $conds[] = "ok = :ok";
+	if ($q !== '')     $conds[] = "name LIKE :q ESCAPE '\\'";
+	$where = empty($conds) ? "1=1" : implode(' AND ', $conds);
+	$query = "SELECT log_id, dist, arch, ok, name, mtime, size, id, runtime FROM logs WHERE "
+		. "$where ORDER BY $order LIMIT :limitnr OFFSET :offset ";
 
 	try {
 		$dbh = new PDO("$database");
@@ -303,9 +435,18 @@ function list_logs()
 	$now = time();
 	$i = $off;
 	$stmt = $dbh->prepare($query);
-	$stmt->bindValue(':dist', $dist, PDO::PARAM_STR);
-	$stmt->bindValue(':arch', $arch, PDO::PARAM_STR);
-	$stmt->bindValue(':ok', $ok, PDO::PARAM_INT);
+	if ($dist !== null) {
+		$stmt->bindValue(':dist', $dist, PDO::PARAM_STR);
+	}
+	if ($arch !== null) {
+		$stmt->bindValue(':arch', $arch, PDO::PARAM_STR);
+	}
+	if ($ok !== '') {
+		$stmt->bindValue(':ok', $ok, PDO::PARAM_INT);
+	}
+	if ($q !== '') {
+		$stmt->bindValue(':q', glob_to_like($q), PDO::PARAM_STR);
+	}
 	$stmt->bindValue(':limitnr', $cnt, PDO::PARAM_INT);
 	$stmt->bindValue(':offset', $off, PDO::PARAM_INT);
 	$stmt->execute();
@@ -314,40 +455,60 @@ function list_logs()
 		$id = $row["id"];
 		$dist = $row["dist"];
 		$arch = $row["arch"];
+		$row_ok = (int)$row["ok"];
 		$f = $name;
 		$name_url = urlencode($name);
-		$t = $now - $row["mtime"];
+		$mtime = (int)$row["mtime"];
+		$t = $now - $mtime;
+		$date_str = date("Y/m/d H:i:s", $mtime);
 		$s = $row["size"];
 		$h = $row["log_id"];
 
-		$t /= 60;
-		if ($t >= 60) {
+		if ($t < 0) {
+			$t = _("in future");
+		} else {
 			$t /= 60;
-			if ($t >= 24) {
-				$t /= 24;
-				$t = (int)round($t);
-				$t = $t . " " . ngettext("day","days",$t);
+			if ($t >= 60) {
+				$t /= 60;
+				if ($t >= 24) {
+					$t /= 24;
+					$t = (int)round($t);
+					$t = $t . " " . ngettext("day","days",$t);
+				} else {
+					$t = (int)round($t);
+					$t = $t . " " . ngettext("hour","hours",$t);
+				}
 			} else {
 				$t = (int)round($t);
-				$t = $t . " " . ngettext("hour","hours",$t);
+				$t = $t . " " . ngettext("minute","minutes",$t);
 			}
-		} else {
-			$t = (int)round($t);
-			$t = $t . " " . ngettext("minute","minutes",$t);
 		}
 		$url_data = array(
 			'dist' => $dist,
 			'arch' => $arch,
-			'ok' => $ok,
+			'ok' => $row_ok,
 			'name' => $name_url,
 			'id' => $id);
 		$u = h($url . '?' . http_build_query($url_data));
-		echo "<tr><td bgcolor=\"#CCCCCC\" align=\"right\">".($i+1).".</td>".
-		     "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">" . h($f) . "</a> ".
+		echo "<tr><td bgcolor=\"#CCCCCC\" align=\"right\" valign=\"middle\">".($i+1).".</td>";
+		if ($show_status) {
+			$status = $row_ok
+				? "<font color=\"green\"><b>"._("OK")."</b></font>"
+				: "<font color=\"red\"><b>"._("FAIL")."</b></font>";
+			echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\">$status</td>";
+		}
+		if ($show_arch) {
+			echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($row["dist"])."</td>";
+			echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($row["arch"])."</td>";
+		}
+		$rt = format_runtime($row["runtime"] ?? null);
+		echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\"><a href=\"$u\">" . h($f) . "</a> ".
 		     "[<a href=\"$u&action=text\">"._("text")."</a> | ".
 		      "<a href=\"$u&action=tail\">"._("tail")."</a>]".
-		     "</td><td bgcolor=\"#CCCCCC\" align=\"right\">".
-		     h((string)$s)."</td><td bgcolor=\"#CCCCCC\">$t</td></tr>\n";
+		     "</td><td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">$rt</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\">".
+		     h((string)$s)."</td><td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".
+		     h($date_str)."</td><td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">$t</td></tr>\n";
 		$i++;
 	}
 	$count = $i - $off;
@@ -389,6 +550,21 @@ function list_logs()
 		echo "$forward</td><td align=right width=1%>$forwardarr";
 	}
 	echo "</td>\n</tr></table></p>";
+
+	$row_counts = [50, 250, 500, 1000, 10000];
+	echo "<p align=\"center\">" . _("Rows per page") . ": ";
+	foreach ($row_counts as $sz) {
+		$qd = $query_data;
+		$qd['cnt'] = $sz;
+		unset($qd['off']);
+		if ($sz == $cnt) {
+			echo "<b>$sz</b>  ";
+		} else {
+			$link_url = h($url . '?' . http_build_query($qd));
+			echo "[<a href=\"$link_url\">$sz</a>]  ";
+		}
+	}
+	echo "</p>";
 }
 
 function file_name()
@@ -404,19 +580,181 @@ function file_name()
 	}
 }
 
-function get_filter($f)
+
+function list_package_history($pkg_name, $cur_dist, $cur_arch, $cur_ok, $cur_id)
 {
-	if (preg_match("/\.bz2$/", $f)) {
-		if (is_executable("/usr/bin/lbzcat"))
-			$filter = "lbzcat";
-		else
-			$filter = "bzcat";
-	} elseif (preg_match("/\.gz$/", $f)) {
-		$filter = "zcat";
+	global $database, $url;
+
+	try {
+		$dbh = new PDO($database);
+		$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
+	} catch (PDOException $e) {
+		return;
+	}
+
+	$chk = $dbh->prepare(
+		"SELECT COUNT(*) FROM logs WHERE name = :name AND id != ''"
+	);
+	$chk->bindValue(':name', $pkg_name, PDO::PARAM_STR);
+	$chk->execute();
+	$has_ids = ((int)$chk->fetchColumn()) > 0;
+
+	if ($has_ids) {
+		$stmt = $dbh->prepare(
+			"SELECT dist, arch, ok, name, mtime, size, id, runtime FROM logs "
+			. "WHERE name = :name AND id IN ("
+			. "  SELECT id FROM logs WHERE name = :name2 AND id != '' "
+			. "  GROUP BY id ORDER BY MAX(mtime) DESC LIMIT 10"
+			. ") AND NOT "
+			. "(dist = :cd AND arch = :ca AND ok = :co AND COALESCE(id,'') = :ci) "
+			. "ORDER BY mtime DESC"
+		);
+		$stmt->bindValue(':name2', $pkg_name, PDO::PARAM_STR);
 	} else {
-		$filter = "cat";
+		$stmt = $dbh->prepare(
+			"SELECT dist, arch, ok, name, mtime, size, id, runtime FROM logs "
+			. "WHERE name = :name AND NOT "
+			. "(dist = :cd AND arch = :ca AND ok = :co AND COALESCE(id,'') = :ci) "
+			. "ORDER BY mtime DESC LIMIT 20"
+		);
+	}
+	$stmt->bindValue(':name', $pkg_name, PDO::PARAM_STR);
+	$stmt->bindValue(':cd', $cur_dist, PDO::PARAM_STR);
+	$stmt->bindValue(':ca', $cur_arch, PDO::PARAM_STR);
+	$stmt->bindValue(':co', (int)$cur_ok, PDO::PARAM_INT);
+	$stmt->bindValue(':ci', (string)$cur_id, PDO::PARAM_STR);
+	$stmt->execute();
+	$rows = $stmt->fetchAll();
+
+	if (empty($rows)) {
+		return;
+	}
+
+	if ($has_ids) {
+		$groups = [];
+		foreach ($rows as $row) {
+			$rid = (string)$row["id"];
+			if (!isset($groups[$rid])) {
+				$groups[$rid] = ['max_mtime' => 0, 'rows' => []];
+			}
+			$groups[$rid]['rows'][] = $row;
+			if ((int)$row["mtime"] > $groups[$rid]['max_mtime']) {
+				$groups[$rid]['max_mtime'] = (int)$row["mtime"];
+			}
+		}
+		uasort($groups, function($a, $b) {
+			return $b['max_mtime'] - $a['max_mtime'];
+		});
 	}
-	return $filter;
+
+	$now = time();
+	echo "<h2 id=\"history\">"._("Previous builds of this package:")."</h2>\n";
+	echo "<div align=\"center\"><table border=\"0\" cellspacing=\"1\" ".
+		"cellpadding=\"6\" bgcolor=\"#000000\" width=\"90%\">\n";
+	$first_col = $has_ids
+		? "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\" width=\"1%\">"._("Id")."</th>"
+		: "<th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"middle\" width=\"1%\">"._("Lp.")."</th>";
+	echo "<tr>".
+	     $first_col.
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Status")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Dist")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Arch")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"left\" valign=\"middle\">"._("Log File")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Runtime")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Size")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Date")."</th>".
+	     "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">"._("Age")."</th>".
+	     "</tr>\n";
+	$render_row = function($row, $first_cell) use ($now, $url) {
+		$r_dist = (string)$row["dist"];
+		$r_arch = (string)$row["arch"];
+		$r_name = (string)$row["name"];
+		$r_id   = (string)$row["id"];
+		$r_ok   = (int)$row["ok"];
+		$r_size = (int)$row["size"];
+		$r_mtime = (int)$row["mtime"];
+
+		if (($now - $r_mtime) < 0) {
+			$t_str = _("in future");
+		} else {
+			$t = ($now - $r_mtime) / 60;
+			if ($t >= 60) {
+				$t /= 60;
+				if ($t >= 24) {
+					$t /= 24;
+					$t = (int)round($t);
+					$t_str = $t . " " . ngettext("day","days",$t);
+				} else {
+					$t = (int)round($t);
+					$t_str = $t . " " . ngettext("hour","hours",$t);
+				}
+			} else {
+				$t = (int)round($t);
+				$t_str = $t . " " . ngettext("minute","minutes",$t);
+			}
+		}
+		$date_str = date("Y/m/d H:i:s", $r_mtime);
+
+		$u = h($url . '?' . http_build_query([
+			'dist' => $r_dist,
+			'arch' => $r_arch,
+			'ok'   => $r_ok,
+			'name' => $r_name,
+			'id'   => $r_id,
+		]));
+		$status = $r_ok
+			? "<font color=\"green\"><b>"._("OK")."</b></font>"
+			: "<font color=\"red\"><b>"._("FAIL")."</b></font>";
+
+		$rt = format_runtime($row["runtime"] ?? null);
+		echo "<tr>".
+		     $first_cell.
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\">$status</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($r_dist)."</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($r_arch)."</td>".
+		     "<td bgcolor=\"#CCCCCC\" valign=\"middle\"><a href=\"$u\">" . h($r_name) . "</a> ".
+		     "[<a href=\"$u&action=text\">"._("text")."</a> | ".
+		     "<a href=\"$u&action=tail\">"._("tail")."</a>]</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">$rt</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\">".h((string)$r_size)."</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($date_str)."</td>".
+		     "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">$t_str</td>".
+		     "</tr>\n";
+	};
+
+	if ($has_ids) {
+		$group_count = count($groups);
+		$group_idx = 0;
+		foreach ($groups as $rid => $grp) {
+			$group_idx++;
+			$span = count($grp['rows']);
+			$short = strlen($rid) > 8 ? substr($rid, 0, 8) : $rid;
+			$first = true;
+			foreach ($grp['rows'] as $row) {
+				if ($first) {
+					$first_cell = "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" ".
+						"nowrap=\"nowrap\" width=\"1%\" rowspan=\"$span\" title=\"".h($rid)."\">".
+						"<small>".h($short)."</small></td>";
+					$first = false;
+				} else {
+					$first_cell = '';
+				}
+				$render_row($row, $first_cell);
+			}
+			if ($group_idx < $group_count) {
+				echo "<tr><td colspan=\"9\" bgcolor=\"#000000\" style=\"height:4px;line-height:4px;font-size:1px;padding:0\"> </td></tr>\n";
+			}
+		}
+	} else {
+		$lp = 0;
+		foreach ($rows as $row) {
+			$lp++;
+			$first_cell = "<td bgcolor=\"#CCCCCC\" align=\"right\" valign=\"middle\">".$lp.".</td>";
+			$render_row($row, $first_cell);
+		}
+	}
+	echo "</table></div>\n";
 }
 
 function dump_log($tail)
@@ -441,7 +779,14 @@ function dump_log($tail)
 		$gitweb_url = "http://git.pld-linux.org/?p=packages/" . rawurlencode($name) . ";a=summary";
 		$name_h = '<a href="' . h($gitweb_url) . '">' . h($name) . '</a>';
 	}
-	echo "<h1>$name_h <small>" . h($id) . "</small></h1>";
+	echo "<h1 id=\"info\">$name_h <small>" . h($id) . "</small></h1>";
+
+	echo "<p>"._("Jump to").": ".
+	     "[<a href=\"#info\">"._("Info")."</a>] ".
+	     "[<a href=\"#history\">"._("History")."</a>] ".
+	     "[<a href=\"#toc\">"._("Toc")."</a>] ".
+	     "[<a href=\"#content\">"._("Content")."</a>]".
+	     "</p>";
 
 	echo "<table border=\"0\" cellpadding=\"3\" cellspacing=\"1\" bgcolor=\"#000000\" width=\"100%\">";
 
@@ -452,8 +797,8 @@ function dump_log($tail)
 	one_item(_("Source URL"),
 		 href_tag(h($source_url), h($source_url)));
 
-	$big_url = "$url?dist=$dist&arch=$arch&ok=$ok&ns=$ns&cnt=$cnt";
-	$bu = "$big_url&off=$off";
+	$big_url = "$url?dist=$dist&arch=$arch&ok=$ok&ns=$ns&cnt=$cnt";
+	$bu = "$big_url&off=$off";
 
 	$bu_attr = h($bu);
 	$name_url_esc = h((string)$name_url);
@@ -495,22 +840,13 @@ function dump_log($tail)
 		echo "</table>";
 		return;
 	}
-	$filter = get_filter($f);
-
-	$descriptors = [
-		0 => ['pipe', 'r'],
-		1 => ['pipe', 'w'],
-		2 => ['pipe', 'w'],
-	];
-	$proc = proc_open([$filter, $full_path], $descriptors, $pipes);
-	if (!is_resource($proc)) {
+	$h = open_log_stream($full_path);
+	if ($h === null) {
 		echo "<p>"._("Failed to spawn decompressor")."</p>";
 		echo "</table>";
 		return;
 	}
-	fclose($pipes[0]);
-	fclose($pipes[2]);
-	$fd = $pipes[1];
+	$fd = $h['fd'];
 	$toc = array();
 	$err = array();
 	$first_cut = false;
@@ -519,6 +855,7 @@ function dump_log($tail)
 	$out_buf = array();
 	$out_buf_size = 0;
 	$err_count = 0;
+	$seen_sections = array();
 	while (($s = fgets($fd, 102400)) != false) {
 
 		$toc_elem = false;
@@ -549,17 +886,21 @@ function dump_log($tail)
 			$s = "<span class=changelog>{$m['line']} $link<br/></span>";
 		} elseif (preg_match('/^(?P<line>\* \w{3} \w{3} [ \d]{2} \d{4} .*?) (?P<hash>[a-z0-9]{7})$/', $s, $m)) {
 			// rpm changelogs
-			$url = "http://git.pld-linux.org/?p=packages/{$name_url}.git;a=commitdiff;h={$m['hash']}";
-			$link = "<a href=\"$url\">{$m['hash']}</a>";
+			$cl_url = "http://git.pld-linux.org/?p=packages/{$name_url}.git;a=commitdiff;h={$m['hash']}";
+			$link = "<a href=\"$cl_url\">{$m['hash']}</a>";
 			$s = "<span class=changelog>{$m['line']} $link<br/></span>";
 		} elseif (substr($s, 0, 2) == "+ ") {
 			// shell verbose
 			$s = "<span class=verbose>$s</span>";
 		} elseif (preg_match("/^Executing\(%(?P<section>\w+)\)/", $s, $m)) {
 			// rpm build section
-			$toc_elem = $m['section'];
+			$section_name = $m['section'];
+			$seen_sections[$section_name] = ($seen_sections[$section_name] ?? 0) + 1;
+			$suffix = $seen_sections[$section_name] > 1
+				? "-" . $seen_sections[$section_name] : "";
+			$toc_elem = $section_name . ($suffix !== "" ? " " . $seen_sections[$section_name] : "");
 			$err_elem = $s;
-			$s = "<span class=section id={$m['section']}>$s</span>";
+			$s = "<span class=section id={$section_name}{$suffix}>$s</span>";
 		} elseif (preg_match("/^Processing files: (?P<pkg>(?P<name>.+)-[^-]+-[^-]+)/", $s, $m)) {
 			$first_cut = true;
 			// processing files
@@ -588,8 +929,7 @@ function dump_log($tail)
 				$err[] = $err_elem;
 		}
 	}
-	fclose($fd);
-	proc_close($proc);
+	close_log_stream($h);
 
 	// no errors found, no processing found but we are in tail mode
 	if ($tail && !$first_cut_done && $out_buf_size > 100) {
@@ -605,8 +945,10 @@ function dump_log($tail)
 
 	echo "</table>";
 
+	list_package_history($name, $dist, $arch, $ok, $id);
+
 	if (!empty($toc)) {
-		echo "<h2>"._("Toc:")."</h2>";
+		echo "<h2 id=\"toc\">"._("Toc:")."</h2>";
 		echo "<ul class=toc>";
 		foreach ($toc as $i => $section) {
 			$id = str_replace(" ", "-", $section);
@@ -616,7 +958,7 @@ function dump_log($tail)
 		echo "</ul>";
 	}
 
-	echo "<h2>"._("Content:")."</h2>";
+	echo "<h2 id=\"content\">"._("Content:")."</h2>";
 
 	start_pre();
 	echo $code;
@@ -659,24 +1001,14 @@ function dump_text()
 	echo "# src  : https://$buildlogs_server/pld/$f\n";
 	echo "# date   : " . date("Y/m/d H:i:s", filemtime($full_path)) . "\n";
 
-	$filter = get_filter($f);
-
-	$descriptors = [
-		0 => ['pipe', 'r'],
-		1 => ['pipe', 'w'],
-		2 => ['pipe', 'w'],
-	];
-	$proc = proc_open([$filter, $full_path], $descriptors, $pipes);
-	if (!is_resource($proc)) {
+	$h = open_log_stream($full_path);
+	if ($h === null) {
 		http_response_code(500);
 		echo "# failed to spawn decompressor\n";
 		return;
 	}
-	fclose($pipes[0]);
-	fclose($pipes[2]);
-	fpassthru($pipes[1]);
-	fclose($pipes[1]);
-	proc_close($proc);
+	fpassthru($h['fd']);
+	close_log_stream($h);
 }
 
 function list_archs()
@@ -686,19 +1018,35 @@ function list_archs()
 	if (!isset($cnt))
 		$cnt = 50;
 
-	$big_url = "$url?ok=$ok&ns=$ns&cnt=$cnt";
+	$big_url = "$url?ok=$ok&ns=$ns&cnt=$cnt";
 
-	echo "<table width=\"100%\" border=\"0\">\n";
-	echo "<tr><td bgcolor=\"#cccccc\" nowrap=\"nowrap\">"._("Failed")."</td><td bgcolor=\"#cccccc\">"._("Ok")."</td></tr>\n";
+	echo "<table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" bgcolor=\"#000000\">\n";
+	$first_group = true;
 	foreach ($addr as $d => $ddist) {
-		echo "<tr><td colspan=2 nowrap=\"nowrap\"><hr/></td></tr>\n";
+		if (!$first_group) {
+			echo "<tr><td colspan=\"4\" bgcolor=\"#ffffff\"> </td></tr>\n";
+		}
+		$first_group = false;
+		$dh = h($d);
+		$all_d  = h("$url?dist=$d&cnt=$cnt");
+		$fail_d = h("$url?dist=$d&ok=0&cnt=$cnt");
+		$ok_d   = h("$url?dist=$d&ok=1&cnt=$cnt");
+		echo "<tr>".
+			"<td bgcolor=\"#CCCCFF\" nowrap=\"nowrap\"><b>$dh</b></td>".
+			"<td bgcolor=\"#CCCCFF\" align=\"center\" nowrap=\"nowrap\">[<a href=\"$all_d\">"._("all")."</a>]</td>".
+			"<td bgcolor=\"#CCCCFF\" align=\"center\" nowrap=\"nowrap\">[<a href=\"$fail_d\">"._("failed")."</a>]</td>".
+			"<td bgcolor=\"#CCCCFF\" align=\"center\" nowrap=\"nowrap\">[<a href=\"$ok_d\">"._("ok")."</a>]</td>".
+			"</tr>\n";
 		foreach ($ddist as $a) {
 			$da = h($d . '/' . $a);
+			$all_qs  = h("$url?dist=$d&arch=$a&cnt=$cnt");
 			$fail_qs = h("$url?dist=$d&arch=$a&ok=0&cnt=$cnt");
 			$ok_qs   = h("$url?dist=$d&arch=$a&ok=1&cnt=$cnt");
-			echo "<tr><td nowrap=\"nowrap\">".
-				"<a href=\"$fail_qs\">$da</a></td><td nowrap=\"nowrap\">".
-				"[<a href=\"$ok_qs\">OK</a>]</td>".
+			echo "<tr>".
+				"<td bgcolor=\"#CCCCCC\" nowrap=\"nowrap\">  <b>$da</b></td>".
+				"<td bgcolor=\"#CCCCCC\" align=\"center\" nowrap=\"nowrap\">[<a href=\"$all_qs\">"._("all")."</a>]</td>".
+				"<td bgcolor=\"#CCCCCC\" align=\"center\" nowrap=\"nowrap\">[<a href=\"$fail_qs\">"._("failed")."</a>]</td>".
+				"<td bgcolor=\"#CCCCCC\" align=\"center\" nowrap=\"nowrap\">[<a href=\"$ok_qs\">"._("ok")."</a>]</td>".
 				"</tr>\n";
 		}
 	}
@@ -751,61 +1099,108 @@ function list_archs()
 	echo "</small></div>";
 
 	if ($dist !== null && $arch !== null) {
-	echo "<form action=\"index.php\" method=\"post\">";
-	echo "<input type=\"hidden\" name=\"dist\" value=\"" . h($dist) . "\" />";
-	echo "<input type=\"hidden\" name=\"arch\" value=\"" . h($arch) . "\" />";
-	echo "<input type=\"hidden\" name=\"action\" value=\"sqa\" />";
-	echo "<input type=\"text\" size=\"14\" name=\"str\" /><br />";
-	echo "<input type=\"submit\" name=\"submit\" value=\""._("Search rpmqa!")."\" />";
-	echo "</form>";
+		echo "<br /><table border=\"0\" cellspacing=\"1\" cellpadding=\"3\" ".
+			"bgcolor=\"#000000\" width=\"100%\">\n";
+		echo "<tr><th bgcolor=\"#CCCCFF\" align=\"center\">".
+			h(_("Search rpm -qa"))." <small>(".h($dist.'/'.$arch).")</small>".
+			"</th></tr>\n";
+		echo "<tr><td bgcolor=\"#CCCCCC\" align=\"center\">";
+		echo "<form action=\"index.php\" method=\"post\" style=\"margin:0\">";
+		echo "<input type=\"hidden\" name=\"dist\" value=\"".h($dist)."\" />";
+		echo "<input type=\"hidden\" name=\"arch\" value=\"".h($arch)."\" />";
+		echo "<input type=\"hidden\" name=\"action\" value=\"sqa\" />";
+		echo "<input type=\"text\" size=\"14\" name=\"str\" ".
+			"placeholder=\"".h(_("glob e.g. foo*"))."\" /><br />";
+		echo "<input type=\"submit\" value=\""._("Search!")."\" />";
+		echo "</form></td></tr>\n";
+		echo "</table>\n";
 	}
 }
 
-function get_qa()
+function qa_url()
 {
 	global $dist, $arch;
-
 	if ($dist === null || $arch === null) {
-		return false;
+		return null;
 	}
-	$addr = "https://ftp1.pld-linux.org/dists/" . rawurlencode($dist)
+	return "https://ftp1.pld-linux.org/dists/" . rawurlencode($dist)
 		. "/.stat/builder/" . rawurlencode($dist)
 		. "/rpmqa-" . rawurlencode($arch) . ".txt";
-	$ctx = stream_context_create([
-		'http' => [
-			'method' => 'GET',
-			'timeout' => 30,
-			'ignore_errors' => false,
-		],
+}
+
+function get_qa(&$status = '', &$url_tried = null, &$error = '')
+{
+	$addr = qa_url();
+	$url_tried = $addr;
+	if ($addr === null) return false;
+
+	$tmp = tmpfile();
+	if ($tmp === false) {
+		$error = 'tmpfile() failed';
+		return false;
+	}
+
+	$ch = curl_init($addr);
+	curl_setopt_array($ch, [
+		CURLOPT_FILE           => $tmp,
+		CURLOPT_TIMEOUT        => 30,
+		CURLOPT_CONNECTTIMEOUT => 10,
+		CURLOPT_FOLLOWLOCATION => true,
+		CURLOPT_MAXREDIRS      => 3,
+		CURLOPT_USERAGENT      => 'PLD-buildlogs/1.0',
 	]);
-	return @fopen($addr, 'r', false, $ctx);
+	$ok = curl_exec($ch);
+	$status = (string)curl_getinfo($ch, CURLINFO_HTTP_CODE);
+	if ($ok === false) {
+		$error = curl_error($ch);
+	}
+	curl_close($ch);
+
+	if ($ok === false || ($status !== '' && (int)$status >= 400)) {
+		fclose($tmp);
+		return false;
+	}
+	rewind($tmp);
+	return $tmp;
 }
 
 function search_qa()
 {
 	global $url, $str, $dist, $arch;
 
-	$f = get_qa();
+	$status = ''; $tried = null; $error = '';
+	$f = get_qa($status, $tried, $error);
 	echo "<h1>"._("Search results for")." '" . h($str) . "' "._("in")." "
 		. h($dist . '/' . $arch) . "</h1>";
 
 	start_pre();
 
 	if ($f === false) {
-		echo h(_("Sorry, cannot open."));
+		echo h(_("Could not fetch rpm -qa for this builder."))."\n";
+		if ($tried !== null) echo h(_("Tried")).": ".h($tried)."\n";
+		if ($status !== '')  echo h(_("HTTP status")).": ".h($status)."\n";
+		if ($error !== '')   echo h(_("cURL error")).": ".h($error)."\n";
 	} else {
+		$use_glob = ($str !== '' && strpbrk($str, '*?[') !== false);
+		$matches = [];
 		while (($s = fgets($f, 1000)) !== false) {
 			if (stristr($s, "Query done at:") !== false) {
 				echo "rpmqa database from " . h(strstr($s, ":")) . "\n";
 				continue;
 			}
-
-			if ($str !== '' && stristr($s, $str) !== false) {
-				echo h($s);
-			}
+			if ($str === '') continue;
+			$line = rtrim($s, "\r\n");
+			$hit = $use_glob
+				? @fnmatch($str, $line, FNM_CASEFOLD)
+				: stristr($line, $str) !== false;
+			if ($hit) $matches[] = $s;
 		}
-		echo "\n/* EOF */";
 		fclose($f);
+		sort($matches, SORT_NATURAL | SORT_FLAG_CASE);
+		foreach ($matches as $s) {
+			echo h($s);
+		}
+		echo "\n/* EOF */";
 	}
 	end_pre();
 }
@@ -814,7 +1209,8 @@ function dump_qa($plain)
 {
 	global $url, $dist, $arch;
 
-	$f = get_qa();
+	$status = ''; $tried = null; $error = '';
+	$f = get_qa($status, $tried, $error);
 	$da = h($dist . '/' . $arch);
 
 	if ($plain) {
@@ -832,12 +1228,53 @@ function dump_qa($plain)
 	}
 
 	if ($f === false) {
-		echo h(_("Sorry, cannot open."));
+		if ($plain) {
+			echo _("# could not fetch rpm -qa for")." $dist/$arch\n";
+			if ($tried !== null) echo "# tried: $tried\n";
+			if ($status !== '')  echo "# http status: $status\n";
+			if ($error !== '')   echo "# curl error: $error\n";
+		} else {
+			echo h(_("Could not fetch rpm -qa for this builder."));
+			echo "\n";
+			if ($tried !== null) {
+				echo h(_("Tried")).": <a href=\"".h($tried)."\">".h($tried)."</a>\n";
+			}
+			if ($status !== '') {
+				echo h(_("HTTP status")).": ".h($status)."\n";
+			}
+			if ($error !== '') {
+				echo h(_("cURL error")).": ".h($error)."\n";
+			}
+			if ($status === '404') {
+				echo "\n".h(_("This builder may not publish rpmqa snapshots, or none have been generated yet."));
+			}
+		}
 	} else {
+		$header = null;
+		$pkgs = [];
 		while (($s = fgets($f, 1000)) !== false) {
-			echo $plain ? $s : h($s);
+			if ($header === null && stripos($s, 'Query done at:') !== false) {
+				$header = rtrim($s, "\r\n");
+				continue;
+			}
+			if (trim($s) === '') continue;
+			$pkgs[] = $s;
 		}
 		fclose($f);
+		sort($pkgs, SORT_NATURAL | SORT_FLAG_CASE);
+		if ($header !== null) {
+			$line = "# " . $header . "\n";
+			echo $plain ? $line : h($line);
+		}
+		if (empty($pkgs)) {
+			echo $plain
+				? _("# rpm -qa file is empty for")." $dist/$arch\n"
+				: h(_("The rpmqa file is empty."));
+		} else {
+			foreach ($pkgs as $s) {
+				echo $plain ? $s : h($s);
+			}
+		}
 	}
 
 	if (!$plain)
@@ -847,134 +1284,147 @@ function dump_qa($plain)
 
 function adv_search()
 {
-  global $database, $addr, $fail_or_ok, $url, $_POST, $off, $cnt, $root_directory, $ok, $ns;
-
-  $big_url = "$url?ok=$ok&ns=$ns&cnt=$cnt";
-
-  echo "<script><!--\n".
-       "function checkboxToggle() {\n".
-       "for (var i=0;i<document.forms[0].elements.length;i++) {\n".
-       "var e = document.forms[0].elements[i];\n".
-       "if ((e.name != 'all') && (e.type=='checkbox'))\n".
-       "e.checked = document.forms[0].all.checked;\n".
-       "}\n }\n -->\n </script>\n";
-
-  $p_n2    = (string)($_POST["n2"]    ?? '');
-  $p_age1  = (string)($_POST["age1"]  ?? '');
-  $p_age2  = (string)($_POST["age2"]  ?? '');
-  $p_size1 = (string)($_POST["size1"] ?? '');
-  $p_size2 = (string)($_POST["size2"] ?? '');
-
-  echo "<form action=\"index.php?action=adv_search\" method=\"post\">";
-
-  echo "<div align=\"center\">";
-  echo "<table border=\"0\">\n";
-  echo "<tr>\n";
-  echo "<td>"._("Package name")."</td>\n";
-  echo "<td><input type=\"text\" size=\"20\" name=\"n2\" value=\"" . h($p_n2) . "\"/></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Days")."</td>\n";
-  echo "<td>"._("From").": <input type=\"text\" size=\"20\" name=\"age1\" value=\"" . h($p_age1) . "\" /></td>\n";
-  echo "<td>"._("To").": <input type=\"text\" size=\"20\" name=\"age2\" value=\"" . h($p_age2) . "\" /></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Size")."</td>\n";
-  echo "<td>"._("From").": <input type=\"text\" size=\"20\" name=\"size1\" value=\"" . h($p_size1) . "\" /></td>\n";
-  echo "<td>"._("To").": <input type=\"text\" size=\"20\" name=\"size2\" value=\"" . h($p_size2) . "\" /></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Search logs:")."</td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Failed")."</td>\n";
-  echo "<td>"._("OK")."</td>\n";
-  echo "</tr>\n";
-
-  $i = 1;
-  foreach ($addr as $d => $ddist) {
-    foreach ($ddist as $a) {
-    echo "<tr>\n";
-    $label = h($d . '/' . $a);
-    $name = "as0_" . $i;
-    $check = isset($_POST[$name]) ? " checked='checked'" : " ";
-    echo "<td><input name=\"$name\" id=\"$name\" type=\"checkbox\"$check /><label for=\"$name\">$label</label></td>\n";
-    $name = "as1_" . $i;
-    $check = isset($_POST[$name]) ? " checked='checked'" : " ";
-    echo "<td><input name=\"$name\" id=\"$name\" type=\"checkbox\"$check /><label for=\"$name\">$label</label></td>\n";
-    echo "</tr>\n";
-    $i++;
-    }
-  }
-	
-  echo "<tr>\n";
-  echo "<td><label><input name=\"all\" type=\"checkbox\" checked=\"on\" onClick=\"checkboxToggle()\">"._("Toggle checkboxes")."</label> <input type=\"submit\" name=\"submit\" value=\""._("Search!")."\" /></td>";
-  echo "</tr>\n";
+	global $database, $addr, $url, $off, $cnt, $ok, $ns, $dir;
+
+	$req = array_merge($_POST, $_GET);
+
+	$p_n     = (string)($req['n']      ?? $req['n2'] ?? '');
+	$p_dfrom = (string)($req['d_from'] ?? '');
+	$p_dto   = (string)($req['d_to']   ?? '');
+	$p_sfrom = (string)($req['s_from'] ?? '');
+	$p_sto   = (string)($req['s_to']   ?? '');
+	$p_stat  = (string)($req['status'] ?? 'any');
+	if (!in_array($p_stat, ['any','0','1'], true)) $p_stat = 'any';
+
+	if (strlen($p_n) > 64 || !preg_match('/^[A-Za-z0-9_.+\-*?]*$/', $p_n)) $p_n = '';
+	$datetime_re = '/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?)?$/';
+	if ($p_dfrom !== '' && !preg_match($datetime_re, $p_dfrom)) $p_dfrom = '';
+	if ($p_dto   !== '' && !preg_match($datetime_re, $p_dto))   $p_dto   = '';
+	if ($p_sfrom !== '' && !ctype_digit($p_sfrom)) $p_sfrom = '';
+	if ($p_sto   !== '' && !ctype_digit($p_sto))   $p_sto   = '';
+	$ts_from = $p_dfrom !== '' ? strtotime($p_dfrom) : false;
+	$ts_to   = $p_dto   !== '' ? strtotime($p_dto)   : false;
+
+	$p_da_raw = $req['da'] ?? [];
+	if (!is_array($p_da_raw)) $p_da_raw = [$p_da_raw];
+	$p_da = [];
+	foreach ($p_da_raw as $v) {
+		$v = (string)$v;
+		if (preg_match('/^[A-Za-z0-9][A-Za-z0-9_.+-]*\/[A-Za-z0-9][A-Za-z0-9_.+-]*$/', $v)) {
+			$p_da[] = $v;
+		}
+	}
 
-  echo "</table>\n";
+	$has_criteria = ($p_n !== '' || $ts_from !== false || $ts_to !== false
+	                 || $p_sfrom !== '' || $p_sto !== ''
+	                 || !empty($p_da) || $p_stat !== 'any');
 
-  if ($p_n2 !== '' || $p_age1 !== '' || $p_age2 !== '' || $p_size1 !== '' || $p_size2 !== '')
-  {
-	$conditions = ['1=1'];
-	$params = [];
-	if ($p_n2 !== '') {
-		$conditions[] = "name LIKE :name_prefix ESCAPE '\\'";
-		$params[':name_prefix'] = like_escape($p_n2) . '%';
+	echo "<h1>"._("Advanced Search")."</h1>\n";
+	echo "<form action=\"index.php\" method=\"get\">";
+	echo "<input type=\"hidden\" name=\"action\" value=\"adv_search\" />";
+	echo "<input type=\"hidden\" name=\"cnt\" value=\"".(int)$cnt."\" />";
+	if ($ns !== '' && $ns !== 0) {
+		echo "<input type=\"hidden\" name=\"ns\" value=\"".(int)$ns."\" />";
 	}
-	$now = time();
-	if ($p_age1 !== '') {
-		$conditions[] = 'mtime > :age1';
-		$params[':age1'] = $now - ((int)$p_age1) * 24 * 3600;
-	}
-	if ($p_age2 !== '') {
-		$conditions[] = 'mtime < :age2';
-		$params[':age2'] = $now - ((int)$p_age2) * 24 * 3600;
-	}
-	if ($p_size1 !== '') {
-		$conditions[] = 'size > :size1';
-		$params[':size1'] = (int)$p_size1;
-	}
-	if ($p_size2 !== '') {
-		$conditions[] = 'size < :size2';
-		$params[':size2'] = (int)$p_size2;
+
+	echo "<table border=\"0\" cellpadding=\"6\" cellspacing=\"1\" bgcolor=\"#000000\" width=\"90%\" align=\"center\">\n";
+
+	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"middle\" width=\"20%\">"._("Package name")."</th>";
+	echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\"><input type=\"text\" name=\"n\" size=\"40\" maxlength=\"64\" value=\"".h($p_n)."\" placeholder=\"".h(_("glob e.g. foo*, bar?-5"))."\" /></td></tr>\n";
+
+	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"middle\">"._("Date")."</th>";
+	echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\">";
+	echo _("From").": <input type=\"datetime-local\" name=\"d_from\" value=\"".h($p_dfrom)."\" />   ";
+	echo _("To").": <input type=\"datetime-local\" name=\"d_to\" value=\"".h($p_dto)."\" />";
+	echo "</td></tr>\n";
+
+	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"middle\">"._("Size (bytes)")."</th>";
+	echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\">";
+	echo _("From").": <input type=\"number\" name=\"s_from\" min=\"0\" value=\"".h($p_sfrom)."\" />   ";
+	echo _("To").": <input type=\"number\" name=\"s_to\" min=\"0\" value=\"".h($p_sto)."\" />";
+	echo "</td></tr>\n";
+
+	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"middle\">"._("Status")."</th>";
+	echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\">";
+	$status_opts = [['any', _("Any")], ['1', _("OK")], ['0', _("FAIL")]];
+	foreach ($status_opts as [$v, $label]) {
+		$sel = ($p_stat === $v) ? ' checked="checked"' : '';
+		echo "<label><input type=\"radio\" name=\"status\" value=\"".h($v)."\"$sel /> ".h($label)."</label>   ";
 	}
+	echo "</td></tr>\n";
 
-	$dao_clauses = [];
-	$ii = 1;
+	$selected_da = array_flip($p_da);
+	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" valign=\"top\">"._("Builders")."</th>";
+	echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\">";
 	foreach ($addr as $d => $ddist) {
+		echo "<div><b>".h($d)."</b>: ";
 		foreach ($ddist as $a) {
-			for ($j = 0; $j < 2; $j++) {
-				if (isset($_POST["as" . $j . "_" . $ii])) {
-					$pd = ":d{$ii}_{$j}";
-					$pa = ":a{$ii}_{$j}";
-					$dao_clauses[] = "(dist = $pd AND arch = $pa AND ok = $j)";
-					$params[$pd] = $d;
-					$params[$pa] = $a;
-				}
-			}
-			$ii++;
+			$val = $d . '/' . $a;
+			$sel = isset($selected_da[$val]) ? ' checked="checked"' : '';
+			echo "<label><input type=\"checkbox\" name=\"da[]\" value=\"".h($val)."\"$sel /> ".h($a)."</label>   ";
 		}
+		echo "</div>";
+	}
+	echo "<div style=\"margin-top:4px\"><label><input type=\"checkbox\" onclick=\"var cs=this.form.querySelectorAll('input[name="da[]"]');for(var i=0;i<cs.length;i++)cs[i].checked=this.checked\" /> "._("Toggle all")."</label></div>";
+	echo "</td></tr>\n";
+
+	echo "<tr><td bgcolor=\"#CCCCCC\" colspan=\"2\" align=\"center\">";
+	echo "<input type=\"submit\" value=\""._("Search")."\" />   ";
+	echo "<input type=\"reset\" value=\""._("Reset")."\" />";
+	echo "</td></tr>\n";
+
+	echo "</table></form>\n";
+
+	if (!$has_criteria) {
+		return;
+	}
+
+	$conditions = [];
+	$params = [];
+	if ($p_n !== '') {
+		$conditions[] = "name LIKE :name_q ESCAPE '\\'";
+		$params[':name_q'] = glob_to_like($p_n);
+	}
+	if ($ts_from !== false) {
+		$conditions[] = 'mtime >= :ts_from';
+		$params[':ts_from'] = $ts_from;
+	}
+	if ($ts_to !== false) {
+		$conditions[] = 'mtime <= :ts_to';
+		$params[':ts_to'] = $ts_to;
 	}
-	if ($dao_clauses) {
-		$conditions[] = '(' . implode(' OR ', $dao_clauses) . ')';
+	if ($p_sfrom !== '') {
+		$conditions[] = 'size >= :s_from';
+		$params[':s_from'] = (int)$p_sfrom;
 	}
+	if ($p_sto !== '') {
+		$conditions[] = 'size <= :s_to';
+		$params[':s_to'] = (int)$p_sto;
+	}
+	if ($p_stat !== 'any') {
+		$conditions[] = 'ok = :status';
+		$params[':status'] = (int)$p_stat;
+	}
+	if (!empty($p_da)) {
+		$da_clauses = [];
+		$j = 0;
+		foreach ($p_da as $da) {
+			[$d, $a] = explode('/', $da, 2);
+			$pd = ":da_d_$j"; $pa = ":da_a_$j";
+			$da_clauses[] = "(dist = $pd AND arch = $pa)";
+			$params[$pd] = $d;
+			$params[$pa] = $a;
+			$j++;
+		}
+		$conditions[] = '(' . implode(' OR ', $da_clauses) . ')';
+	}
+	$where = empty($conditions) ? '1=1' : implode(' AND ', $conditions);
 
-	$order_whitelist = [
-		0 => 'mtime DESC',
-		1 => 'name',
-		2 => 'dist, arch, name',
-	];
-	$ns_int = is_int($ns) ? $ns : (int)$ns;
-	$order = $order_whitelist[$ns_int] ?? 'mtime DESC';
+	$ns_int = ($ns === '') ? 0 : (int)$ns;
+	$order = SORT_ORDER_BY[$ns_int . effective_dir($ns, $dir)] ?? 'mtime DESC';
 
-	$sql = 'SELECT log_id, dist, arch, ok, name, size, mtime, id FROM logs WHERE '
-		. implode(' AND ', $conditions)
-		. ' ORDER BY ' . $order
-		. ' LIMIT :limitnr OFFSET :offset';
+	$sql = 'SELECT log_id, dist, arch, ok, name, size, mtime, id, runtime FROM logs WHERE '
+		. $where . ' ORDER BY ' . $order . ' LIMIT :limitnr OFFSET :offset';
 
 	try {
 		$dbh = new PDO($database);
@@ -982,6 +1432,7 @@ function adv_search()
 		$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
 	} catch (PDOException $e) {
 		mydie("new PDO: " . $e->getMessage());
+		return;
 	}
 	$stmt = $dbh->prepare($sql);
 	foreach ($params as $k => $v) {
@@ -992,117 +1443,101 @@ function adv_search()
 	$stmt->execute();
 	$result = $stmt->fetchAll();
 
+	$state = ['action' => 'adv_search', 'cnt' => $cnt];
+	if ($p_n !== '')       $state['n']      = $p_n;
+	if ($p_dfrom !== '')   $state['d_from'] = $p_dfrom;
+	if ($p_dto !== '')     $state['d_to']   = $p_dto;
+	if ($p_sfrom !== '')   $state['s_from'] = $p_sfrom;
+	if ($p_sto !== '')     $state['s_to']   = $p_sto;
+	if ($p_stat !== 'any') $state['status'] = $p_stat;
+	if (!empty($p_da))     $state['da']     = $p_da;
+	$base_url = h($url . '?' . http_build_query($state));
+
 	if (empty($result)) {
-		echo h(_("Nothing found"));
-	} else {
-		$big_url_esc = h($big_url);
-		echo "<table border=\"0\" cellspacing=\"1\" ".
-			"cellpadding=3 bgcolor=\"#000000\" width=\"90%\">\n";
-		echo "<tr><th bgcolor=\"#CCCCFF\" align=\"left\" width=\"10%\">"._("Builder").
-			"[<a href=\"$big_url_esc&ns=2\">"._("sort")."</a>]</th>";
-		echo "<th bgcolor=\"#CCCCFF\" align=\"left\" width=\"60%\">"._("Log File").
-			"[<a href=\"$big_url_esc&ns=1\">"._("sort")."</a>]</th>".
-			"<th bgcolor=\"#CCCCFF\" align=\"right\" width=\"15%\">"._("Size")."</th> ".
-			"<th bgcolor=\"#CCCCFF\" align=\"left\">"._("Age").
-			"[<a href=\"$big_url_esc&ns=0\">"._("sort")."</a>]</th>".
-			"</th></tr>";
-		$i = $off;
-		foreach ($result as $row) {
-			$r_dist = (string)$row["dist"];
-			$r_arch = (string)$row["arch"];
-			$r_name = (string)$row["name"];
-			$r_id   = (string)$row["id"];
-			$r_ok   = (int)$row["ok"];
-			$r_size = (int)$row["size"];
-			$r_mtime = (int)$row["mtime"];
+		echo "<p align=\"center\">".h(_("Nothing found"))."</p>";
+		return;
+	}
 
+	$now = time();
+	$sl = function(int $col_ns, string $label) use ($base_url, $ns, $dir) {
+		return "<a href=\"$base_url&" . sort_target($col_ns, $ns, $dir) . "\">$label</a>"
+			. sort_arrow($col_ns, $ns, $dir);
+	};
+	echo "<div align=\"center\"><table border=\"0\" cellspacing=\"1\" cellpadding=\"6\" bgcolor=\"#000000\" width=\"90%\">\n";
+	echo "<tr>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(3, _("Status"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(5, _("Dist"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(4, _("Arch"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"left\" valign=\"middle\" width=\"60%\">".$sl(1, _("Log File"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(6, _("Runtime"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(2, _("Size"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(0, _("Date"))."</th>";
+	echo "<th bgcolor=\"#CCCCFF\" align=\"center\" valign=\"middle\">".$sl(0, _("Age"))."</th>";
+	echo "</tr>\n";
+	foreach ($result as $row) {
+		$r_dist = (string)$row["dist"];
+		$r_arch = (string)$row["arch"];
+		$r_name = (string)$row["name"];
+		$r_id   = (string)$row["id"];
+		$r_ok   = (int)$row["ok"];
+		$r_size = (int)$row["size"];
+		$r_mtime = (int)$row["mtime"];
+
+		if (($now - $r_mtime) < 0) {
+			$t_str = _("in future");
+		} else {
 			$t = ($now - $r_mtime) / 60;
 			if ($t >= 60) {
 				$t /= 60;
 				if ($t >= 24) {
-					$t /= 24;
-					$t = round($t);
-					$t_str = $t . " " . ngettext("day","days",(int)$t);
+					$t /= 24; $t = (int)round($t);
+					$t_str = $t . " " . ngettext("day","days",$t);
 				} else {
-					$t = round($t);
-					$t_str = $t . " " . ngettext("hour","hours",(int)$t);
+					$t = (int)round($t);
+					$t_str = $t . " " . ngettext("hour","hours",$t);
 				}
 			} else {
-				$t = round($t);
-				$t_str = $t . " " . ngettext("minute","minutes",(int)$t);
+				$t = (int)round($t);
+				$t_str = $t . " " . ngettext("minute","minutes",$t);
 			}
-
-			$u = h($url . '?' . http_build_query([
-				'dist' => $r_dist,
-				'arch' => $r_arch,
-				'name' => $r_name,
-				'ok'   => $r_ok,
-				'id'   => $r_id,
-			]));
-			$b = h($url . '?' . http_build_query([
-				'dist' => $r_dist,
-				'arch' => $r_arch,
-				'ok'   => $r_ok,
-				'ns'   => is_int($ns) ? $ns : 0,
-				'off'  => $off,
-				'cnt'  => $cnt,
-			]));
-			$builder = h($r_dist . '/' . $r_arch . '/' . $fail_or_ok[$r_ok]);
-
-			echo "<tr>";
-			echo "<td bgcolor=\"#CCCCCC\"><a href=\"$b\">$builder</a></td>";
-			echo "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">" . h($r_name) . "</a> ".
-				"[<a href=\"$u&action=text\">"._("text")."</a> | ".
-				"<a href=\"$u&action=tail\">"._("tail")."</a>]".
-				"</td><td bgcolor=\"#CCCCCC\" align=\"right\">".
-				h((string)$r_size)."</td><td bgcolor=\"#CCCCCC\">$t_str</td></tr>\n";
-			$i++;
 		}
-		echo "</table></div>\n";
-
-		$backarr = "<<< ";
-		$back = _("Page back");
-		$forward = _("Page forward");
-		$forwardarr = " >>>";
+		$date_str = date("Y/m/d H:i:s", $r_mtime);
 
+		$u = h($url . '?' . http_build_query([
+			'dist' => $r_dist, 'arch' => $r_arch,
+			'name' => $r_name, 'ok' => $r_ok, 'id' => $r_id,
+		]));
+		$status = $r_ok
+			? "<font color=\"green\"><b>"._("OK")."</b></font>"
+			: "<font color=\"red\"><b>"._("FAIL")."</b></font>";
+
+		echo "<tr>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\">$status</td>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($r_dist)."</td>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($r_arch)."</td>";
+		echo "<td bgcolor=\"#CCCCCC\" valign=\"middle\"><a href=\"$u\">".h($r_name)."</a> ".
+			"[<a href=\"$u&action=text\">"._("text")."</a> | ".
+			"<a href=\"$u&action=tail\">"._("tail")."</a>]</td>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".format_runtime($row["runtime"] ?? null)."</td>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\">".h((string)$r_size)."</td>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">".h($date_str)."</td>";
+		echo "<td bgcolor=\"#CCCCCC\" align=\"center\" valign=\"middle\" nowrap=\"nowrap\">$t_str</td>";
+		echo "</tr>\n";
 	}
-// FIXME
-/*
-	echo "<p><table width=\"90%\" align=\"center\"><tr><td align=left width=1%>";
+	echo "</table></div>\n";
 
+	echo "<p align=\"center\">";
 	if ($off > 0) {
-		$noff = $off - $cnt;
-		if ($noff < 0)	
-			$noff = 0;
-		$hrefurl = "<a href=\"$big_url&off=$noff\">";
-		echo "$hrefurl$backarr</a></td><td align=left>$hrefurl$back</a>";
-	} else {
-		echo "$backarr</td><td align=left>$back";
+		$prev = max(0, $off - $cnt);
+		$pu = h($url . '?' . http_build_query($state + ['off' => $prev]));
+		echo "[<a href=\"$pu\">"._("Page back")."</a>]   ";
 	}
-
-    echo "</td>\n<td align=\"center\">";
-    echo "</td>\n<td align=\"right\">";
-
-    if ($off + $cnt < count($list))
-    {
-      $noff = $off + $cnt;
-      if ($noff < 0)	
-        $noff = 0;
-      $hrefurl = "<a href=\"$big_url&off=$noff\">";
-      echo "$hrefurl$forward</a></td><td align=\"right\" width=\"1%\">$hrefurl$forwardarr</a>";
-    }
-    else
-    {
-      echo "$forward</td><td align=\"right\" width=\"1%\">$forwardarr";
-    }
-
-    echo "</td>\n</tr></table></p>";
-*/
-  } else
-  {
-    echo _("Enter something!");
-  }
-  echo "</div></form>\n";
+	if (count($result) == $cnt) {
+		$next = $off + $cnt;
+		$nu = h($url . '?' . http_build_query($state + ['off' => $next]));
+		echo "[<a href=\"$nu\">"._("Page forward")."</a>]";
+	}
+	echo "</p>";
 }
 
 function welcome()
@@ -1136,9 +1571,9 @@ if ($action == "text") {
 	dump_qa(1);
 } else {
 	myheader();
-	echo "<table cellpadding=\"10\" width=\"100%\"><tr><td valign=\"top\" width=\"10%\">";
+	echo "<table cellpadding=\"10\" width=\"100%\"><tr><td style=\"vertical-align: top\" width=\"10%\">";
 	list_archs();
-	echo "</td><td valign=\"top\">";
+	echo "</td><td style=\"vertical-align: top\">";
 	flush();
 	if ($action == "qa")
 		dump_qa(0);
@@ -1146,10 +1581,13 @@ if ($action == "text") {
 		search_qa();
 	else if (isset($id) || isset($name))
 		dump_log($action == "tail");
-	else if (isset($dist))
+	else if (isset($dist) || $q !== '')
 		list_logs();
-	else
-		welcome();
+	else {
+		$keys = array_keys($addr);
+		$dist = $keys[0] ?? 'th';
+		list_logs();
+	}
 	echo "</td></tr></table>";
 	trailer();
 }
diff --git a/lib.php b/lib.php
new file mode 100644
index 0000000..ec6d6cd
--- /dev/null
+++ b/lib.php
@@ -0,0 +1,26 @@
+<?php
+declare(strict_types=1);
+
+function decompressor_for(string $path): string {
+	if (preg_match('/\.bz2$/', $path)) {
+		return is_executable('/usr/bin/lbzcat') ? '/usr/bin/lbzcat' : '/usr/bin/bzcat';
+	}
+	if (preg_match('/\.gz$/', $path)) {
+		return '/usr/bin/zcat';
+	}
+	return '/bin/cat';
+}
+
+function open_log_stream(string $path) {
+	$descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
+	$proc = proc_open([decompressor_for($path), $path], $descriptors, $pipes);
+	if (!is_resource($proc)) return null;
+	fclose($pipes[0]);
+	fclose($pipes[2]);
+	return ['proc' => $proc, 'fd' => $pipes[1]];
+}
+
+function close_log_stream(array $h): void {
+	fclose($h['fd']);
+	proc_close($h['proc']);
+}
diff --git a/obsolete/buildlogs.sql/PRZECZYTAJ.TO b/obsolete/buildlogs.sql/PRZECZYTAJ.TO
deleted file mode 100644
index 0c4dc9d..0000000
--- a/obsolete/buildlogs.sql/PRZECZYTAJ.TO
+++ /dev/null
@@ -1,32 +0,0 @@
-# vim:fileencoding=UTF-8
-# $Revision: 1.3 $, $Date: 2007-11-28 12:42:52 $
-
-Poprzedni silnik buildlogów był mało wydajny, szczególnie dla szukania
-zaawansowanego. Ten silnik korzysta z bazy sqlite3 (php-pdo-sqlite)
-i jest w miarę szybki.
-
-Najpierw należy zainicjalizować bazę danych przy pomocy skryptu migration.php.
-Skrypt ten wymaga php-program. Należy go uruchomić raz. Czas wykonywania
-zależy od liczby plików i filesystemu. Może to trwać kilka minut.
-
-Następnie umieścić index.php, buildlogs.inc i powpld.png na serwerze www.
-Skrypt wymaga dodatkowo php-gettext.
-
-Każdy nowy buildlog (dla nowego lub starego speca) powinien zostać
-dodany do bazy używając skryptu addlog.php (korzysta z php-cli i php-pdo-sqlite).
-W zależności od tego czy spec jest nowy czy nie, w bazie zostanie uaktualniony
-rekord lub dodany nowy. Parametrem dla addlog.php jest bezwzględna ścieżka
-do pliku loga,
-np. addlog.php /home/services/ftp/pub/pld-buildlogs/ac/i686/OK/kernel.bz2
-
-
-Skrypty index.php, addlog.php i migration.php używają zmiennej $database.
-Zmienna ta powinna być jednakowa we wszystkich trzech skryptach.
-Jej obecna wartość to 'sqlite:/home/services/ftp/buildlogs.db'.
-Należy ją ustawić na taką wartość, by plik bazy i katalog, w którym się on znajduje
-był zapisywalny przez skrypty migration.php i addlog.php oraz możliwy do odczytania przez
-index.php.
-
-Konfiguracja skryptów jest zapisana w pliku buildlogs.inc.
-Po każdej zmianie w tym pliku należy się upewnić, czy numerki się zgadzają
-i przebudować bazę uruchamiając migration.php.
diff --git a/obsolete/buildlogs.sql/addlog.php b/obsolete/buildlogs.sql/addlog.php
deleted file mode 100644
index e89f013..0000000
--- a/obsolete/buildlogs.sql/addlog.php
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/php.cli
-<?php
-// $Revision: 1.8 $, $Date: 2008/03/12 15:59:00 $
-/*
-$database = 'sqlite:/home/services/httpd/html/pld-buildlogs/db/buildlogs.db';
-$root_directory = '/home/services/ftp/pub/pld-buildlogs';
-// $database and $root_directory are taken from buildlogs.inc .
-// parameter: argv[1] - full path to the log file.
-// Keep in sync with database
-$reverse_addr = array(
-	"th/SRPMS" => 1,
-	"th/i486" => 2,
-	"th/i686" => 3,
-	"th/athlon" => 4,
-	"th/x86_64" => 5,
-	"th/ia64" => 6,
-	"th/alpha" => 7,
-	"th/ppc" => 8,
-	"th/sparc" => 9,
-	"ac/SRPMS" => 10,
-	"ac/i386" => 11,
-	"ac/i586" => 12,
-	"ac/i686" => 13,
-	"ac/athlon" => 14,
-	"ac/amd64" => 15,
-	"ac/alpha" => 16,
-	"ac/ppc" => 17,
-	"ac/sparc" => 18,
-	"ac/sparc64" => 19
-);
-*/
-
-$result = array("FAIL" => 0, "OK" => 1);
-require('buildlogs.inc');
-
-if (!isset($argv[1])) {
-	die("Usage: $argv[0] full_path_to_the_log\n");
-}
-preg_match("|$root_directory/(.*/.*)/(.*)/(.*)\.bz2|", $argv[1], $matches);
-
-$arch_name = $matches[1];
-if (!array_key_exists($arch_name, $reverse_addr)) {
-	die("$argv[1]: Nieznana architektura \"$arch_name\"\n");
-}
-else $arch_id = $reverse_addr[$arch_name];
-
-$result_name = $matches[2];
-if (!array_key_exists($result_name, $result)) {
-	die("$argv[1]: Nieznany resultat \"$result_name\"\n");
-}
-else $result_id = $result[$result_name];
-
-$spec_name = $matches[3];
-if ($spec_name == '') {
-	die("$argv[1]: Brak nazwy speca.\n");
-}
-
-$spec_name = addslashes($spec_name);
-$size = filesize($argv[1]);
-$mtime = filemtime($argv[1]);
-
-try {
-	$dbh = new PDO("$database");
-} catch (PDOException $e) {
-	die ($e->getMessage());
-}
-$result = $dbh->query("SELECT log_id FROM logs WHERE spec = '$spec_name' AND arch_id = $arch_id LIMIT 1")->fetchAll();
-if (count($result) == 1) {
-	foreach ($result as $row) {
-		$query = "UPDATE logs SET result = $result_id, size = $size, mtime = $mtime WHERE log_id = $row[log_id]";
-		break;
-	}
-} else {
-	$query = "INSERT INTO logs(arch_id, result, size, mtime, spec) VALUES($arch_id, $result_id, $size, $mtime, '$spec_name')";
-}
-$ile = $dbh->exec("$query");
-if ($ile != 1) {
-	print_r($dbh->errorInfo());
-}
-?>
diff --git a/obsolete/buildlogs.sql/buildlogs.inc b/obsolete/buildlogs.sql/buildlogs.inc
deleted file mode 100644
index ae0462d..0000000
--- a/obsolete/buildlogs.sql/buildlogs.inc
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-$database_file = "/home/services/httpd/html/pld-buildlogs/db/buildlogs.db";
-$database = "sqlite:$database_file";
-$root_directory = "/home/services/ftp/pub/pld-buildlogs";
-$addr = array(
-	0 => "", /* must be first */
-	1 => "th/SRPMS",
-	2 => "th/i486",
-	3 => "th/i686",
-	4 => "th/athlon",
-	5 => "th/x86_64",
-//	6 => "th/amd64",
-//	6 => "th/ia64",
-	7 => "th/alpha",	
-	8 => "th/ppc",
-//	9 => "th/sparc",
-	10 => "ac/SRPMS",
-	11 => "ac/i386",
-	12 => "ac/i586",
-	13 => "ac/i686",
-	14 => "ac/athlon",
-	15 => "ac/amd64",
-	16 => "ac/alpha",	
-	17 => "ac/ppc",
-	18 => "ac/sparc",
-	19 => "ac/sparc64"
-);
-
-$qa_addr = array(
-	0 => "", /* must be first */
-	1 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-SRPMS.txt",
-	2 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-i486.txt",
-	3 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-i686.txt",
-	4 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-athlon.txt",
-	5 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-x86_64.txt",
-//	6 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-amd64.txt",
-	6 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-ia64.txt",
-	7 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-alpha.txt",	
-	8 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-ppc.txt",
-	9 => "http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-sparc.txt",
-	10 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-SRPMS.txt",
-	11 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i386.txt",
-	12 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i586.txt",
-	13 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i686.txt",
-	14 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-athlon.txt",
-	15 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-amd64.txt",
-	16 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-alpha.txt",	
-	17 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-ppc.txt",
-	18 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-sparc.txt",
-	19 => "http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-sparc64.txt"
-);
-
-$reverse_addr = array(
-	"th/SRPMS" => 1,
-	"th/i486" => 2,
-	"th/i686" => 3,
-	"th/athlon" => 4,
-	"th/x86_64" => 5,
-	"th/amd64" => 5,
-	"th/ia64" => 6,
-	"th/alpha" => 7,
-	"th/ppc" => 8,
-	"th/sparc" => 9,
-	"ac/SRPMS" => 10,
-	"ac/i386" => 11,
-	"ac/i586" => 12,
-	"ac/i686" => 13,
-	"ac/athlon" => 14,
-	"ac/amd64" => 15,
-	"ac/alpha" => 16,
-	"ac/ppc" => 17,
-	"ac/sparc" => 18,
-	"ac/sparc64" => 19
-);
-
-?>
diff --git a/obsolete/buildlogs.sql/index.php b/obsolete/buildlogs.sql/index.php
deleted file mode 100644
index b4fd09f..0000000
--- a/obsolete/buildlogs.sql/index.php
+++ /dev/null
@@ -1,1111 +0,0 @@
-<?php
-ob_start("ob_gzhandler", 1);
-$buildlogs_server = "buildlogs.pld-linux.org";
-$url = "index.php";
-$fail_or_ok = array( "FAIL", "OK" );
-/*
-$addr = array(
-	"",
-	"th/SRPMS",
-	"th/i486",
-	"th/i686",
-	"th/athlon",
-	"th/x86_64",
-	"th/ia64",
-	"th/alpha",	
-	"th/ppc",
-	"th/sparc",
-	"ac/SRPMS",
-	"ac/i386",
-	"ac/i586",
-	"ac/i686",
-	"ac/athlon",
-	"ac/amd64",
-	"ac/alpha",	
-	"ac/ppc",
-	"ac/sparc",
-	"ac/sparc64",
-);
-*/
-/*
-$qa_addr = array(
-	"",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-SRPMS.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-i486.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-i686.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-athlon.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-x86_64.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-ia64.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-alpha.txt",	
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-ppc.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-sparc.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-SRPMS.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i386.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i586.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i686.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-athlon.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-amd64.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-alpha.txt",	
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-ppc.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-sparc.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-sparc64.txt"/*,
-);
-$database = 'sqlite:/home/services/ftp/buildlogs.db';
-$root_directory = "/home/services/ftp/pub/pld-buildlogs";
-*/
-
-$local = 1; /* $local=0 for FTP */ 
-
-// $database, $root_directory and others are taken from buildlogs.inc
-include('buildlogs.inc');
-
-$ftp_conn = 0;
-/* It should be set */
-
-$langs["en_US"]["charset"]="ISO-8859-1";
-$langs["pl_PL"]["charset"]="ISO-8859-2";
-
-$lang="en_US";
-if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
-{
-  $rows=explode(";",$_SERVER["HTTP_ACCEPT_LANGUAGE"]);
-  $rows=explode(",",$rows[0]);
-  $lang_detected=rtrim($rows[0]);
-} else if (preg_match("/opera/i",$_SERVER["HTTP_USER_AGENT"]))
-{
-  $lang_detected=preg_replace("/.*\[(.*)\].*/i","\\1",$_SERVER["HTTP_USER_AGENT"]);
-}
-
-// FIXME - some array
-$lang_detected=preg_replace("/^pl$/i","pl_PL",$lang_detected);
-
-if (isset($lang_detected) && isset($langs[$lang_detected]))
-{
-  $lang=$lang_detected;
-}
-
-if (isset($_GET["lang"]))$_SESSION["lang"]=$_GET["lang"];
-if (isset($_SESSION["lang"]))$lang=$_SESSION["lang"];
-
-putenv("LANG=$lang");
-setlocale(LC_ALL,$lang);
-bindtextdomain("messages","locale");
-textdomain("messages");
-
-if (isset($_GET["idx"]))$idx=(int)$_GET["idx"];
-if (isset($_GET["dist"]) && isset($_GET["arch"]))
-{
-	$i = $_GET["dist"] . "/" . $_GET["arch"];
-	$idx = (int)$reverse_addr["$i"];
-}
-if (isset($_GET["ok"]))$ok=(int)$_GET["ok"];
-else $ok="";
-if (isset($_GET["ns"]))$ns=(int)$_GET["ns"];
-else $ns="";
-if (isset($_GET["cnt"]))$cnt=(int)$_GET["cnt"];
-else $cnt = 50;
-if (isset($_GET["action"]))$action=$_GET["action"];
-else $action="";
-if (isset($_GET["off"]))$off=(int)$_GET["off"];
-else $off = 0;
-if (isset($_GET["id"]))$id=$_GET["id"];
-if (isset($_GET["log"]))$log=(int)$_GET["log"];
-
-if (isset($_POST["str"]))$str=$_POST["str"];
-if (isset($_POST["idx"]))$idx=(int)$_POST["idx"];
-if (isset($_POST["action"]))$action=$_POST["action"];
-
-function myheader()
-{
-echo '<' . '?xml version="1.0" encoding="' . _("ISO-8859-1") .'"?' . ">\n";
-echo '<' . '?xml-stylesheet href="#internalStyle" type="text/css"?' . ">\n";
-?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
-  <title>PLD Build Logs</title>
-  <?php echo '<meta http-equiv="Content-type" content="text/html; charset=' . _("ISO-8859-1") .'"/>' ."\n";?>
-  <style type="text/css"><!--
-A { text-decoration: none; }
-A:hover { text-decoration: underline; }
-H1 { font-family: arial,helvetica,sans-serif; 
-     font-size: 20pt; 
-     font-weight: bold;}
-H2 { font-family: arial,helvetica,sans-serif; 
-     font-size: 18pt; 
-     font-weight: bold;}
-BODY,TD { font-family: arial,helvetica,sans-serif; 
-          font-size: 13pt; }
-TH { font-family: arial,helvetica,sans-serif; 
-     font-size: 13pt; 
-     font-weight: bold; }
-//-->
-</style>
- </head>
- <!-- Diffrent color for visited link doesn't make much sense here...
-      this page is autogenerated and it might be misleading after some
-      build log changes. -->
- <body bgcolor="#ffffff" text="#000000" link="#5f26cd" vlink="#5f26cd">
-<?php
-}
-
-function start_pre()
-{
-	echo "<table cellpadding=\"10\"><tr><td bgcolor=\"#000000\">".
-		"<font color=\"#cccccc\"><pre style=\"width: 2048px;overflow: scroll\">";
-}
-
-function end_pre()
-{
-	echo "</pre></font></td></tr></table>\n";
-}
-
-function trailer()
-{
-	echo "</body></html>";
-}
-
-
-function mydie($msg)
-{
-	echo "Fatal error: $msg";
-}
-
-function open_ftp($pidx="", $pok="")
-{
-	global $idx, $addr, $buildlogs_server, $ok;
-	global $ftp_conn, $big_url, $url, $ns;
-	global $off, $cnt;
-	
-	if ($pidx==="")$pidx=$idx;
-	if ($pok==="")$pok=$ok;
-
-	if (!isset($pidx) || !isset($addr[$pidx]))
-		return false;
-
-	if ($pok != 1)
-		$pok = 0;
-	if ($ns != 1)
-		$ns = 0;
-
-	if ($pok == 1) {
-		$a = "$addr[$pidx]/OK";
-	} else {
-		$a = "$addr[$pidx]/FAIL";
-	}
-
-	if (!isset($off))
-		$off = 0;
-	if (!isset($cnt))
-		$cnt = 16;
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	$ftp = ftp_connect($buildlogs_server);
-
-	if ($ftp == false) {
-		mydie(_("cannot connect to")." $buildlogs_server");
-		return false;
-	}
-
-	if (ftp_login($ftp, "anonymous", 
-		      "buildlogs-iface at pld-linux.org") == false) {
-		ftp_quit($ftp);
-		mydie(_("cannot ftp login to")." $buildlogs_server");
-		return false;
-	}
-
-	$list = ftp_nlist($ftp, $a);
-	if ($list == false) {
-		ftp_quit($ftp);
-		mydie(_("cannot list")." $a");
-		return false;
-	}
-
-	$ftp_conn = $ftp;
-
-	return $list;
-}
-
-function directory_list($pidx="",$pok="")
-{
-	global $idx, $addr, $buildlogs_server, $ok;
-	global $root_directory, $big_url, $url, $ns;
-	global $off, $cnt;
-
-	if ($pidx==="")$pidx=$idx;
-	if ($pok==="")$pok=$ok;
-	if (!isset($pidx) || !isset($addr[$pidx]))
-		return false;
-
-	if ($pok != 1)
-		$pok = 0;
-	if ($ns != 1)
-		$ns = 0;
-
-	if ($pok == 1) {
-		$a = "$addr[$pidx]/OK";
-	} else {
-		$a = "$addr[$pidx]/FAIL";
-	}
-
-	if (!isset($off))
-		$off = 0;
-	if (!isset($cnt))
-		$cnt = 16;
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	$dir = opendir("$root_directory/$a");
-	$i = 0;
-	$list = array ();
-	while ($file = readdir($dir)) {
-		if (($file != ".") && ($file != "..")) {
-			$list[$i] = array("/$a/$file", filemtime("$root_directory/$a/$file"));
-			$i++;
-		}
-	}
-	closedir($dir);
-	return $list;
-}
-
-function list_logs()
-{
-	global $database;
-	global $idx, $addr, $ok;
-	global $ftp_conn, $big_url, $ns, $qa_addr;
-	global $off, $cnt, $local, $root_directory, $url;
-/*
-	if ($local) {
-		$list = directory_list();
-	} else {
-		$list = open_ftp();
-	}
-	if ($list == false)
-		return;
-*/
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	if ($ok == 1) {
-		echo "<h1>"._("Listing of")." $addr[$idx]/OK "
-			."(<a href=\"$big_url&ok=0\">"._("fail")."</a>)</h1>\n";
-	} else {
-		echo "<h1>"._("Listing of")." $addr[$idx]/FAIL "
-			."(<a href=\"$big_url&ok=1\">"._("ok")."</a>)</h1>\n";
-	}
-
-	echo "<div align=\"center\"><table cols=\"4\" border=\"0\" cellspacing=\"1\" ".
-		"cellpadding=\"3\" bgcolor=\"#000000\" width=\"90%\">\n";
-	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" width=\"1%\">"._("No.")."</th>".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\" width=\"80%\">"._("Log File").
-			"[<a href=\"$big_url&ns=1\">"._("sort")."</a>]</th>".
-		 "<th bgcolor=\"#CCCCFF\" align=\"right\" width=\"15%\">"._("Size")."</th> ".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\">"._("Age").
-			 "[<a href=\"$big_url&ns=0\">"._("sort")."</a>]</th>".
-		 "</tr>";
-/*
-	function cmp($f1, $f2) {
-		global $ftp_conn, $root_directory, $local;
-		if ($local)
-			return $f2[1] - $f1[1];//filemtime("$root_directory$f2") - filemtime("$root_directory$f1");
-		return ftp_mdtm($ftp_conn, $f2) - ftp_mdtm($ftp_conn, $f1);
-	}
-
-	function cmp2($f1, $f2) {
-		return strcmp($f1[0], $f2[0]);
-	}
-
-	if ($ns != 1) {
-		$ns = 0;
-		usort($list, "cmp");
-	} else {
-		usort($list, "cmp2");
-	}
-*/
-	if ($ns != 1) $ns = 0;
-	if (!isset($idx)) $idx = 1;
-	if (!isset($ok)) $ok = 0;
-//	if (!isset($off)) $off = 0;
-//	if (!isset($cnt)) $cnt = 50;
-	if ($ns == 0) $order = "mtime DESC";
-	else $order = "spec";
-
-	$query = "SELECT spec, log_id, mtime, size FROM logs WHERE "
-	. "arch_id = $idx AND result = $ok ORDER BY $order LIMIT $cnt OFFSET $off";
-
-	try {
-		$dbh = new PDO("$database");
-	} catch (PDOException $e) {
-		mydie("new PDO: " . $e->getMessage());
-	}
-	$now = time();
-	$i = $off;
-	foreach ($dbh->query("$query") as $row) {
-//	$now = time();
-//	for ($i = $off; $i < $count + $off; $i++) {
-//		$row = mysql_fetch_assoc($result);
-		$f = $row["spec"];
-		$t = $now - $row["mtime"];
-		$s = $row["size"];
-		$h = $row["log_id"];
-/*		
-		if (!isset($filename))
-			continue;
-		$h = bin2hex(mhash(MHASH_MD5, $filename));
-		$f = preg_replace("/.*\/([^\/]*)$/", "\\1", $filename);
-		$f = preg_replace("/\.(bz2|gz)$/", "", $f);
-		if ($local) {
-			$s = filesize("$root_directory/$filename");
-			$t = $now - $list[$i][1];
-		} else {
-			$s = ftp_size($ftp_conn, $list[$i]);
-			$t = $now - ftp_mdtm($ftp_conn, $list[$i]);
-		}
-*/
-		$t /= 60;
-		if ($t >= 60) {
-			$t /= 60;
-			if ($t >= 24) {
-				$t /= 24;
-				$t = round($t);
-				$t = $t . " " . ngettext("day","days",$t);
-			} else {
-				$t = round($t);
-				$t = $t . " " . ngettext("hour","hours",$t);
-			}
-		} else {
-			$t = round($t);
-			$t = $t . " " . ngettext("minute","minutes",$t);
-		}
-//		$u = "$big_url&off=$off&id=$h";
-		$u = "$url?log=$h";
-		echo "<tr><td bgcolor=\"#CCCCCC\" align=\"right\">".($i+1).".</td>".
-		     "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">$f</a> ".
-		     "[<a href=\"$u&action=text\">"._("text")."</a> | ".
-		      "<a href=\"$u&action=tail\">"._("tail")."</a>]".
-		     "</td><td bgcolor=\"#CCCCCC\" align=\"right\">".
-		     "$s</td><td bgcolor=\"#CCCCCC\">$t</td></tr>\n";
-		$i++;
-	}
-	$count = $i - $off;
-	echo "</table></div>\n";
-
-	$backarr = "<<< ";
-	$back = _("Page back");
-	$forward = _("Page forward");
-	$forwardarr = " >>>";
-
-	echo "<p><table width=\"90%\" align=\"center\"><tr><td align=\"left\" width=\"1%\">";
-
-	if ($off > 0) {
-		$noff = $off - $count;
-		if ($noff < 0)	
-			$noff = 0;
-		$hrefurl = "<a href=\"$big_url&off=$noff\">";
-		echo "$hrefurl$backarr</a></td><td align=\"left\">$hrefurl$back</a>";
-	} else {
-		echo "$backarr</td><td align=\"left\">$back";
-	}
-
-	echo "</td>\n<td align=\"center\">";
-
-	if ($qa_addr[$idx] != "") {
-		echo "[<a href=\"$big_url&action=qa\">"._("View <quot>rpm -qa</quot> of builder")."</a>]";
-	} else {
-		echo " ";
-	}
-
-	echo "</td>\n<td align=right>";
-//	if ($off + $cnt < count($list)) {
-	if ($cnt == $count) {
-		$noff = $off + $cnt;
-		if ($noff < 0)	
-			$noff = 0;
-		$hrefurl = "<a href=\"$big_url&off=$noff\">";
-		echo "$hrefurl$forward</a></td><td align=right width=1%>$hrefurl$forwardarr</a>";
-	} else {
-		echo "$forward</td><td align=right width=1%>$forwardarr";
-	}
-	echo "</td>\n</tr></table></p>";
-//	if ($local == 0) {
-//		ftp_quit($ftp_conn);
-//		$ftp_conn = 0;
-//	}
-}
-
-function file_name_log($l)
-{
-	global $database, $addr, $fail_or_ok, $idx, $ok;
-	try {
-		$dbh = new PDO($database);
-	} catch (PDOException $e) {
-		mydie("new PDO: " . $e->getMessage());
-	}
-	$f = false;
-	foreach ($dbh->query("SELECT arch_id, result, spec FROM logs WHERE log_id = $l LIMIT 1") as $row) {
-		$f = $addr[$row["arch_id"]] . "/" . $fail_or_ok[$row["result"]] . "/" . $row["spec"] . ".bz2";
-		$idx = $row["arch_id"]; /* for rpmqa */
-		$ok = $row["result"]; /* for status */
-	}
-	return $f;
-}
-
-function file_name()
-{
-	global $idx, $addr, $ok;
-	global $ftp_conn, $root_directory, $big_url, $ns, $id;
-	global $buildlogs_server, $local, $log;
-
-	if (isset($log)) return file_name_log($log);
-	if (isset($_GET['name']) && isset($ok) && isset($_GET['arch']) && isset($_GET['dist'])) {
-		$name = basename($_GET['name']);
-		$arch = basename($_GET['arch']);
-		$dist = basename($_GET['dist']);
-		$w = $ok ? "OK" : "FAIL";
-		return "$dist/$arch/$w/$name.bz2";
-	}
-	if (!isset($id))
-		return false;
-	if ($local) {
-		$list = directory_list();
-	} else {
-		$list = open_ftp();
-	}
-	if ($list == false)
-		return false;
-
-	$f = false;
-	for ($i = 0; $i < count($list); $i++) {
-		$h = bin2hex(mhash(MHASH_MD5, $list[$i][0]));
-		if ($h == $id) {
-			$f = $list[$i][0];
-			break;
-		}
-	}
-
-	if ($f == false) {
-		mydie(_("cannot find specified file:")." $id");
-		if ($local == 0)
-			ftp_quit($ftp_conn);
-		return false;
-	}
-
-	return $f;
-}
-
-function dump_log($tail)
-{
-	global $idx, $addr, $ok, $url;
-	global $ftp_conn, $root_directory, $big_url, $ns, $id, $cnt, $off;
-	global $buildlogs_server, $local, $qa_addr, $log;
-
-	$f = file_name();
-
-	if ($f == false)
-		return;
-
-	$df = preg_replace("/.*\/([^\/]*)$/", "\\1", $f);
-	$df = preg_replace("/\.(bz2|gz)$/", "", $df);
-
-	echo "<h1>$df</h1>";
-
-	echo "<table border=\"0\" cellpadding=\"3\" cellspacing=\"1\" bgcolor=\"#000000\">";
-
-	function one_item($h, $t) {
-		echo "<tr><td bgcolor=\"#ccccff\">$h:</td>".
-		         "<td bgcolor=\"#cccccc\">$t</td></tr>";
-	}
-
-	function href($h, $c) {
-		return "<a href=\"$h\">$c</a>";
-	}
-
-	one_item(_("Status"), ($ok == 1 ?  
-				"<font color=\"green\"><b>"._("OK")."</b></font>" : 
-				"<font color=\"red\"><b>"._("Failed")."</b></a>"));
-	one_item(_("Source URL"), 
-		 href("ftp://$buildlogs_server/$f", 
-		      "ftp://$buildlogs_server/$f"));
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-	$bu = "$big_url&off=$off";
-
-	one_item(_("text/plain URL"), 
-	         href(isset($log) ? "$url?log=$log&action=text" : "$bu&id=$id&action=text",
-		      _("View!")));
-	if ($tail) {
-		one_item(_("full text"), 
-	        	 href(isset($log) ? "$url?log=$log" : "$bu&id=$id",
-			      _("View!")));
-	}
-
-	if ($qa_addr[$idx] != "") {
-		one_item(_("rpm -qa of builder"), href("$bu&action=qa", _("View!")));
-	} else {
-		one_item(_("rpm -qa of builder"), _("Not available"));
-        }
-	if ($local) {
-		one_item("Data", date("Y/m/d H:i:s", filemtime("$root_directory/$f")));
-	} else {
-		one_item("Data", date("Y/m/d H:i:s", ftp_mdtm($ftp_conn, $f)));
-	}
-	/*
-	echo "<tr><td>Here:</td><td>" . 
-		"<a href=\"$url?idx=$idx&ok=$ok&id=$id\">".
-		"http://" . getenv("SERVER_NAME") .
-		getenv("SCRIPT_NAME") . "?idx=$idx&ok=$ok&id=$id</a>" .
-	     "</td></tr>"; */
-
-	echo "</table><h2>"._("Content:")."</h2>";
-
-	if ($local == 0) {
-		ftp_quit($ftp_conn);
-		$ftp_conn = 0;
-	}
-
-
-	# what can I say beside PHP suxx? how the fuck should I create
-	# bidirectional pipe? gotta use wget
-
-	if (preg_match("/\.bz2$/", $f)) {
-		$filter = "bzcat";
-	} elseif (preg_match("/\.gz$/", $f)) {
-		$filter = "zcat";
-	} else {
-		$filter = "cat";
-	}
-
-	if ($local) {
-		$cmd = "$filter $root_directory/$f";
-	} else {
-		$cmd = "wget -q -O - ftp://$buildlogs_server$f 2>&1 | $filter 2>&1";
-	}
-	if ($tail)
-		$cmd = "$cmd | tail -n 100";
-	$fd = popen($cmd, "r");
-	start_pre();
-	while (($s = fgets($fd, 102400)) != false) {
-		if (strlen($s) > 800) {
-			$s = chunk_split($s, 800, "\n    ");
-			$s = trim($s);
-		}
-		$s = htmlspecialchars($s);
-		echo $s;
-	}
-	end_pre();
-	pclose($fd);
-
-?>
-	<table width="100%">
-	 <tr>
-	  <td align=left>
-	   [<a href="<?php echo $bu; ?>"><?=_("Back to list of logs")?></a>]
-	  </td>
-	  <td align=right>
-	   [<a href="<?php echo "$bu&action=qa" 
-	   	?>"><?=_("View rpm -qa of builder")?></a>]
-	  </td>
-	 </tr>
-	</table>
-<?php
-
-}
-
-function dump_text()
-{
-	global $ftp_conn, $root_directory;
-	global $buildlogs_server, $local;
-
-	header("Content-type: text/plain");
-
-	$f = file_name();
-	if ($f == false)
-		return;
-
-	echo "# src  : ftp://$buildlogs_server/$f\n";
-	if ($local) {
-		echo "# date   : " .  
-			date("Y/m/d H:i:s", filemtime("$root_directory/$f")) . "\n";
-	} else {
-		echo "# date   : " .  
-			date("Y/m/d H:i:s", ftp_mdtm($ftp_conn, $f)) . "\n";
-		ftp_quit($ftp_conn);
-		$ftp_conn = 0;
-	}
-
-	if (preg_match("/\.bz2$/", $f)) {
-		$filter = "bzcat";
-	} elseif (preg_match("/\.gz$/", $f)) {
-		$filter = "zcat";
-	} else {
-		$filter = "cat";
-	}
-
-	if ($local) {
-		$cmd = "$filter $root_directory/$f";
-	} else {
-		$cmd = "wget -q -O - ftp://$buildlogs_server$f 2>&1 | $filter 2>&1";
-	}
-	$fd = popen($cmd, "r");
-	while (($s = fgets($fd, 1000)) != false) {
-		echo $s;
-	}
-	pclose($fd);
-}
-
-function list_archs()
-{
-	global $addr, $url, $idx, $cnt,$ok,$ns;
-
-	if (!isset($cnt))
-		$cnt = 50;
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	echo "<table width=\"100%\" border=\"0\">\n";
-	echo "<tr><td bgcolor=\"#cccccc\" nowrap=\"nowrap\">"._("Failed")."</td><td bgcolor=\"#cccccc\">"._("Ok")."</td></tr>\n";
-	for ($i = 1; $i < count($addr); $i++)
-		echo "<tr><td nowrap=\"nowrap\">".
-		     "<a href=\"$url?idx=$i&ok=0&cnt=$cnt\">$addr[$i]</a></td><td nowrap=\"nowrap\">".
-		     "[<a href=\"$url?idx=$i&ok=1&cnt=$cnt\">OK</a>]</td>".
-		     #"<td>[<a href=\"$url?idx=$i&action=qa\">qa</a>]</td>".
-		     "</tr>\n";
-	echo "</table><hr />\n";
-	
-	echo "<div align=\"center\">";
-	echo "<a href=\"$big_url&action=adv_search\">"._("Advanced Search")."</a><br />\n";
-	
-	echo "<a href=\"$url\">main()</a><hr />\n";
-	echo "<a href=\"http://www.pld-linux.org/\"><img src=\"powpld.png\" ".
-		"alt=\""._("Powered by PLD Linux")."\" border=\"0\" /></a><br />\n" .
-	     "<small>(c) 2002 ".
-	     "<a href=\"mailto:feedback at pld-linux.org\">PLD Team</a><br />\n".
-	     '$Revision: 1.6 $'.
-	     "</small></div>\n";
-
-	# smile ;)
-	echo "<div align=\"center\"><small>";
-	$pow = array("vim", "php", "brain", "power", "electricity",
-		     "coffee", "ufo", "penguin", "GNOME", "ELF", "DWARF",
-		     "voodoo magic", "Linux", "x-files", "X", "foobar",
-		     "/dev/null", "/dev/zero", "/dev/drzewo", 
-		     "Leppe'", "matrix", "Neo", "PDP-11",
-		     "Ken", "GNU antilope", "PDP-7", "ITS", "Multics",
-		     "foobarbaz", "ed", "Joe", "Unix conspiracy", 
-		     "overclock", "The Right Thing",
-		     "The Bad Thing", "Star Treck", "NSA", "NASA",
-		     "achelon", "VAX", "Real Programmer",
-		     "Real Operating System", "Real Computer",
-		     "computron", "bogon", "quantum bogodynamics",
-		     "BOFH", "/dev/ill", "nasi tu byli",
-		     "Paranoid Android", "Lunatic Corp", "Parallel thinking",
-		     "sfistak", "Linus", "The Golden Path", "Dark Side of the Force",
-		     "Przewodniczacego Lepper-a", "KDE", "Microsoft Windows 2003", "sqlite3"
-		     # feel free to add sth if you change this file ;)
-		     );
-	echo _("Powered by")." ";
-	$max = 1;
-	for ($i = 0; $i < $max; $i++) {
-		$x = rand(0, count($pow) - 1);
-		if ($pow[$x] == "") $i--;
-		else echo $pow[$x] . ($i == $max - 1 ? "." : ", ");
-		$pow[$x] = "";
-	}
-	echo "</small></div>";
-
-	global $qa_addr;
-
-	if (isset($qa_addr[$idx]) && $qa_addr[$idx] != "") {
-	echo "<form action=\"index.php\" method=\"post\">";
-	echo "<input type=\"hidden\" name=\"idx\" value=\"$idx\" />";
-	echo "<input type=\"hidden\" name=\"action\" value=\"sqa\" />";
-	echo "<input type=\"text\" size=\"14\" name=\"str\" /><br />";
-	echo "<input type=\"submit\" name=\"submit\" value=\""._("Search rpmqa!")."\" />";
-	echo "</form>";
-	}
-}
-
-function get_qa()
-{
-	global $idx, $qa_addr;
-
-	if (!isset($idx) || !isset($qa_addr[$idx]))
-		return false;
-
-	$a = $qa_addr[$idx];
-
-	if ($qa_addr[$idx] == "")
-		return false;
-	else
-		return fopen("$qa_addr[$idx]", "r");
-}
-
-function search_qa()
-{
-	global $url, $idx, $qa_addr, $str;
-
-	$f = get_qa();
-	echo "<h1>"._("Search results for")." '$str' "._("in")." $qa_addr[$idx]</h1>";
-
-	start_pre();
-
-	if ($f == 0) {
-	 	echo _("Sorry, cannot open.");
-	} else {
-		while (($s = fgets($f, 1000)) != false) {
-			if (stristr($s, $str))
-				echo $s;
-		}
-		echo "/* EOF */";
-	}
-	end_pre();
-}
-
-function dump_qa($plain)
-{
-	global $url, $idx, $qa_addr;
-
-	$a = $qa_addr[$idx];
-
-	$f = get_qa();
-
-	if ($plain) {
-		header("Content-type: text/plain"); 
-		echo _("# rpm -qa of")." $a\n";
-	} else {
-		echo "<h1>"._("rpm -qa of")." $a</h1>";
-		echo "<a href=\"$url?idx=$idx&action=qatxt\">"._("text/plain version")."</a>";
-		start_pre();
-	}
-
-	if ($f == 0) {
-	 	echo _("Sorry, cannot open.");
-	} else {
-		while (($s = fgets($f, 1000)) != false) {
-			echo $s;
-		}
-	}
-
-	if (!$plain)
-		end_pre();
-}
-
-
-function adv_search()
-{
-  global $database, $addr, $fail_or_ok, $url, $local, $_POST, $off, $cnt, $root_directory, $idx, $ok, $ns;
-
-  $big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-  echo "<script><!--\n".
-       "function checkboxToggle() {\n".
-       "for (var i=0;i<document.forms[0].elements.length;i++) {\n".
-       "var e = document.forms[0].elements[i];\n".
-       "if ((e.name != 'all') && (e.type=='checkbox'))\n".
-       "e.checked = document.forms[0].all.checked;\n".
-       "}\n }\n -->\n </script>\n";
-
-/* Shut up warnings */
-  if (!isset($_POST["name"])) $_POST["name"] = "";
-  if (!isset($_POST["age1"])) $_POST["age1"] = "";
-  if (!isset($_POST["age2"])) $_POST["age2"] = "";
-  if (!isset($_POST["size1"])) $_POST["size1"] = "";
-  if (!isset($_POST["size2"])) $_POST["size2"] = "";
-
-  echo "<form action=\"index.php?action=adv_search\" method=\"post\">";
-
-  echo "<div align=\"center\">";
-  echo "<table border=\"0\">\n";
-  echo "<tr>\n";
-  echo "<td>"._("Package name")."</td>\n";
-  echo "<td><input type=\"text\" size=\"20\" name=\"name\" value=\"". $_POST["name"] ."\"/></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Days")."</td>\n";
-  echo "<td>"._("From").": <input type=\"text\" size=\"20\" name=\"age1\" value=\"". $_POST["age1"] ."\" /></td>\n";
-  echo "<td>"._("To").": <input type=\"text\" size=\"20\" name=\"age2\" value=\"". $_POST["age2"] ."\" /></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Size")."</td>\n";
-  echo "<td>"._("From").": <input type=\"text\" size=\"20\" name=\"size1\" value=\"". $_POST["size1"] ."\" /></td>\n";
-  echo "<td>"._("To").": <input type=\"text\" size=\"20\" name=\"size2\" value=\"". $_POST["size2"] ."\" /></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Search logs:")."</td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Failed")."</td>\n";
-  echo "<td>"._("OK")."</td>\n";
-  echo "</tr>\n";
-
-  for ($i = 1; $i < count($addr); $i++)
-  {
-    echo "<tr>\n";
-    $name="as0_".$i;
-    if (!isset($_POST["$name"])) {
-    	$check = " ";
-    } else {
-    	$check=" checked=\"on\"";
-    }
-    echo "<td><input name=\"$name\" id=\"$name\" type=\"checkbox\"$check /><label for=\"$name\">".$addr[$i]."</label></td>\n";
-    $name="as1_".$i;
-    if (!isset($_POST["$name"])) {
-    	$check = " ";
-    } else {
-    	$check=" checked=\"on\"";
-    }
-    echo "<td><input name=\"$name\" id=\"$name\" type=\"checkbox\"$check /><label for=\"$name\">".$addr[$i]."</label></td>\n";
-    echo "</tr>\n";
-  }
-	
-  echo "<tr>\n";
-  echo "<td><input name=\"all\" type=\"checkbox\" checked=\"on\" onClick=\"checkboxToggle()\">"._("Toggle checkboxes")." <input type=\"submit\" name=\"submit\" value=\""._("Search!")."\" /></td>";
-  echo "</tr>\n";
-
-  echo "</table>\n";
-
-//	if (isset($_POST["name"]) || isset($_POST["age1"]) || isset($_POST["age2"]) ||
-//	  isset($_POST["size1"]) || isset($_POST["size2"])
-  if (($_POST["name"]!="") || ($_POST["age1"]!="") || ($_POST["age2"]!="") ||
-    ($_POST["size1"]!="") || ($_POST["size2"]!=""))
-  {
-	$query = "SELECT spec, mtime, arch_id, result, log_id, size FROM logs WHERE 1 ";
-	if ($_POST["name"] != "") {
-		$n = addslashes($_POST["name"]);
-		$query .= "AND spec LIKE '$n%' ";
-	}
-	$now = time();
-
-	if ($_POST["age1"] != "") {
-		$age = $now - (int)$_POST["age1"] * 24 * 3600;
-		$query .= "AND mtime > $age ";
-	}
-
-	if ($_POST["age2"] != "") {
-		$age = $now - (int)$_POST["age2"] * 24 * 3600;
-		$query .= "AND mtime < $age ";
-	}
-
-	if ($_POST["size1"] != "") {
-		$size = (int)$_POST["size1"];
-		$query .= "AND size > $size ";
-	}
-
-	if ($_POST["size2"] != "") {
-		$size = (int)$_POST["size2"];
-		$query .= "AND size < $size ";
-	}
-
-	$or = "AND (";
-	for ($i = 1; $i < count($addr); $i++) {
-		for ($j = 0; $j < 2; $j++) {
-			if (isset($_POST["as" . $j . "_" .$i])) {
-				$query .= "$or (arch_id = $i AND result = $j)";
-				$or = " OR ";
-			}
-		}
-	}
-	if ($or == " OR ") $query .= ")";
-//	if (!isset($cnt)) $cnt = 50;
-//	if (!isset($off)) $off = 0;
-	if (!isset($ns)) $ns = 0;
-	switch ($ns) {
-		case 0:
-			$query .= " ORDER BY mtime DESC";
-			break;
-		case 1:
-			$query .= " ORDER BY spec";
-			break;
-		case 2:
-			$query .= " ORDER BY arch_id, spec";
-			break;
-	}
-	$query .= " LIMIT $cnt OFFSET $off ";
-
-	try {
-		$dbh = new PDO("$database");
-	} catch (PDOException $e) {
-		mydie("new PDO: " . $e->getMessage());
-	}
-	$result = $dbh->query("$query")->fetchAll();
-
-	if ($result == FALSE) {
-		echo _("Nothing found");
-	} else {
-		echo "<table border=\"0\" cellspacing=\"1\" ".
-			"cellpadding=3 bgcolor=\"#000000\" width=\"90%\">\n";
-		echo "<tr><th bgcolor=\"#CCCCFF\" align=\"left\" width=\"10%\">"._("Builder").
-	     		"[<a href=\"$big_url&ns=2\">"._("sort")."</a>]</th>";
-		echo "<th bgcolor=\"#CCCCFF\" align=\"left\" width=\"60%\">"._("Log File").
-			"[<a href=\"$big_url&ns=1\">"._("sort")."</a>]</th>".
-	         	"<th bgcolor=\"#CCCCFF\" align=\"right\" width=\"15%\">"._("Size")."</th> ".
-			 "<th bgcolor=\"#CCCCFF\" align=\"left\">"._("Age").
-			 "[<a href=\"$big_url&ns=0\">"._("sort")."</a>]</th>".
-			 "</th></tr>";
-		$i = $off;
-//		for ($i = $off; $i < $off + $count; $i++) {
-		foreach ($result as $row) {
-			$f = $row["spec"];
-			$t = $now - $row["mtime"];
-			$s = $row["size"];
-			$t /= 60;
-			if ($t >= 60) {
-				$t /= 60;
-				if ($t >= 24) {
-					$t /= 24;
-					$t = round($t);
-					$t = $t . " " . ngettext("day","days",$t);
-				} else {
-					$t = round($t);
-					$t = $t . " " . ngettext("hour","hours",$t);
-				}
-			} else {
-				$t = round($t);
-				$t = $t . " " . ngettext("minute","minutes",$t);
-			}
-			
-//                $big_url = "$url?idx=$i&ok=$j&ns=$ns&cnt=$cnt";
-			$h = $row["log_id"];
-			$u = "$url?log=$h";
-			$arch_id = $row["arch_id"];
-			$ok = $row["result"];
-			$b = "$url?idx=$arch_id&ok=$ok&ns=$ns&off=$off&cnt=$cnt";
-
-			$builder = $addr[$arch_id]."/". $fail_or_ok[$ok];
-			echo "<tr>";
-			echo "<td bgcolor=\"#CCCCCC\"><a href=\"$b\">$builder</a></td>";
-			echo "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">$f</a> ".
-		     	"[<a href=\"$u&action=text\">"._("text")."</a> | ".
-		      	"<a href=\"$u&action=tail\">"._("tail")."</a>]".
-		     	"</td><td bgcolor=\"#CCCCCC\" align=\"right\">".
-		     	"$s</td><td bgcolor=\"#CCCCCC\">$t</td></tr>\n";
-		     	$i++;
-		}
-		echo "</table></div>\n";
-
-		$backarr = "<<< ";
-		$back = _("Page back");
-		$forward = _("Page forward");
-		$forwardarr = " >>>";
-
-	}
-// FIXME
-/*
-	echo "<p><table width=\"90%\" align=\"center\"><tr><td align=left width=1%>";
-
-	if ($off > 0) {
-		$noff = $off - $cnt;
-		if ($noff < 0)	
-			$noff = 0;
-		$hrefurl = "<a href=\"$big_url&off=$noff\">";
-		echo "$hrefurl$backarr</a></td><td align=left>$hrefurl$back</a>";
-	} else {
-		echo "$backarr</td><td align=left>$back";
-	}
-
-    echo "</td>\n<td align=\"center\">";
-    echo "</td>\n<td align=\"right\">";
-
-    if ($off + $cnt < count($list))
-    {
-      $noff = $off + $cnt;
-      if ($noff < 0)	
-        $noff = 0;
-      $hrefurl = "<a href=\"$big_url&off=$noff\">";
-      echo "$hrefurl$forward</a></td><td align=\"right\" width=\"1%\">$hrefurl$forwardarr</a>";
-    }
-    else
-    {
-      echo "$forward</td><td align=\"right\" width=\"1%\">$forwardarr";
-    }
-
-    echo "</td>\n</tr></table></p>";
-*/
-  } else
-  {
-    echo _("Enter something!");
-  }
-  echo "</form>\n";
-}
-
-function welcome()
-{
-?>
-<table border="0" width="100%"><tr><td width="20%"> </td><td>
-<h1><?=_("Welcome!")?></h1>
-<p><?=_("Welcome to PLD Build Logs WWW interface.")?></p><p>
-<?=_("Feel free to email bug reports, complaints and feature requests ")?>
-<!-- ech... niech strace... -->
-<a href="mailto:feedback at pld-linux.org"><?=_("to us")?></a>. <?=_("Positive opinions are also")?> 
-<a href="mailto:feedback at pld-linux.org"><?=_("welcome")?></a> ;)</p>
-<p>Version: $Id: index.php,v 1.6 2007-11-27 09:12:54 witekfl Exp $</p>
-</td><td width="20%"> </td></tr>
-</table>
-<?php
-}
-
-header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
-header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-header("Cache-Control: no-cache, must-revalidate");
-header("Pragma: no-cache");
-
-//phpinfo();
-if ($local) {
-	if ($action == "text") {
-		dump_text();
-	} else if ($action == "adv_search") {
-		myheader();
-		adv_search();
-		trailer();
-	} else if ($action == "qatxt") {
-		dump_qa(1);
-	} else {
-		myheader();
-		echo "<table cellpadding=\"10\" width=\"100%\"><tr><td valign=\"top\" width=\"10%\">";
-		list_archs();
-		echo "</td><td valign=\"top\">";
-		flush();
-		if ($action == "qa")
-			dump_qa(0);
-		else if ($action == "sqa")
-			search_qa();
-		else if (isset($id) || isset($log) || isset($_GET['name']))
-			dump_log($action == "tail");
-		else if (isset($idx))
-			list_logs();
-		else 
-			welcome();
-		echo "</td></tr></table>";
-		trailer();
-	}
-}
-else {
-
-	if ($action == "text") {
-		dump_text();
-	} else if ($action == "qatxt") {
-		dump_qa(1);
-	} else {
-		myheader();
-		echo "<table cellpadding=\"10\" width=\"100%\"><tr><td valign=top width=\"10%\">";
-		list_archs();
-		echo "</td><td valign=\"top\">";
-		flush();
-		if ($action == "qa")
-			dump_qa(0);
-		else if (isset($id))
-			dump_log($action == "tail");
-		else if (isset($idx))
-			list_logs();
-		else 
-			welcome();
-		echo "</td></tr></table>";
-		trailer();
-	}
-}
-?>
diff --git a/obsolete/buildlogs.sql/init.sql b/obsolete/buildlogs.sql/init.sql
deleted file mode 100644
index 27f6705..0000000
--- a/obsolete/buildlogs.sql/init.sql
+++ /dev/null
@@ -1,82 +0,0 @@
--- MySQL dump 9.11
---
--- Host: localhost    Database: buildlogs
--- ------------------------------------------------------
--- Server version	4.0.22
-
---
--- Table structure for table `architectures`
---
-CREATE DATABASE buildlogs;
-
-USE buildlogs;
-
-
-CREATE TABLE architectures (
-  arch_id tinyint(4) NOT NULL default '0',
-  name varchar(15) default NULL,
-  PRIMARY KEY  (arch_id)
-) TYPE=MyISAM;
-
---
--- Dumping data for table `architectures`
---
-
-INSERT INTO architectures VALUES (0,'th/SRPMS');
-INSERT INTO architectures VALUES (1,'th/i486');
-INSERT INTO architectures VALUES (2,'th/i686');
-INSERT INTO architectures VALUES (3,'th/athlon');
-INSERT INTO architectures VALUES (4,'th/x86_64');
-INSERT INTO architectures VALUES (5,'th/ia64');
-INSERT INTO architectures VALUES (6,'th/alpha');
-INSERT INTO architectures VALUES (7,'th/ppc');
-INSERT INTO architectures VALUES (8,'th/sparc');
-INSERT INTO architectures VALUES (9,'ac/SRPMS');
-INSERT INTO architectures VALUES (10,'ac/i386');
-INSERT INTO architectures VALUES (11,'ac/i586');
-INSERT INTO architectures VALUES (12,'ac/i686');
-INSERT INTO architectures VALUES (13,'ac/athlon');
-INSERT INTO architectures VALUES (14,'ac/amd64');
-INSERT INTO architectures VALUES (15,'ac/alpha');
-INSERT INTO architectures VALUES (16,'ac/ppc');
-INSERT INTO architectures VALUES (17,'ac/sparc');
-INSERT INTO architectures VALUES (18,'ac/sparc64');
-
-
--- Table structure for table `logs`
---
-
-CREATE TABLE logs (
-  log_id int(11) NOT NULL auto_increment,
-  arch_id tinyint(4) default NULL,
-  result tinyint(4) default NULL,
-  size int(11) default NULL,
-  spec_id smallint(6) default NULL,
-  mtime int(11) default NULL,
-  PRIMARY KEY  (log_id)
-) TYPE=MyISAM;
-
-
-CREATE TABLE result (
-  result_id tinyint(4) NOT NULL default '0',
-  name varchar(5) default NULL,
-  PRIMARY KEY  (result_id)
-) TYPE=MyISAM;
-
---
--- Dumping data for table `result`
---
-
-INSERT INTO result VALUES (0,'FAIL');
-INSERT INTO result VALUES (1,'OK');
-
---
--- Table structure for table `specs`
---
-
-CREATE TABLE specs (
-  spec_id smallint(6) NOT NULL auto_increment,
-  spec varchar(70) default NULL,
-  PRIMARY KEY  (spec_id)
-) TYPE=MyISAM;
-
diff --git a/obsolete/buildlogs.sql/migration.php b/obsolete/buildlogs.sql/migration.php
deleted file mode 100644
index e308ef2..0000000
--- a/obsolete/buildlogs.sql/migration.php
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/php.cli
-<?php
-// $Revision: 1.6 $, $Date: 2007/12/02 15:49:42 $
-/*
-$root_directory = '/home/services/ftp/pub/pld-buildlogs';
-$database = 'sqlite:/home/services/httpd/html/pld-buildlogs/db/buildlogs.db';
-// $root_directory and $database are taken from buildlogs.inc
-$reverse_addr = array(
-	"th/SRPMS" => 1,
-	"th/i486" => 2,
-	"th/i686" => 3,
-	"th/athlon" => 4,
-	"th/x86_64" => 5,
-	"th/ia64" => 6,
-	"th/alpha" => 7,
-	"th/ppc" => 8,
-	"th/sparc" => 9,
-	"ac/SRPMS" => 10,
-	"ac/i386" => 11,
-	"ac/i586" => 12,
-	"ac/i686" => 13,
-	"ac/athlon" => 14,
-	"ac/amd64" => 15,
-	"ac/alpha" => 16,
-	"ac/ppc" => 17,
-	"ac/sparc" => 18,
-	"ac/sparc64" => 19
-);
- */
-
-$me = $argv[0];
-
-require('buildlogs.inc');
-
-if (file_exists($database_file)) {
-	unlink($database_file);
-}
-
-$query = " CREATE TABLE LOGS(log_id INTEGER PRIMARY KEY, arch_id INTEGER, result INTEGER, size INTEGER, mtime INTEGER, spec TEXT);";
-try {
-	$dbhandle = new PDO("$database");
-} catch (PDOException $e) {
-	die("$me: new PDO: ". $e->getMessage());
-}
-
-foreach ($addr as $key=>$val) {
-	if ($key == 0)
-		continue;
-	foreach (array(0=>"FAIL", 1=>"OK") as $rkey=>$rval) {
-		$dir = "$root_directory/" . $val . "/" . $rval;
-		$dh = opendir($dir);
-		if (!$dh) {
-			echo "$me: $dir: can't open directory\n";
-			continue;
-		}
-		while ($file = readdir($dh)) {
-			if (preg_match("/^(.*)\.bz2$/", $file, $match)) {
-				$f = "$dir/$file";
-				$size = filesize($f);
-				$mtime = filemtime($f);
-				$spec = $match[1];
-				echo "$me: Doing: $spec, $mtime, $size...\n";
-				$query .= " INSERT INTO logs(arch_id, result, size, mtime, spec) VALUES($key, $rkey, $size, $mtime, '$spec');";
-			}
-		}
-		closedir($dh);
-	}
-}
-
-$dbhandle->beginTransaction();
-$dbhandle->exec("$query");
-$dbhandle->commit();
-?>
diff --git a/obsolete/buildlogs/index.php b/obsolete/buildlogs/index.php
deleted file mode 100644
index 41534bd..0000000
--- a/obsolete/buildlogs/index.php
+++ /dev/null
@@ -1,1071 +0,0 @@
-<?php
-ob_start("ob_gzhandler");
-
-$buildlogs_server = "buildlogs.pld-linux.org";
-$url = "index.php";
-$addr = array(
-	"/th/SRPMS",
-	"/th/i486",
-	"/th/i686",
-	"/th/athlon",
-	"/th/x86_64",
-	"/th/ia64",
-	"/th/alpha",	
-	"/th/ppc",
-	"/th/sparc",
-	"/ac/SRPMS",
-	"/ac/i386",
-	"/ac/i586",
-	"/ac/i686",
-	"/ac/athlon",
-	"/ac/amd64",
-	"/ac/alpha",	
-	"/ac/ppc",
-	"/ac/sparc",
-	"/ac/sparc64"/*,
-	"/ra/i386",
-	"/ra/i586",
-	"/ra/i686",
-	"/ra/alpha",	
-	"/ra/ppc",
-	"/ra/sparc",
-	"/nest/i486",
-	"/nest/i686",
-	"/nest/alpha",
-	"/nest/ppc"
-*/
-);
-$qa_addr = array(
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-SRPMS.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-i486.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-i686.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-athlon.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-x86_64.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-ia64.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-alpha.txt",	
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-ppc.txt",
-	"http://ftp.pld-linux.org/dists/th/.stat/builder/th/rpmqa-sparc.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-SRPMS.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i386.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i586.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-i686.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-athlon.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-amd64.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-alpha.txt",	
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-ppc.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-sparc.txt",
-	"http://ftp.pld-linux.org/dists/ac/.stat/builder/ac/rpmqa-sparc64.txt"/*,
-	"http://ftp.pld-linux.org/dists/ra/.stat/builder/liniowiec/rpmqa-ra-i386.txt",
-	"http://ftp.pld-linux.org/dists/ra/.stat/builder/liniowiec/rpmqa-ra-i586.txt",
-	"http://ftp.pld-linux.org/dists/ra/.stat/builder/liniowiec/rpmqa-ra-i686.txt",
-	"http://ftp.pld-linux.org/dists/ra/.stat/builder/fly/rpmqa-ra-alpha.txt",	
-	"http://ftp.pld-linux.org/dists/ra/.stat/builder/an2/rpmqa-ra-ppc.txt",
-	"http://ftp.pld-linux.org/dists/ra/.stat/builder/ares/rpmqa-ra-sparc.txt",
-	"http://ftp.nest.pld-linux.org/.stat/builder/kenny/rpmqa-nest-i486.txt",
-	"http://ftp.nest.pld-linux.org/.stat/builder/kenny/rpmqa-nest-i686.txt",
-	"http://ftp.nest.pld-linux.org/.stat/builder/alpha/rpmqa-nest-alpha.txt",
-	"http://ftp.nest.pld-linux.org/.stat/builder/an2/rpmqa-nest-ppc.txt"
-*/
-);
-$local = 1; /* $local=0 for FTP */ 
-$root_directory = "/home/services/ftp/pub/pld-buildlogs";
-$ftp_conn = 0;
-/* It should be set */
-
-$langs["en_US"]["charset"]="ISO-8859-1";
-$langs["pl_PL"]["charset"]="ISO-8859-2";
-
-$lang="en_US";
-if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
-{
-  $rows=explode(";",$_SERVER["HTTP_ACCEPT_LANGUAGE"]);
-  $rows=explode(",",$rows[0]);
-  $lang_detected=rtrim($rows[0]);
-} else if (preg_match("/opera/i",$_SERVER["HTTP_USER_AGENT"]))
-{
-  $lang_detected=preg_replace("/.*\[(.*)\].*/i","\\1",$_SERVER["HTTP_USER_AGENT"]);
-}
-
-// FIXME - some array
-$lang_detected=preg_replace("/^pl$/i","pl_PL",$lang_detected);
-
-if (isset($lang_detected) && isset($langs[$lang_detected]))
-{
-  $lang=$lang_detected;
-}
-
-if (isset($_GET["lang"]))$_SESSION["lang"]=$_GET["lang"];
-if (isset($_SESSION["lang"]))$lang=$_SESSION["lang"];
-
-putenv("LANG=$lang");
-setlocale(LC_ALL,$lang);
-bindtextdomain("messages","locale");
-textdomain("messages");
-
-if (isset($_GET["idx"]))$idx=$_GET["idx"];
-if (isset($_GET["dist"]))
-{
-	$dist=$_GET["dist"];
-	if (isset($_GET["arch"]))
-	{
-		$arch=$_GET["arch"];
-		for ($i = 0; $i < count($addr); $i++)
-		{
-			if ($addr[$i]=="/".$dist."/".$arch)
-				$idx=$i;
-		}
-	}
-}
-if (isset($_GET["ok"]))$ok=$_GET["ok"];
-else $ok="";
-if (isset($_GET["ns"]))$ns=$_GET["ns"];
-else $ns="";
-if (isset($_GET["cnt"]))$cnt=$_GET["cnt"];
-if (isset($_GET["action"]))$action=$_GET["action"];
-else $action="";
-if (isset($_GET["off"]))$off=$_GET["off"];
-if (isset($_GET["id"]))$id=$_GET["id"];
-
-if (isset($_POST["str"]))$str=$_POST["str"];
-if (isset($_POST["idx"]))$idx=$_POST["idx"];
-if (isset($_POST["action"]))$action=$_POST["action"];
-
-function myheader()
-{
-echo '<' . '?xml version="1.0" encoding="' . _("ISO-8859-1") .'"?' . ">\n";
-echo '<' . '?xml-stylesheet href="#internalStyle" type="text/css"?' . ">\n";
-?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
-  <title>PLD Build Logs</title>
-  <?php echo '<meta http-equiv="Content-type" content="text/html; charset=' . _("ISO-8859-1") .'"/>' ."\n";?>
-  <style type="text/css"><!--
-A { text-decoration: none; }
-A:hover { text-decoration: underline; }
-H1 { font-family: arial,helvetica,sans-serif; 
-     font-size: 20pt; 
-     font-weight: bold;}
-H2 { font-family: arial,helvetica,sans-serif; 
-     font-size: 18pt; 
-     font-weight: bold;}
-BODY,TD { font-family: arial,helvetica,sans-serif; 
-          font-size: 13pt; }
-TH { font-family: arial,helvetica,sans-serif; 
-     font-size: 13pt; 
-     font-weight: bold; }
-//-->
-</style>
- </head>
- <!-- Diffrent color for visited link doesn't make much sense here...
-      this page is autogenerated and it might be misleading after some
-      build log changes. -->
- <body bgcolor="#ffffff" text="#000000" link="#5f26cd" vlink="#5f26cd">
-<?php
-}
-
-function start_pre()
-{
-	echo "<table cellpadding=\"10\"><tr><td bgcolor=\"#000000\">".
-		"<font color=\"#cccccc\"><pre style=\"width: 2048px;overflow: scroll\">";
-}
-
-function end_pre()
-{
-	echo "</pre></font></td></tr></table>\n";
-}
-
-function trailer()
-{
-	echo "</body></html>";
-}
-
-
-function mydie($msg)
-{
-	echo "Fatal error: $msg";
-}
-
-function open_ftp($pidx="", $pok="")
-{
-	global $idx, $addr, $buildlogs_server, $ok;
-	global $ftp_conn, $big_url, $url, $ns;
-	global $off, $cnt;
-	
-	if ($pidx==="")$pidx=$idx;
-	if ($pok==="")$pok=$ok;
-
-	if (!isset($pidx) || !isset($addr[$pidx]))
-		return false;
-
-	if ($pok != 1)
-		$pok = 0;
-	if ($ns != 1)
-		$ns = 0;
-
-	if ($pok == 1) {
-		$a = "$addr[$pidx]/OK";
-	} else {
-		$a = "$addr[$pidx]/FAIL";
-	}
-
-	if (!isset($off))
-		$off = 0;
-	if (!isset($cnt))
-		$cnt = 16;
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	$ftp = ftp_connect($buildlogs_server);
-
-	if ($ftp == false) {
-		mydie(_("cannot connect to")." $buildlogs_server");
-		return false;
-	}
-
-	if (ftp_login($ftp, "anonymous", 
-		      "buildlogs-iface at pld-linux.org") == false) {
-		ftp_quit($ftp);
-		mydie(_("cannot ftp login to")." $buildlogs_server");
-		return false;
-	}
-
-	$list = ftp_nlist($ftp, $a);
-	if ($list == false) {
-		ftp_quit($ftp);
-		mydie(_("cannot list")." $a");
-		return false;
-	}
-
-	$ftp_conn = $ftp;
-
-	return $list;
-}
-
-function directory_list($pidx="",$pok="")
-{
-	global $idx, $addr, $buildlogs_server, $ok;
-	global $root_directory, $big_url, $url, $ns;
-	global $off, $cnt;
-
-	if ($pidx==="")$pidx=$idx;
-	if ($pok==="")$pok=$ok;
-	if (!isset($pidx) || !isset($addr[$pidx]))
-		return false;
-
-	if ($pok != 1)
-		$pok = 0;
-	if ($ns != 1)
-		$ns = 0;
-
-	if ($pok == 1) {
-		$a = "$addr[$pidx]/OK";
-	} else {
-		$a = "$addr[$pidx]/FAIL";
-	}
-
-	if (!isset($off))
-		$off = 0;
-	if (!isset($cnt))
-		$cnt = 16;
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	$dir = opendir("$root_directory$a");
-	$i = 0;
-	$list = array ();
-	while ($file = readdir($dir)) {
-		if (($file != ".") && ($file != "..")) {
-			$list[$i] = array("$a/$file", filemtime("$root_directory$a/$file"));
-			$i++;
-		}
-	}
-	closedir($dir);
-	return $list;
-}
-
-function list_logs()
-{
-	global $idx, $addr, $ok;
-	global $ftp_conn, $big_url, $ns, $qa_addr;
-	global $off, $cnt, $local, $root_directory;
-
-	if ($local) {
-		$list = directory_list();
-	} else {
-		$list = open_ftp();
-	}
-	if ($list == false)
-		return;
-
-	if ($ok == 1) {
-		echo "<h1>"._("Listing of")." $addr[$idx]/OK "
-			."(<a href=\"$big_url&ok=0\">"._("fail")."</a>)</h1>\n";
-	} else {
-		echo "<h1>"._("Listing of")." $addr[$idx]/FAIL "
-			."(<a href=\"$big_url&ok=1\">"._("ok")."</a>)</h1>\n";
-	}
-
-	echo "<div align=\"center\"><table cols=\"4\" border=\"0\" cellspacing=\"1\" ".
-		"cellpadding=\"3\" bgcolor=\"#000000\" width=\"90%\">\n";
-	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"right\" width=\"1%\">"._("No.")."</th>".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\" width=\"80%\">"._("Log File").
-			"[<a href=\"$big_url&ns=1\">"._("sort")."</a>]</th>".
-		 "<th bgcolor=\"#CCCCFF\" align=\"right\" width=\"15%\">"._("Size")."</th> ".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\">"._("Age").
-			 "[<a href=\"$big_url&ns=0\">"._("sort")."</a>]</th>".
-		 "</tr>";
-
-	function cmp($f1, $f2) {
-		global $ftp_conn, $root_directory, $local;
-		if ($local)
-			return $f2[1] - $f1[1];//filemtime("$root_directory$f2") - filemtime("$root_directory$f1");
-		return ftp_mdtm($ftp_conn, $f2) - ftp_mdtm($ftp_conn, $f1);
-	}
-
-	function cmp2($f1, $f2) {
-		return strcmp($f1[0], $f2[0]);
-	}
-
-	if ($ns != 1) {
-		$ns = 0;
-		usort($list, "cmp");
-	} else {
-		usort($list, "cmp2");
-	}
-
-	$now = time();
-	for ($i = $off; $i < $cnt + $off; $i++) {
-		$filename = $list[$i][0];
-		if (!isset($filename))
-			continue;
-		$h = bin2hex(mhash(MHASH_MD5, $filename));
-		$f = preg_replace("/.*\/([^\/]*)$/", "\\1", $filename);
-		$f = preg_replace("/\.(bz2|gz)$/", "", $f);
-		if ($local) {
-			$s = filesize("$root_directory$filename");
-			$t = $now - $list[$i][1];
-		} else {
-			$s = ftp_size($ftp_conn, $list[$i]);
-			$t = $now - ftp_mdtm($ftp_conn, $list[$i]);
-		}
-		$t /= 60;
-		if ($t >= 60) {
-			$t /= 60;
-			if ($t >= 24) {
-				$t /= 24;
-				$t = round($t);
-				$t = $t . " " . ngettext("day","days",$t);
-			} else {
-				$t = round($t);
-				$t = $t . " " . ngettext("hour","hours",$t);
-			}
-		} else {
-			$t = round($t);
-			$t = $t . " " . ngettext("minute","minutes",$t);
-		}
-		$u = "$big_url&off=$off&id=$h";
-		echo "<tr><td bgcolor=\"#CCCCCC\" align=\"right\">".($i+1).".</td>".
-		     "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">$f</a> ".
-		     "[<a href=\"$u&action=text\">"._("text")."</a> | ".
-		      "<a href=\"$u&action=tail\">"._("tail")."</a>]".
-		     "</td><td bgcolor=\"#CCCCCC\" align=\"right\">".
-		     "$s</td><td bgcolor=\"#CCCCCC\">$t</td></tr>\n";
-	}
-	echo "</table></div>\n";
-
-	$backarr = "<<< ";
-	$back = _("Page back");
-	$forward = _("Page forward");
-	$forwardarr = " >>>";
-
-	echo "<p><table width=\"90%\" align=\"center\"><tr><td align=\"left\" width=\"1%\">";
-
-	if ($off > 0) {
-		$noff = $off - $cnt;
-		if ($noff < 0)	
-			$noff = 0;
-		$hrefurl = "<a href=\"$big_url&off=$noff\">";
-		echo "$hrefurl$backarr</a></td><td align=\"left\">$hrefurl$back</a>";
-	} else {
-		echo "$backarr</td><td align=\"left\">$back";
-	}
-
-	echo "</td>\n<td align=\"center\">";
-
-	if ($qa_addr[$idx] != "") {
-		echo "[<a href=\"$big_url&action=qa\">"._("View <quot>rpm -qa</quot> of builder")."</a>]";
-	} else {
-		echo " ";
-	}
-
-	echo "</td>\n<td align=right>";
-	if ($off + $cnt < count($list)) {
-		$noff = $off + $cnt;
-		if ($noff < 0)	
-			$noff = 0;
-		$hrefurl = "<a href=\"$big_url&off=$noff\">";
-		echo "$hrefurl$forward</a></td><td align=right width=1%>$hrefurl$forwardarr</a>";
-	} else {
-		echo "$forward</td><td align=right width=1%>$forwardarr";
-	}
-	echo "</td>\n</tr></table></p>";
-	if ($local == 0) {
-		ftp_quit($ftp_conn);
-		$ftp_conn = 0;
-	}
-}
-
-function file_name()
-{
-	global $idx, $addr, $ok;
-	global $ftp_conn, $root_directory, $big_url, $ns, $id;
-	global $buildlogs_server, $local;
-
-	if (!isset($id))
-		return false;
-	if ($local) {
-		$list = directory_list();
-	} else {
-		$list = open_ftp();
-	}
-	if ($list == false)
-		return false;
-
-	$f = false;
-	for ($i = 0; $i < count($list); $i++) {
-		$h = bin2hex(mhash(MHASH_MD5, $list[$i][0]));
-		if ($h == $id) {
-			$f = $list[$i][0];
-		}
-	}
-
-	if ($f == false) {
-		mydie(_("cannot find specified file:")." $id");
-		if ($local == 0)
-			ftp_quit($ftp_conn);
-		return false;
-	}
-
-	return $f;
-}
-
-function dump_log($tail)
-{
-	global $idx, $addr, $ok, $url;
-	global $ftp_conn, $root_directory, $big_url, $ns, $id, $cnt, $off;
-	global $buildlogs_server, $local, $qa_addr;
-
-	$f = file_name();
-
-	if ($f == false)
-		return;
-
-	$df = preg_replace("/.*\/([^\/]*)$/", "\\1", $f);
-	$df = preg_replace("/\.(bz2|gz)$/", "", $df);
-
-	echo "<h1>$df</h1>";
-
-	echo "<table border=\"0\" cellpadding=\"3\" cellspacing=\"1\" bgcolor=\"#000000\">";
-
-	function one_item($h, $t) {
-		echo "<tr><td bgcolor=\"#ccccff\">$h:</td>".
-		         "<td bgcolor=\"#cccccc\">$t</td></tr>";
-	}
-
-	function href($h, $c) {
-		return "<a href=\"$h\">$c</a>";
-	}
-
-	one_item(_("Status"), ($ok == 1 ?  
-				"<font color=\"green\"><b>"._("OK")."</b></font>" : 
-				"<font color=\"red\"><b>"._("Failed")."</b></a>"));
-	one_item(_("Source URL"), 
-		 href("ftp://$buildlogs_server$f", 
-		      "ftp://$buildlogs_server$f"));
-
-	$bu = "$big_url&off=$off";
-
-	one_item(_("text/plain URL"), 
-	         href("$bu&id=$id&action=text",
-		      _("View!")));
-	if ($tail) {
-		one_item(_("full text"), 
-	        	 href("$bu&id=$id",
-			      "View!"));
-	}
-
-	if ($qa_addr[$idx] != "") {
-		one_item(_("rpm -qa of builder"), href("$bu&action=qa", _("View!")));
-	} else {
-		one_item(_("rpm -qa of builder"), _("Not available"));
-        }
-	if ($local) {
-		one_item("Data", date("Y/m/d H:i:s", filemtime("$root_directory$f")));
-	} else {
-		one_item("Data", date("Y/m/d H:i:s", ftp_mdtm($ftp_conn, $f)));
-	}
-	/*
-	echo "<tr><td>Here:</td><td>" . 
-		"<a href=\"$url?idx=$idx&ok=$ok&id=$id\">".
-		"http://" . getenv("SERVER_NAME") .
-		getenv("SCRIPT_NAME") . "?idx=$idx&ok=$ok&id=$id</a>" .
-	     "</td></tr>"; */
-
-	echo "</table><h2>"._("Content:")."</h2>";
-
-	if ($local == 0) {
-		ftp_quit($ftp_conn);
-		$ftp_conn = 0;
-	}
-
-
-	# what can I say beside PHP suxx? how the fuck should I create
-	# bidirectional pipe? gotta use wget
-
-	if (preg_match("/\.bz2$/", $f)) {
-		$filter = "bzcat";
-	} elseif (preg_match("/\.gz$/", $f)) {
-		$filter = "zcat";
-	} else {
-		$filter = "cat";
-	}
-
-	if ($local) {
-		$cmd = "$filter $root_directory$f";
-	} else {
-		$cmd = "wget -q -O - ftp://$buildlogs_server$f 2>&1 | $filter 2>&1";
-	}
-	if ($tail)
-		$cmd = "$cmd | tail -n 100";
-	$fd = popen($cmd, "r");
-	start_pre();
-	while (($s = fgets($fd, 102400)) != false) {
-		if (strlen($s) > 800) {
-			$s = chunk_split($s, 800, "\n    ");
-			$s = trim($s);
-		}
-		$s = htmlspecialchars($s);
-		echo $s;
-	}
-	end_pre();
-	pclose($fd);
-
-?>
-	<table width="100%">
-	 <tr>
-	  <td align=left>
-	   [<a href="<?php echo $bu; ?>"><?=_("Back to list of logs")?></a>]
-	  </td>
-	  <td align=right>
-	   [<a href="<?php echo "$bu&action=qa" 
-	   	?>"><?=_("View rpm -qa of builder")?></a>]
-	  </td>
-	 </tr>
-	</table>
-<?php
-
-}
-
-function dump_text()
-{
-	global $ftp_conn, $root_directory;
-	global $buildlogs_server, $local;
-
-	header("Content-type: text/plain");
-
-	$f = file_name();
-
-	if ($f == false)
-		return;
-
-	echo "# src  : ftp://$buildlogs_server$f\n";
-	if ($local) {
-		echo "# date   : " .  
-			date("Y/m/d H:i:s", filemtime("$root_directory$f")) . "\n";
-	} else {
-		echo "# date   : " .  
-			date("Y/m/d H:i:s", ftp_mdtm($ftp_conn, $f)) . "\n";
-		ftp_quit($ftp_conn);
-		$ftp_conn = 0;
-	}
-
-	if (preg_match("/\.bz2$/", $f)) {
-		$filter = "bzcat";
-	} elseif (preg_match("/\.gz$/", $f)) {
-		$filter = "zcat";
-	} else {
-		$filter = "cat";
-	}
-
-	if ($local) {
-		$cmd = "$filter $root_directory$f";
-	} else {
-		$cmd = "wget -q -O - ftp://$buildlogs_server$f 2>&1 | $filter 2>&1";
-	}
-	$fd = popen($cmd, "r");
-	while (($s = fgets($fd, 1000)) != false) {
-		echo $s;
-	}
-	pclose($fd);
-}
-
-function list_archs()
-{
-	global $addr, $url, $idx, $cnt,$ok,$ns;
-
-	if (!isset($cnt))
-		$cnt = 16;
-
-	$big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-	echo "<table width=\"100%\" border=\"0\">\n";
-	echo "<tr><td bgcolor=\"#cccccc\" nowrap=\"nowrap\">"._("Failed")."</td><td bgcolor=\"#cccccc\">"._("Ok")."</td></tr>\n";
-	for ($i = 0; $i < count($addr); $i++)
-		echo "<tr><td nowrap=\"nowrap\">".
-		     "<a href=\"$url?idx=$i&ok=0&cnt=$cnt\">$addr[$i]</a></td><td nowrap=\"nowrap\">".
-		     "[<a href=\"$url?idx=$i&ok=1&cnt=$cnt\">OK</a>]</td>".
-		     #"<td>[<a href=\"$url?idx=$i&action=qa\">qa</a>]</td>".
-		     "</tr>\n";
-	echo "</table><hr />\n";
-	
-	echo "<div align=\"center\">";
-	echo "<a href=\"$big_url&action=adv_search\">"._("Advanced Search")."</a><br />\n";
-	
-	echo "<a href=\"$url\">main()</a><hr />\n";
-	echo "<a href=\"http://www.pld-linux.org/\"><img src=\"powpld.png\" ".
-		"alt=\""._("Powered by PLD Linux")."\" border=\"0\" /></a><br />\n" .
-	     "<small>(c) 2002 ".
-	     "<a href=\"mailto:feedback at pld-linux.org\">PLD Team</a><br />\n".
-	     '$Revision: 1.90 $'.
-	     "</small></div>\n";
-
-	# smile ;)
-	echo "<div align=\"center\"><small>";
-	$pow = array("vim", "php", "brain", "power", "electricity",
-		     "coffee", "ufo", "penguin", "GNOME", "ELF", "DWARF",
-		     "voodoo magic", "Linux", "x-files", "X", "foobar",
-		     "/dev/null", "/dev/zero", "/dev/drzewo", 
-		     "Leppe'", "matrix", "Neo", "PDP-11",
-		     "Ken", "GNU antilope", "PDP-7", "ITS", "Multics",
-		     "foobarbaz", "ed", "Joe", "Unix conspiracy", 
-		     "overclock", "The Right Thing",
-		     "The Bad Thing", "Star Treck", "NSA", "NASA",
-		     "achelon", "VAX", "Real Programmer",
-		     "Real Operating System", "Real Computer",
-		     "computron", "bogon", "quantum bogodynamics",
-		     "BOFH", "/dev/ill", "nasi tu byli",
-		     "Paranoid Android", "Lunatic Corp", "Parallel thinking",
-		     "sfistak", "Linus", "The Golden Path", "Dark Side of the Force",
-		     "Przewodniczacego Lepper-a", "KDE", "Microsoft Windows 2003"
-		     # feel free to add sth if you change this file ;)
-		     );
-	echo _("Powered by")." ";
-	$max = 1;
-	for ($i = 0; $i < $max; $i++) {
-		$x = rand(0, count($pow) - 1);
-		if ($pow[$x] == "") $i--;
-		else echo $pow[$x] . ($i == $max - 1 ? "." : ", ");
-		$pow[$x] = "";
-	}
-	echo "</small></div>";
-
-	global $qa_addr;
-
-	if (isset($qa_addr[$idx]) && $qa_addr[$idx] != "") {
-	echo "<form action=\"index.php\" method=\"post\">";
-	echo "<input type=\"hidden\" name=\"idx\" value=\"$idx\" />";
-	echo "<input type=\"hidden\" name=\"action\" value=\"sqa\" />";
-	echo "<input type=\"text\" size=\"14\" name=\"str\" /><br />";
-	echo "<input type=\"submit\" name=\"submit\" value=\""._("Search rpmqa!")."\" />";
-	echo "</form>";
-	}
-}
-
-function get_qa()
-{
-	global $idx, $qa_addr;
-
-	if (!isset($idx) || !isset($qa_addr[$idx]))
-		return false;
-
-	$a = $qa_addr[$idx];
-
-	if ($qa_addr[$idx] == "")
-		return false;
-	else
-		return fopen("$qa_addr[$idx]", "r");
-}
-
-function search_qa()
-{
-	global $url, $idx, $qa_addr, $str;
-
-	$f = get_qa();
-	echo "<h1>"._("Search results for")." '$str' "._("in")." $qa_addr[$idx]</h1>";
-
-	start_pre();
-
-	if ($f == 0) {
-	 	echo _("Sorry, cannot open.");
-	} else {
-		while (($s = fgets($f, 1000)) != false) {
-			if (stristr($s, $str))
-				echo $s;
-		}
-		echo "/* EOF */";
-	}
-	end_pre();
-}
-
-function dump_qa($plain)
-{
-	global $url, $idx, $qa_addr;
-
-	$a = $qa_addr[$idx];
-
-	$f = get_qa();
-
-	if ($plain) {
-		header("Content-type: text/plain"); 
-		echo _("# rpm -qa of")." $a\n";
-	} else {
-		echo "<h1>"._("rpm -qa of")." $a</h1>";
-		echo "<a href=\"$url?idx=$idx&action=qatxt\">"._("text/plain version")."</a>";
-		start_pre();
-	}
-
-	if ($f == 0) {
-	 	echo _("Sorry, cannot open.");
-	} else {
-		while (($s = fgets($f, 1000)) != false) {
-			echo $s;
-		}
-	}
-
-	if (!$plain)
-		end_pre();
-}
-
-
-function adv_search()
-{
-  global $addr, $url, $local, $_POST, $off, $cnt, $root_directory;
-
-  $big_url = "$url?idx=$idx&ok=$ok&ns=$ns&cnt=$cnt";
-
-  echo "<script><!--\n".
-       "function checkboxToggle() {\n".
-       "for (var i=0;i<document.forms[0].elements.length;i++) {\n".
-       "var e = document.forms[0].elements[i];\n".
-       "if ((e.name != 'all') && (e.type=='checkbox'))\n".
-       "e.checked = document.forms[0].all.checked;\n".
-       "}\n }\n -->\n </script>\n";
-
-  echo "<form action=\"index.php?action=adv_search\" method=\"post\">";
-
-  echo "<div align=\"center\">";
-  echo "<table border=\"0\">\n";
-  echo "<tr>\n";
-  echo "<td>"._("Package name")."</td>\n";
-  echo "<td><input type=\"text\" size=\"20\" name=\"name\" value=\"".$_POST["name"]."\"/></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Days")."</td>\n";
-  echo "<td>"._("From").": <input type=\"text\" size=\"20\" name=\"age1\" value=\"".$_POST["age1"]."\" /></td>\n";
-  echo "<td>"._("To").": <input type=\"text\" size=\"20\" name=\"age2\" value=\"".$_POST["age2"]."\" /></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Size")."</td>\n";
-  echo "<td>"._("From").": <input type=\"text\" size=\"20\" name=\"size1\" value=\"".$_POST["size1"]."\" /></td>\n";
-  echo "<td>"._("To").": <input type=\"text\" size=\"20\" name=\"size2\" value=\"".$_POST["size2"]."\" /></td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Search logs:")."</td>\n";
-  echo "</tr>\n";
-
-  echo "<tr>\n";
-  echo "<td>"._("Failed")."</td>\n";
-  echo "<td>"._("OK")."</td>\n";
-  echo "</tr>\n";
-
-  for ($i = 0; $i < count($addr); $i++)
-  {
-    echo "<tr>\n";
-    $name="as0_".$i;
-    $check=" checked=\"on\"";
-    echo "<td><input name=\"$name\" id=\"$name\" type=\"checkbox\"$check /><label for=\"$name\">".$addr[$i]."</label></td>\n";
-    $name="as1_".$i;
-    $check=" checked=\"on\"";
-    echo "<td><input name=\"$name\" id=\"$name\" type=\"checkbox\"$check /><label for=\"$name\">".$addr[$i]."</label></td>\n";
-    echo "</tr>\n";
-  }
-	
-  echo "<tr>\n";
-  echo "<td><input name=\"all\" type=\"checkbox\" checked=\"on\" onClick=\"checkboxToggle()\">"._("Toggle checkboxes")." <input type=\"submit\" name=\"submit\" value=\""._("Search!")."\" /></td>";
-  echo "</tr>\n";
-
-  echo "</table>\n";
-
-//	if (isset($_POST["name"]) || isset($_POST["age1"]) || isset($_POST["age2"]) ||
-//	  isset($_POST["size1"]) || isset($_POST["size2"]))
-  if (($_POST["name"]!="") || ($_POST["age1"]!="") || ($_POST["age2"]!="") ||
-    ($_POST["size1"]!="") || ($_POST["size2"]!=""))
-  {
-    unset($list);
-    $now = time();
-    for ($i = 0; $i < count($addr); $i++)
-    
-      for ($j=0;$j<2;$j++)
-	{
-          unset($tmp_list);
-          if (isset($_POST["as".$j."_".$i]))
-  	  {
-	    if ($local) {
-		$tmp_list = directory_list($i,$j);
-	    } else {
-	  	$tmp_list = open_ftp($i,$j);
-	    }
-	    if (is_array($tmp_list))
-	    {
-	      while (list($k,$name)=each($tmp_list))
-	      {
-		$s = filesize("$root_directory$name[0]");
-		$t = $now - $name[1];
-		$t/=(24*3600);
-		if (($_POST["name"]!="") && (!preg_match("/".$_POST["name"]."/i",$name[0])))continue;
-		if (($_POST["age1"]) && ($_POST["age1"]>$t))continue;
-		if (($_POST["age2"]) && ($_POST["age2"]<$t))continue;
-
-		if (($_POST["size1"]) && ($_POST["size1"]>$s))continue;
-		if (($_POST["size2"]) && ($_POST["size2"]<$s))continue;
-
-	        $list[$i."_".$j."_".$k]=$name;
-	      }
-	    }
-	  }
-        }
-	
-	if (sizeof($list)==0)
-	{
-	  echo _("Nothing found");
-	} else
-	{
-
-	echo "<table border=\"0\" cellspacing=\"1\" ".
-		"cellpadding=3 bgcolor=\"#000000\" width=\"90%\">\n";
-	echo "<tr><th bgcolor=\"#CCCCFF\" align=\"left\" width=\"10%\">"._("Builder").
-	     "[<a href=\"$big_url&ns=2\">"._("sort")."</a>]</th>";
-	echo "<th bgcolor=\"#CCCCFF\" align=\"left\" width=\"60%\">"._("Log File").
-			"[<a href=\"$big_url&ns=1\">"._("sort")."</a>]</th>".
-	         "<th bgcolor=\"#CCCCFF\" align=\"right\" width=\"15%\">"._("Size")."</th> ".
-		 "<th bgcolor=\"#CCCCFF\" align=\"left\">"._("Age").
-			 "[<a href=\"$big_url&ns=0\">"._("sort")."</a>]</th>".
-		 "</th></tr>";
-
-	function cmp1($f1, $f2) {
-		global $ftp_conn, $root_directory, $local;
-		if ($local)
-			return $f2[1] - $f1[1];
-		return ftp_mdtm($ftp_conn, $f2) - ftp_mdtm($ftp_conn, $f1);
-	}
-
-	function cmp2($f1, $f2) {
-	  list($p11,$p12,$p13)=explode("_",$f1[0]);
-	  list($p21,$p22,$p23)=explode("_",$f2[0]);
-	  return strcmp($f1[0],$f2[0]);
-	}
-
-	if ($ns == 1)
-	{
-	  usort($list, "cmp1");
-//	} else if ($ns == 2)
-//	{
-//	  uksort($list, "cmp2");
-	} else
-	{
-	  asort($list);
-	}
-
-        $counter=0;
-	while (list($k,$name)=each($list))
-	{
-	if (($counter<$off) || ($counter>$off+$cnt-1))
-	{
-  	  $counter++;
-	  continue;
-	}
-
-  	  $counter++;
-	  list($i,$j,$k)=explode("_",$k);
-	  $filename = $name[0];
-
-		$h = bin2hex(mhash(MHASH_MD5, $filename));
-		$f = preg_replace("/.*\/([^\/]*)$/", "\\1", $filename);
-		$f = preg_replace("/\.(bz2|gz)$/", "", $f);
-		if ($local) {
-			$s = filesize("$root_directory$filename");
-			$t = $now - $name[1];
-		} else {
-			$s = ftp_size($ftp_conn, $list[$i]);
-			$t = $now - ftp_mdtm($ftp_conn, $list[$i]);
-		}
-		$t /= 60;
-		if ($t >= 60) {
-			$t /= 60;
-			if ($t >= 24) {
-				$t /= 24;
-				$t = round($t);
-				$t = $t . " " . ngettext("day","days",$t);
-			} else {
-				$t = round($t);
-				$t = $t . " " . ngettext("hour","hours",$t);
-			}
-		} else {
-			$t = round($t);
-			$t = $t . " " . ngettext("minute","minutes",$t);
-		}
-                $big_url = "$url?idx=$i&ok=$j&ns=$ns&cnt=$cnt";
-		$u = "$big_url&off=$off&id=$h";
-
-		$builder=$addr[$i]."/".(($j=="1")?"OK":"FAIL");
-		echo "<tr>";
-		echo "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">$builder</a></td>";
-		echo "<td bgcolor=\"#CCCCCC\"><a href=\"$u\">$f</a> ".
-		     "[<a href=\"$u&action=text\">"._("text")."</a> | ".
-		      "<a href=\"$u&action=tail\">"._("tail")."</a>]".
-		     "</td><td bgcolor=\"#CCCCCC\" align=\"right\">".
-		     "$s</td><td bgcolor=\"#CCCCCC\">$t</td></tr>\n";
-	}
-	echo "</table></div>\n";
-
-	$backarr = "<<< ";
-	$back = _("Page back");
-	$forward = _("Page forward");
-	$forwardarr = " >>>";
-
-// FIXME
-/*
-	echo "<p><table width=\"90%\" align=\"center\"><tr><td align=left width=1%>";
-
-	if ($off > 0) {
-		$noff = $off - $cnt;
<Skipped 490 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/projects/buildlogs.git/commitdiff/166f87ba777bdf92412dccf4b6e825ff1e0b4f99



More information about the pld-cvs-commit mailing list