cookutils diff lighttpd/index.cgi @ rev 898

Add lighttpd/*: this is for cook.slitaz.org Lighttpd-driven web interface.
author Aleksej Bobylev <al.bobylev@gmail.com>
date Thu May 11 00:17:06 2017 +0300 (2017-05-11)
parents
children e6e0957f3a48
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lighttpd/index.cgi	Thu May 11 00:17:06 2017 +0300
     1.3 @@ -0,0 +1,1205 @@
     1.4 +#!/bin/sh
     1.5 +#
     1.6 +# SliTaz Cooker CGI + Lighttpd web interface.
     1.7 +#
     1.8 +
     1.9 +# Make request URI relative to the script name
    1.10 +base="$(dirname "$SCRIPT_NAME")"; [ "$base" == '/' ] && base=''
    1.11 +REQUEST_URI=$(echo "$REQUEST_URI" | sed "s|^$base/*|/|; s|\?.*||")
    1.12 +
    1.13 +# Split the URI request to /pkg/cmd/arg
    1.14 +export pkg=$(echo "$REQUEST_URI" | cut -d/ -f2)
    1.15 +export cmd=$(echo "$REQUEST_URI" | cut -d/ -f3)
    1.16 +export arg=$(echo "$REQUEST_URI" | sed 's|^/[^/]*/[^/]*/||')
    1.17 +
    1.18 +
    1.19 +. /usr/lib/slitaz/httphelper.sh
    1.20 +
    1.21 +[ -f "/etc/slitaz/cook.conf" ] && . /etc/slitaz/cook.conf
    1.22 +[ -f "./cook.conf" ] && . ./cook.conf
    1.23 +wok="$WOK"
    1.24 +title=${title:-SliTaz Cooker}
    1.25 +# Cooker DB files.
    1.26 +activity="$CACHE/activity"
    1.27 +commits="$CACHE/commits"
    1.28 +cooklist="$CACHE/cooklist"
    1.29 +cookorder="$CACHE/cookorder"
    1.30 +command="$CACHE/command"; touch $command
    1.31 +blocked="$CACHE/blocked"
    1.32 +broken="$CACHE/broken"
    1.33 +cooknotes="$CACHE/cooknotes"
    1.34 +cooktime="$CACHE/cooktime"
    1.35 +wokrev="$CACHE/wokrev"
    1.36 +
    1.37 +# Path to markdown to html convertor
    1.38 +cmark_opts='--smart -e table -e strikethrough -e autolink -e tagfilter'
    1.39 +if [ -n "$(which cmark 2>/dev/null)" ]; then
    1.40 +	md2html="$(which cmark) $cmark_opts"
    1.41 +elif [ -x "./cmark" ]; then
    1.42 +	md2html="./cmark $cmark_opts"
    1.43 +elif [ -n "$(which sundown 2>/dev/null)" ]; then
    1.44 +	md2html=$(which sundown)
    1.45 +elif [ -x "./sundown" ]; then
    1.46 +	md2html="./sundown"
    1.47 +fi
    1.48 +
    1.49 +
    1.50 +
    1.51 +
    1.52 +# Search form redirection
    1.53 +if [ -n "$(GET search)" ]; then
    1.54 +	echo -e "HTTP/1.1 301 Moved Permanently\nLocation: $base/$(GET q)\n\n"
    1.55 +	exit 0
    1.56 +fi
    1.57 +
    1.58 +
    1.59 +# Show the running command and it's progression
    1.60 +
    1.61 +running_command() {
    1.62 +	state="$(cat $command)"
    1.63 +	local pct
    1.64 +	if [ -n "$state" ];then
    1.65 +		echo -n "$state</td></tr><tr><td>Completion</td>"
    1.66 +		set -- $(grep "^$state" $cooktime)
    1.67 +		[ -n "$1" -a $2 -ne 0 ] && pct=$((($(date +%s)-$3)*100/$2))
    1.68 +		[ -n "$pct" ] && max="max='100'"
    1.69 +		echo -n "<td><progress id='gauge' $max value='$pct' title='Click to stop updating' onclick='stopUpdating()'>"
    1.70 +		echo -n "</progress> <span id='pct'>${pct:-?}%</span>"
    1.71 +		[ "$2" -gt 60 ] &&
    1.72 +			echo -n "</td></tr><tr><td>Estimated end time</td><td>$(date +%H:%M -ud @$(($2+$3)))"
    1.73 +	else
    1.74 +		echo 'not running'
    1.75 +	fi
    1.76 +}
    1.77 +
    1.78 +
    1.79 +# HTML page header
    1.80 +
    1.81 +page_header() {
    1.82 +	local theme t='' css
    1.83 +	theme=$(COOKIE theme)
    1.84 +	[ "$theme" == 'default' ] && theme=''
    1.85 +	[ -n "$theme" ] && theme="-$theme"
    1.86 +	css="cooker$theme.css"
    1.87 +
    1.88 +	echo -e 'Content-Type: text/html; charset=UTF-8\n'
    1.89 +
    1.90 +	cat <<EOT
    1.91 +<!DOCTYPE html>
    1.92 +<html lang="en">
    1.93 +<head>
    1.94 +	<title>$([ -n "$pkg" ] && echo "$pkg - ")$title</title>
    1.95 +	<link rel="stylesheet" href="/$css">
    1.96 +	<link rel="icon" type="image/png" href="/slitaz-cooker.png">
    1.97 +	<!-- mobile -->
    1.98 +	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    1.99 +	<meta name="theme-color" content="#222">
   1.100 +	<!-- rss -->
   1.101 +	<link rel="alternate" type="application/rss+xml" title="$title Feed" href="?rss">
   1.102 +</head>
   1.103 +<body>
   1.104 +<div id="container">
   1.105 +<header>
   1.106 +	<h1><a href="$base/">$title</a></h1>
   1.107 +	<div class="network">
   1.108 +		<a href="http://www.slitaz.org/">Home</a>
   1.109 +		<a href="http://bugs.slitaz.org/">Bugs</a>
   1.110 +		<a href="http://hg.slitaz.org/wok-next/">Hg</a>
   1.111 +		<a href="http://roadmap.slitaz.org/">Roadmap</a>
   1.112 +		<a href="http://pizza.slitaz.me/">Pizza</a>
   1.113 +		<a href="http://tank.slitaz.org/">Tank</a>
   1.114 +		|
   1.115 +		<a href="$base/cross/">Cross</a>
   1.116 +		<a href="$base/i486.cgi">i486</a>
   1.117 +		<a href="$base/cookiso.cgi">ISO</a>
   1.118 +		<select onChange="window.location.href=this.value" style="display: none">
   1.119 +			<option value=".">Go to…</option>
   1.120 +			<option value="http://www.slitaz.org/">Home</option>
   1.121 +			<option value="http://bugs.slitaz.org/">Bug tracker</option>
   1.122 +			<option value="http://hg.slitaz.org/wok/">Hg wok</option>
   1.123 +			<option value="http://roadmap.slitaz.org/">Roadmap</option>
   1.124 +			<option value="http://pizza.slitaz.me/">Pizza</option>
   1.125 +			<option value="http://tank.slitaz.org/">Tank</option>
   1.126 +			<option disabled>---------</option>
   1.127 +			<option value="cross/">Cross</option>
   1.128 +			<option value="i486.cgi">i486</option>
   1.129 +			<option value="cookiso.cgi">ISO</option>
   1.130 +		</select>
   1.131 +	</div>
   1.132 +</header>
   1.133 +
   1.134 +<main>
   1.135 +EOT
   1.136 +
   1.137 +	[ -n "$(GET debug)" ] && echo "<pre><code class='language-ini'>$(env | sort)</code></pre>"
   1.138 +}
   1.139 +
   1.140 +
   1.141 +# HTML page footer
   1.142 +
   1.143 +page_footer() {
   1.144 +	date_now=$(date +%s)
   1.145 +	sec_now=$(date +%S); sec_now=${sec_now#0} # remove one leading zero
   1.146 +	wait_sec=$(( 60 - $sec_now ))
   1.147 +	cat <<EOT
   1.148 +</main>
   1.149 +
   1.150 +<footer>
   1.151 +	<a href="http://www.slitaz.org/">SliTaz Website</a>
   1.152 +	<a href="$base/">Cooker</a>
   1.153 +	<a href="$base/doc/cookutils/cookutils.html">Documentation</a>
   1.154 +	<a href="$base/?theme">Theme</a>
   1.155 +</footer>
   1.156 +</div>
   1.157 +<script src="/cooker.js"></script>
   1.158 +<script>refreshDate(${wait_sec}000, ${date_now}000)</script>
   1.159 +</body>
   1.160 +</html>
   1.161 +EOT
   1.162 +}
   1.163 +
   1.164 +
   1.165 +show_note() {
   1.166 +	echo "<div class='bigicon-$1'>$2</div>"
   1.167 +}
   1.168 +
   1.169 +
   1.170 +not_found() {
   1.171 +	local file="${1#$PKGS/}"; file="${file#$LOGS/}"; file="${file#$WOK/}"
   1.172 +	echo "HTTP/1.1 404 Not Found"
   1.173 +	page_header
   1.174 +	echo "<h2>Not Found</h2>"
   1.175 +	case $2 in
   1.176 +		pkg)
   1.177 +			show_note e "The requested package “$(basename "$(dirname "$file")")” was not found." ;;
   1.178 +		*)
   1.179 +			show_note e "The requested file “$file” was not found." ;;
   1.180 +	esac
   1.181 +	page_footer
   1.182 +}
   1.183 +
   1.184 +
   1.185 +manage_modified() {
   1.186 +	local file="$1" option="$2" nul day mon year time hh mm ss date_s
   1.187 +	if [ ! -f "$file" ]; then
   1.188 +		if [ "$option" == 'silently-absent' ]; then
   1.189 +			echo "HTTP/1.1 404 Not Found"
   1.190 +			return
   1.191 +		else
   1.192 +			not_found "$file" "$2"
   1.193 +			exit
   1.194 +		fi
   1.195 +	fi
   1.196 +	[ "$option" == 'no-last-modified' ] && return
   1.197 +	if [ -n "$HTTP_IF_MODIFIED_SINCE" ]; then
   1.198 +		echo "$HTTP_IF_MODIFIED_SINCE" | \
   1.199 +		while read nul day mon year time nul; do
   1.200 +			case $mon in
   1.201 +				Jan) mon='01';; Feb) mon='02';; Mar) mon='03';; Apr) mon='04';;
   1.202 +				May) mon='05';; Jun) mon='06';; Jul) mon='07';; Aug) mon='08';;
   1.203 +				Sep) mon='09';; Oct) mon='10';; Nov) mon='11';; Dec) mon='12';;
   1.204 +			esac
   1.205 +			hh=$(echo $time | cut -d: -f1)
   1.206 +			mm=$(echo $time | cut -d: -f2)
   1.207 +			ss=$(echo $time | cut -d: -f3)
   1.208 +			date_s=$(date -ud "$year$mon$day$hh$mm.$ss" +%s)
   1.209 +#			if [ "$date_s" -ge "$(date -ur "$file" +%s)" ]; then
   1.210 +#				echo -e 'HTTP/1.1 304 Not Modified\n'
   1.211 +#				exit
   1.212 +#			fi
   1.213 +# TODO: improve caching control
   1.214 +		done
   1.215 +	fi
   1.216 +	echo "Last-Modified: $(date -Rur "$file" | sed 's|UTC|GMT|')"
   1.217 +	echo "Cache-Control: public, max-age=3600"
   1.218 +}
   1.219 +
   1.220 +
   1.221 +# Query '?pct=<package>': update percentage
   1.222 +
   1.223 +if [ -n "$(GET pct)" ]; then
   1.224 +	pkg="$(GET pct)"
   1.225 +	state="$(cat $command)"
   1.226 +	if [ "$state" == "cook:$pkg" ]; then
   1.227 +		set -- $(grep "^$state" $cooktime)
   1.228 +		[ -n "$1" ] && pct=$(( ($(date +%s) - $3) * 100 / $2 ))
   1.229 +		echo "${pct:-?}"
   1.230 +	else
   1.231 +		echo 'reload'
   1.232 +	fi
   1.233 +	exit 0
   1.234 +fi
   1.235 +
   1.236 +
   1.237 +# Query '?poke': poke cooker
   1.238 +
   1.239 +if [ -n "$(GET poke)" ]; then
   1.240 +	touch $CACHE/cooker-request
   1.241 +	echo -e "Location: ${HTTP_REFERER:-${REQUEST_URI%\?*}}\n"
   1.242 +	exit
   1.243 +fi
   1.244 +
   1.245 +
   1.246 +# Query '?recook=<package>': query to recook package
   1.247 +
   1.248 +if [ -n "$(GET recook)" ]; then
   1.249 +	pkg="$(GET recook)"
   1.250 +	case "$HTTP_USER_AGENT" in
   1.251 +		*SliTaz*)
   1.252 +			grep -qs "^$pkg$" $CACHE/recook-packages ||
   1.253 +			echo "$pkg" >>    $CACHE/recook-packages
   1.254 +	esac
   1.255 +	echo -e "Location: ${HTTP_REFERER:-${REQUEST_URI%\?*}}\n"
   1.256 +	exit
   1.257 +fi
   1.258 +
   1.259 +
   1.260 +# Query '/i/<log>/<pkg>': show indicator icon
   1.261 +# Can't use ?query - not able to change '+' to '%2B' in the sed rules (see log handler)
   1.262 +
   1.263 +if [ "$pkg" == 'i' ]; then
   1.264 +	echo -en "Content-Type: image/svg+xml\n\n<svg xmlns='http://www.w3.org/2000/svg' height='12' width='8'><path d='"
   1.265 +	if [ $LOGS/$cmd -nt $PKGS/$arg.tazpkg ]; then
   1.266 +		echo "m1 2-1 1v8l1 1h6l1-1v-8l-1-1z' fill='#090'/></svg>"
   1.267 +	else
   1.268 +		echo "m0 3v8l1 1h6l1-1v-8l-1-1h-6zm3 0h2v5h-2zm0 6h2v2h-2z' fill='#d00'/></svg>"
   1.269 +	fi
   1.270 +	exit
   1.271 +fi
   1.272 +
   1.273 +
   1.274 +# Query '?theme[=<theme>]': change UI theme
   1.275 +
   1.276 +if [ -n "$(GET theme)" ]; then
   1.277 +	theme="$(GET theme)"
   1.278 +	case $theme in
   1.279 +		theme)
   1.280 +			current=$(COOKIE theme)
   1.281 +			page_header
   1.282 +			cat <<EOT
   1.283 +<section>
   1.284 +	<h2>Change theme</h2>
   1.285 +	<p>Current theme: “${current:-default}”. Select other:</p>
   1.286 +	<ul>
   1.287 +		$(
   1.288 +			for i in default emerald sky goldenrod like2016 terminal; do
   1.289 +				[ "$i" == "${current:-default}" ] || echo "<li><a href="$base/?theme=$i">$i</a></li>"
   1.290 +			done
   1.291 +		)
   1.292 +	</ul>
   1.293 +</section>
   1.294 +EOT
   1.295 +			page_footer
   1.296 +			exit 0
   1.297 +			;;
   1.298 +		default|emerald|sky|goldenrod|like2016|terminal)
   1.299 +			# Expires in a year
   1.300 +			expires=$(date -uRd @$(($(date +%s)+31536000)) | sed 's|UTC|GMT|')
   1.301 +			echo -e "HTTP/1.1 302 Found\nLocation: $base/\nCache-Control: no-cache\nSet-Cookie: theme=$theme; expires=$expires\n\n"
   1.302 +			exit 0
   1.303 +			;;
   1.304 +	esac
   1.305 +fi
   1.306 +
   1.307 +
   1.308 +#case "$QUERY_STRING" in
   1.309 +#	stuff*)
   1.310 +#		file="$wok/$(GET stuff)"
   1.311 +#		manage_modified "$file"
   1.312 +#		;;
   1.313 +#
   1.314 +#	pkg=*|receipt=*|description=*|files=*|log=*|man=*|doc=*|info=*)
   1.315 +#		type=${QUERY_STRING%%=*}
   1.316 +#		pkg=$(GET $type)
   1.317 +#		case "$type" in
   1.318 +#			description)
   1.319 +#				manage_modified "$wok/$pkg/receipt" 'no-last-modified'
   1.320 +#				manage_modified "$wok/$pkg/description.txt" 'silently-absent'
   1.321 +#				;;
   1.322 +#			log)
   1.323 +#				manage_modified "$wok/${pkg%%.log*}/receipt" 'no-last-modified'
   1.324 +#				manage_modified "$LOGS/$pkg"
   1.325 +#				;;
   1.326 +#			*)
   1.327 +#				manage_modified "$wok/$pkg/receipt" pkg
   1.328 +#				;;
   1.329 +#		esac
   1.330 +#		;;
   1.331 +#esac
   1.332 +
   1.333 +
   1.334 +# RSS feed generator
   1.335 +# URI: ?rss[&limit={1..100}]
   1.336 +
   1.337 +if [ -n "$(GET rss)" ]; then
   1.338 +	limit=$(GET limit); limit="${limit:-12}"; [ "$limit" -gt 100 ] && limit='100'
   1.339 +	pubdate=$(date -Rur$(ls -t $FEEDS/*.xml | head -n1) | sed 's|UTC|GMT|')
   1.340 +	cooker_url="http://$HTTP_HOST$base/"
   1.341 +	cat <<EOT
   1.342 +Content-Type: application/rss+xml
   1.343 +
   1.344 +<?xml version="1.0" encoding="utf-8" ?>
   1.345 +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
   1.346 +<channel>
   1.347 +	<title>$title</title>
   1.348 +	<description>The SliTaz packages cooker feed</description>
   1.349 +	<link>$cooker_url</link>
   1.350 +	<lastBuildDate>$pubdate</lastBuildDate>
   1.351 +	<pubDate>$pubdate</pubDate>
   1.352 +	<atom:link href="$cooker_url?rss" rel="self" type="application/rss+xml" />
   1.353 +EOT
   1.354 +	for rss in $(ls -t $FEEDS/*.xml | head -n$limit); do
   1.355 +		sed "s|http[^=]*=|$cooker_url|; s|<guid|& isPermaLink=\"false\"|g; s|</pubDate| GMT&|g" $rss
   1.356 +	done
   1.357 +	cat <<EOT
   1.358 +</channel>
   1.359 +</rss>
   1.360 +EOT
   1.361 +	exit 0
   1.362 +fi
   1.363 +
   1.364 +
   1.365 +
   1.366 +
   1.367 +#
   1.368 +# Functions
   1.369 +#
   1.370 +
   1.371 +
   1.372 +# Unpack to stdout
   1.373 +
   1.374 +docat() {
   1.375 +	case "$1" in
   1.376 +		*gz)   zcat ;;
   1.377 +		*bz2) bzcat ;;
   1.378 +		*xz)  xzcat ;;
   1.379 +		*)      cat
   1.380 +	esac < $1
   1.381 +}
   1.382 +
   1.383 +
   1.384 +# Tiny texinfo converter
   1.385 +
   1.386 +info2html() {
   1.387 +	sed \
   1.388 +		-e 's|&|\&amp;|g; s|<|\&lt;|g; s|>|\&gt;|g' \
   1.389 +		-e 's|^\* \(.*\)::|* <a href="#\1">\1</a>  |' \
   1.390 +		-e 's|\*note \(.*\)::|<a href="#\1">\1</a>|' \
   1.391 +		-e '/^File: / s|(dir)|Top|g' \
   1.392 +		-e '/^File: / s|Next: \([^,]*\)|<a class="button" href="#\1">Next: \1</a>|' \
   1.393 +		-e '/^File: / s|Prev: \([^,]*\)|<a class="button" href="#\1">Prev: \1</a>|' \
   1.394 +		-e '/^File: / s|Up: \([^,]*\)|<a class="button" href="#\1">Up: \1</a>|' \
   1.395 +		-e '/^File: / s|^.* Node: \([^,]*\), *\(.*\)$|<pre id="\1">\2|' \
   1.396 +		-e '/^<pre id=/ s|^\([^>]*>\)\(<a[^>]*>Next: [^,]*\), *\(<a[^>]*>Prev: [^,]*\), *\(<a[^>]*>Up: .*\)|\1 \3 \4 \2|' \
   1.397 +		-e '/^Tag Table:$/,/^End Tag Table$/d' \
   1.398 +		-e '/INFO-DIR/,/^END-INFO-DIR/d' \
   1.399 +		-e "s|https*://[^>),'\"\`’ ]*|<a href=\"&\">&</a>|g" \
   1.400 +		-e "s|ftp://[^>),\"\` ]*|<a href=\"&\">&</a>|g" \
   1.401 +		-e 's|^\* Menu:|<b>Menu:</b>|' \
   1.402 +		-e "s|^|</pre>|"
   1.403 +}
   1.404 +
   1.405 +
   1.406 +# Put some colors into log and DB files.
   1.407 +
   1.408 +syntax_highlighter() {
   1.409 +	case $1 in
   1.410 +		log)
   1.411 +			# If variables not defined - define them with some rare values
   1.412 +			: ${_src=#_#_#}
   1.413 +			: ${_install=#_#_#}
   1.414 +			: ${_fs=#_#_#}
   1.415 +			: ${_stuff=#_#_#}
   1.416 +			# Use one-letter html tags to save some bytes :)
   1.417 +			# <b>is error (red)</b> <u>is warning (orange)</u> <i>is informal (green)</i>
   1.418 +			sed	-e 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g' \
   1.419 +				-e 's#OK$#<i>OK</i>#' \
   1.420 +				-e 's#\([Dd]one\)$#<i>\1</i>#' \
   1.421 +				-e 's#Success$#<i>Success</i>#' \
   1.422 +				-e 's#\([^a-z]\)ok$#\1<i>ok</i>#' \
   1.423 +				-e 's#\([^a-z]\)yes$#\1<i>yes</i>#' \
   1.424 +				-e 's#\([^a-z]\)no$#\1<u>no</u>#' \
   1.425 +				-e 's#\([^a-z]\)none$#\1<u>none</u>#' \
   1.426 +				-e 's#\([^a-z]\)false$#\1<u>false</u>#' \
   1.427 +				-e 's#\(^checking .*\.\.\. \)\(.*\)$#\1<i>\2</i>#' \
   1.428 +				\
   1.429 +				-e 's#\( \[Y[nm/]\?\] n\)$# <u>\1</u>#' \
   1.430 +				-e 's#\( \[N[ym/]\?\] y\)$# <i>\1</i>#' \
   1.431 +				-e 's# y$# <i>y</i>#' \
   1.432 +				-e 's# n$# <u>n</u>#' \
   1.433 +				-e 's#(NEW) *$#<b>(NEW)</b>#' \
   1.434 +				\
   1.435 +				-e 's#.*(pkg/local).*#<i>\0</i>#' \
   1.436 +				-e 's#.*(web/cache).*#<u>\0</u>#' \
   1.437 +				\
   1.438 +				-e 's#\([^a-zA-Z]\)\([Ee]rror\)$#\1<b>\2</b>#' \
   1.439 +				-e 's#ERROR:#<b>ERROR:</b>#g' \
   1.440 +				\
   1.441 +				-e 's#^.*[Ff]ailed.*#<b>\0</b>#' \
   1.442 +				-e 's#^.*[Ff]atal.*#<b>\0</b>#' \
   1.443 +				-e 's#^.*[Nn]ot found.*#<b>\0</b>#' \
   1.444 +				-e 's#^.*[Nn]o such file.*#<b>\0</b>#' \
   1.445 +				-e 's#^.*No package .* found.*#<b>\0</b>#' \
   1.446 +				-e 's#^.*Unable to find.*#<b>\0</b>#' \
   1.447 +				-e 's#^.*[Ii]nvalid.*#<b>\0</b>#' \
   1.448 +				-e 's#\([Nn][Oo][Tt] found\)$#<b>\1</b>#' \
   1.449 +				-e 's#\(found\)$#<i>\1</i>#' \
   1.450 +				\
   1.451 +				-e 's#^.*WARNING:.*#<u>\0</u>#' \
   1.452 +				-e 's#^.*warning:.*#<u>\0</u>#' \
   1.453 +				-e 's#^.* [Ee]rror:* .*#<b>\0</b>#' \
   1.454 +				-e 's#^.*terminated.*#<b>\0</b>#' \
   1.455 +				-e 's#\(missing\)#<b>\1</b>#g' \
   1.456 +				-e 's#^.*[Cc]annot find.*#<b>\0</b>#' \
   1.457 +				-e 's#^.*unrecognized options.*#<u>\0</u>#' \
   1.458 +				-e 's#^.*does not.*#<u>\0</u>#' \
   1.459 +				-e 's#^.*[Ii]gnoring.*#<u>\0</u>#' \
   1.460 +				-e 's#^.*note:.*#<u>\0</u>#' \
   1.461 +				\
   1.462 +				-e 's#^.* will not .*#<u>\0</u>#' \
   1.463 +				-e 's!^Hunk .* succeeded at .*!<u>\0</u>!' \
   1.464 +				-e 's#^.* Warning: .*#<u>\0</u>#' \
   1.465 +				\
   1.466 +				-e "s#^Executing:\([^']*\).#<em>\0</em>#" \
   1.467 +				-e "s#^Making.*#<em>\0</em>#" \
   1.468 +				-e "s#^Scanning dependencies of target .*#<em>\0</em>#" \
   1.469 +				-e "s#^====\([^']*\).#<span class='span-line'>\0</span>#g" \
   1.470 +				-e "s#^[a-zA-Z0-9]\([^']*\) :: #<span class='span-sky'>\0</span>#g" \
   1.471 +				-e "s#[fh]tt*ps*://[^ '\"]*#<a href='\0'>\0</a>#g" \
   1.472 +				\
   1.473 +				-e "s|$_src|<span class='var'>\${src}</span>|g;
   1.474 +					s|$_install|<span class='var'>\${install}</span>|g;
   1.475 +					s|$_fs|<span class='var'>\${fs}</span>|g;
   1.476 +					s|$_stuff|<span class='var'>\${stuff}</span>|g" \
   1.477 +				-e "s|\[9\([1-6]\)m|<span class='c\1'>|;
   1.478 +					s|\[39m|</span>|;"
   1.479 +			;;
   1.480 +
   1.481 +		files)
   1.482 +			# Highlight the Busybox's `ls` output
   1.483 +			awk '{
   1.484 +				part1 = substr($0,  0, 16);
   1.485 +				part2 = substr($0, 17,  9);
   1.486 +				part3 = substr($0, 26,  9);
   1.487 +				part4 = substr($0, 35);
   1.488 +				if (part2 != "root     ") part2 = "<span class=\"c11\">" part2 "</span>";
   1.489 +				if (part3 != "root     ") part3 = "<span class=\"c11\">" part3 "</span>";
   1.490 +				print part1 part2 part3 part4;
   1.491 +			}' | \
   1.492 +			sed "s|\[\([01]\);3\([1-7]\)m|<a class='c\2\1'>|g;
   1.493 +				 s|\[\([01]\);0m|<a class='c0\1'>|g;
   1.494 +				 s|\[0m|</a>|g;
   1.495 +				 s|^\(lrwxrwxrwx\)|<span class='c61'>\1</span>|;
   1.496 +				 s|^\(-rwxr-xr-x\)|<span class='c21'>\1</span>|;
   1.497 +				 s|^\(-rw-r--r--\)|<span class='c31'>\1</span>|;
   1.498 +				 s|^\([lrwx-]*\)|<span class='c11'>\1</span>|;
   1.499 +				"
   1.500 +			;;
   1.501 +	esac
   1.502 +}
   1.503 +
   1.504 +
   1.505 +show_code() {
   1.506 +	echo -n "<pre><code class=\"language-$1\">"
   1.507 +	sed 's|&|\&amp;|g; s|<|\&lt;|g; s|>|\&gt;|g'
   1.508 +	echo '</code></pre>'
   1.509 +}
   1.510 +
   1.511 +
   1.512 +datalist() {
   1.513 +	(
   1.514 +		cd $wok
   1.515 +
   1.516 +		ls | awk '
   1.517 +		BEGIN{printf("<datalist id=\"packages\">")}
   1.518 +		     {printf("<option>%s</option>",$1)}
   1.519 +		END  {printf("</datalist>")}
   1.520 +		'
   1.521 +	)
   1.522 +}
   1.523 +
   1.524 +
   1.525 +mklog() {
   1.526 +	awk '
   1.527 +	BEGIN { printf("<pre class=\"log dog\">\n") }
   1.528 +		  { print }
   1.529 +	  END { print "</pre>" }'
   1.530 +}
   1.531 +
   1.532 +
   1.533 +summary() {
   1.534 +	log="$1"
   1.535 +	pkg="$(basename ${log%%.log*})"
   1.536 +
   1.537 +	if [ -f "$log" ]; then
   1.538 +		if grep -q "cook:$pkg$" $command; then
   1.539 +			show_note i "The Cooker is currently building $pkg"
   1.540 +		elif fgrep -q "Summary for:" $log; then
   1.541 +			sed '/^Summary for:/,$!d' $log | head -n13 | awk '
   1.542 +			BEGIN { print "<section>" }
   1.543 +			{
   1.544 +				if (NR==1) {
   1.545 +					printf("<h3>%s</h3>\n<table>\n", $0)
   1.546 +				} else if ($0 !~ "===") {
   1.547 +					split($0, s, " : ");
   1.548 +					printf("<tr><td>%s</td><td>%s</td></tr>", s[1], s[2]);
   1.549 +				}
   1.550 +			}
   1.551 +			END { print "</table></section>" }
   1.552 +			'
   1.553 +		elif fgrep -q "Debug information" $log; then
   1.554 +			echo -e '<section>\n<h3>Debug information</h3>'
   1.555 +			sed -e '/^Debug information/,$!d; /^===/d; /^$/d' $log | sed -n '1!p' | \
   1.556 +			if [ -n "$2" ]; then
   1.557 +				syntax_highlighter log | sed 's|\([0-9][0-9]*\):|<a href="#l\1">\1</a>:|'
   1.558 +			else
   1.559 +				sed 's|^[0-9][0-9]*:||' | syntax_highlighter log
   1.560 +			fi | mklog
   1.561 +			echo '</section>'
   1.562 +		fi
   1.563 +	else
   1.564 +		[ -n "$pkg" -a -d "$wok/$pkg" ] && show_note e "No log for $pkg"
   1.565 +	fi
   1.566 +}
   1.567 +
   1.568 +
   1.569 +active() {
   1.570 +	[ "$cmd" == "$1" -o "$cmd" == "${2:-$1}" ] && echo -n ' active'
   1.571 +}
   1.572 +
   1.573 +
   1.574 +pkg_info() {
   1.575 +	local log active bpkg
   1.576 +	log="$LOGS/$pkg.log"
   1.577 +
   1.578 +	echo "<h2>Package “$pkg”</h2>"
   1.579 +	echo '<div id="info">'
   1.580 +	echo "<a class='button icon receipt$(active receipt stuff)' href='$base/$pkg/receipt'>receipt &amp; stuff</a>"
   1.581 +
   1.582 +	unset WEB_SITE WANTED
   1.583 +	. $wok/$pkg/receipt
   1.584 +
   1.585 +	[ -n "$WEB_SITE" ] &&
   1.586 +		echo "<a class='button icon website' href='$WEB_SITE' target='_blank' rel='noopener noreferrer'>web site</a>"
   1.587 +
   1.588 +	if [ -f "$wok/$pkg/taz/$PACKAGE-$VERSION/receipt" ]; then
   1.589 +		echo "<a class='button icon files$(active files)' href='$base/$pkg/files'>files</a>"
   1.590 +
   1.591 +		[ -f "$wok/$pkg/description.txt" ] &&
   1.592 +			echo "<a class='button icon desc$(active description)' href='$base/$pkg/description'>description</a>"
   1.593 +
   1.594 +		unset EXTRAVERSION
   1.595 +		. $wok/$pkg/taz/$PACKAGE-$VERSION/receipt
   1.596 +		for filename in "$PACKAGE-$VERSION$EXTRAVERSION.tazpkg" "$PACKAGE-$VERSION$EXTRAVERSION-$ARCH.tazpkg"; do
   1.597 +			[ -f "$PKGS/$filename" ] &&
   1.598 +				echo "<a class='button icon download' href='$base/get/$filename'>download</a>"
   1.599 +		done
   1.600 +
   1.601 +	fi
   1.602 +
   1.603 +	[ -n "$TARBALL" -a -s "$SRC/$TARBALL" ] &&
   1.604 +		echo "<a class='button icon source' href='$base/src/$TARBALL'>source</a>"
   1.605 +
   1.606 +	echo "<a class='button icon browse' href='$base/$pkg/browse/'>browse</a>"
   1.607 +
   1.608 +	[ -x ./man2html -a -d "$wok/$pkg/install/usr/share/man" ] &&
   1.609 +		echo "<a class='button icon doc$(active man)' href='$base/$pkg/man/'>man</a>"
   1.610 +
   1.611 +	[ -d "$wok/$pkg/install/usr/share/doc" -o -d "$wok/$pkg/install/usr/share/gtk-doc" ] &&
   1.612 +		echo "<a class='button icon doc$(active doc)' href='$base/$pkg/doc/'>doc</a>"
   1.613 +
   1.614 +	[ -d "$wok/$pkg/install/usr/share/info" ] &&
   1.615 +		echo "<a class='button icon doc$(active info)' href='$base/$pkg/info/#Top'>info</a>"
   1.616 +
   1.617 +	[ -s "$log" ] &&
   1.618 +		echo "<a class='button icon log$(active log)' href='$base/$pkg/log/'>logs</a>"
   1.619 +
   1.620 +	echo '</div>'
   1.621 +}
   1.622 +
   1.623 +
   1.624 +mktable() {
   1.625 +	sed 's# : #|#' | awk -vc="$1" '
   1.626 +	BEGIN { printf("<table class=\"%s\">\n", c); FS="|" }
   1.627 +		  { printf("<tr><td>%s</td>", $1);
   1.628 +			if (NF == 2) printf("<td>%s</td>", $2);
   1.629 +			printf("</tr>\n", $2) }
   1.630 +	  END { print "</table>" }'
   1.631 +}
   1.632 +
   1.633 +
   1.634 +section() {
   1.635 +	local i=$(basename "$1")
   1.636 +	echo -e '\n\n<section>'
   1.637 +	[ $(wc -l < $1) -gt $2 ] && echo "<a class='button icon more r' href='?$i'>${3#*|}</a>"
   1.638 +	echo "<h2>${3%|*}</h2>"
   1.639 +	mktable "$i"
   1.640 +	echo '</section>'
   1.641 +}
   1.642 +
   1.643 +
   1.644 +
   1.645 +
   1.646 +#
   1.647 +# Load requested page
   1.648 +#
   1.649 +
   1.650 +if [ -z "$pkg" ]; then
   1.651 +
   1.652 +	page_header
   1.653 +	if [ -n "$QUERY_STRING" -a "$QUERY_STRING" != 'debug' ]; then
   1.654 +
   1.655 +		for list in activity cooknotes cooklist; do
   1.656 +			[ -n "$(GET $list)" ] || continue
   1.657 +			[ "$list" == 'cooklist' ] && nb="- Packages: $(wc -l < $cooklist)"
   1.658 +			echo '<section id="content2">'
   1.659 +			echo "<h2>DB: $list $nb</h2>"
   1.660 +			tac $CACHE/$list | sed 's|cooker.cgi?pkg=||;
   1.661 +				s|\[ Done|<span class="r c20">Done|;
   1.662 +				s|\[ Failed|<span class="r c10">Failed|;
   1.663 +				s| \]|</span>|' | mktable $list
   1.664 +			echo '</section>'
   1.665 +		done
   1.666 +
   1.667 +		if [ -n "$(GET broken)" ]; then
   1.668 +			echo '<div id="content2">'
   1.669 +			echo "<h2>DB: broken - Packages: $(wc -l < $broken)</h2>"
   1.670 +			sort $CACHE/broken | sed "s|^[^']*|<a href='$base/\0'>\0</a>|g" | mktable
   1.671 +			echo '</div>'
   1.672 +		fi
   1.673 +
   1.674 +		case "$QUERY_STRING" in
   1.675 +			*.log)
   1.676 +				log=$LOGS/$QUERY_STRING
   1.677 +				name=$(basename $log)
   1.678 +				if [ -f "$log" ]; then
   1.679 +					echo "<h2>Log for: ${name%.log}</h2>"
   1.680 +					if fgrep -q "Summary" $log; then
   1.681 +						echo '<pre class="log">'
   1.682 +						grep -A 20 '^Summary' $log | syntax_highlighter log
   1.683 +						echo '</pre>'
   1.684 +					fi
   1.685 +					echo '<pre class="log">'
   1.686 +					syntax_highlighter log < $log
   1.687 +					echo '</pre>'
   1.688 +				else
   1.689 +					show_note e "No log file: $log"
   1.690 +				fi
   1.691 +				;;
   1.692 +		esac
   1.693 +		page_footer
   1.694 +		exit 0
   1.695 +	fi
   1.696 +
   1.697 +
   1.698 +	# We may have a toolchain.cgi script for cross cooker's
   1.699 +	if [ -f "toolchain.cgi" ]; then
   1.700 +		toolchain="toolchain.cgi"
   1.701 +	else
   1.702 +		toolchain="slitaz-toolchain/"
   1.703 +	fi
   1.704 +	# Main page with summary. Count only package include in ARCH,
   1.705 +	# use 'cooker arch-db' to manually create arch.$ARCH files.
   1.706 +	inwok=$(ls $WOK/*/arch.$ARCH | wc -l)
   1.707 +	cooked=$(ls $PKGS/*.tazpkg | wc -l)
   1.708 +	unbuilt=$(($inwok - $cooked))
   1.709 +	pct=0; [ $inwok -gt 0 ] && pct=$(( ($cooked * 100) / $inwok ))
   1.710 +	cat <<EOT
   1.711 +<div id="content2">
   1.712 +
   1.713 +<section>
   1.714 +<form method="get" action="" class="search r">
   1.715 +	<input type="hidden" name="search" value="pkg"/>
   1.716 +	<button type="submit" title="Search">Search</button>
   1.717 +	<input type="search" name="q" placeholder="Package" list="packages" autocorrect="off" autocapitalize="off"/>
   1.718 +</form>
   1.719 +
   1.720 +<h2>Summary</h2>
   1.721 +EOT
   1.722 +
   1.723 +mktable <<EOT
   1.724 +Cooker state     : $(running_command)
   1.725 +Wok revision     : <a href='$WOK_URL' target='_blank' rel='noopener noreferrer'>$(cat $wokrev)</a>
   1.726 +Commits to cook  : $(wc -l < $commits)
   1.727 +Current cooklist : $(wc -l < $cooklist)
   1.728 +Broken packages  : $(wc -l < $broken)
   1.729 +Blocked packages : $(wc -l < $blocked)
   1.730 +Architecture     : $ARCH, <a href="$toolchain">toolchain</a>
   1.731 +Server date      : <span id='date'>$(date -u '+%F %R %Z')</span>
   1.732 +EOT
   1.733 +
   1.734 +	# If command is "cook:*", update gauge and percentage periodically.
   1.735 +	# If different package is cooking, reload the page (with new settings)
   1.736 +	cmd="$(cat $command)"
   1.737 +	case "$cmd" in
   1.738 +		cook:*)
   1.739 +			pkg=${cmd#*:}
   1.740 +			echo "<script>updatePkg = '${pkg//+/%2B}';</script>"
   1.741 +			;;
   1.742 +	esac
   1.743 +
   1.744 +	if [ -e "$CACHE/cooker-request" -a ! -s $command ]; then
   1.745 +		if [ "$activity" -nt "$CACHE/cooker-request" ]; then
   1.746 +			echo '<a class="button icon bell r" href="?poke">Wake up</a>'
   1.747 +		else
   1.748 +			show_note i 'Cooker will be launched in the next 5 minutes.'
   1.749 +		fi
   1.750 +	fi
   1.751 +
   1.752 +	cat <<EOT
   1.753 +<p>Packages: $inwok in the wok · $cooked cooked · $unbuilt unbuilt</p>
   1.754 +
   1.755 +<div class="meter"><progress max="100" value="$pct">${pct}%</progress><span>${pct}%</span></div>
   1.756 +
   1.757 +<p>
   1.758 +	Service logs:
   1.759 +	<a href="?cookorder.log">cookorder</a> ·
   1.760 +	<a href="?commits.log">commits</a> ·
   1.761 +	<a href="?pkgdb.log">pkgdb</a>
   1.762 +</p>
   1.763 +</section>
   1.764 +EOT
   1.765 +
   1.766 +	tac $activity | head -n12 | sed 's|cooker.cgi?pkg=||;
   1.767 +		s|\[ Done|<span class="r c20">Done|;
   1.768 +		s|\[ Failed|<span class="r c10">Failed|;
   1.769 +		s| \]|</span>|;
   1.770 +		s|%2B|\+|g' | \
   1.771 +		section $activity 12 "Activity|More activity"
   1.772 +
   1.773 +	[ -s "$cooknotes" ] && tac $cooknotes | head -n12 | \
   1.774 +		section $cooknotes 12 "Cooknotes|More notes"
   1.775 +
   1.776 +	[ -s "$commits" ] &&
   1.777 +		section $commits 20 "Commits|More commits" < $commits
   1.778 +
   1.779 +	[ -s "$cooklist" ] && head -n 20 $cooklist | \
   1.780 +		section $cooklist 20 "Cooklist|Full cooklist"
   1.781 +
   1.782 +	[ -s "$broken" ] && head -n20 $broken | sed "s|^[^']*|<a href='\0'>\0</a>|g" | \
   1.783 +		section $broken 20 "Broken|All broken packages"
   1.784 +
   1.785 +	[ -s "$blocked" ] && sed "s|^[^']*|<a href='\0'>\0</a>|g" $blocked | \
   1.786 +		section $blocked 12 "Blocked|All blocked packages"
   1.787 +
   1.788 +	cd $PKGS
   1.789 +	ls -let *.tazpkg | awk '
   1.790 +	(NR<=20){
   1.791 +		sub(/:[0-9][0-9]$/, "", $9);
   1.792 +		mon = index("  JanFebMarAprMayJunJulAugSepOctNovDec", $7) / 3;
   1.793 +		printf("%d-%02d-%02d %s : <a href=\"get/%s\">%s</a>\n", $10, mon, $8, $9, $11, $11);
   1.794 +	}' | \
   1.795 +		section $activity 1000 "Latest cook"
   1.796 +
   1.797 +	echo '</div>'
   1.798 +	datalist
   1.799 +	page_footer
   1.800 +	exit 0
   1.801 +fi
   1.802 +
   1.803 +
   1.804 +case "$cmd" in
   1.805 +	'')
   1.806 +		page_header
   1.807 +		log=$LOGS/$pkg.log
   1.808 +
   1.809 +		# Package info.
   1.810 +		if [ -f "$wok/$pkg/receipt" ]; then
   1.811 +			pkg_info
   1.812 +		else
   1.813 +			if [ $(ls $wok/*$pkg*/receipt 2>/dev/null | wc -l) -eq 0 ]; then
   1.814 +				echo "<h2>Not Found</h2>"
   1.815 +				show_note e "The requested package <b>$pkg</b> was not found on this server."
   1.816 +			else
   1.817 +				# Search page
   1.818 +				echo "<section><h2>Package names matching “$pkg”</h2>"
   1.819 +				echo "<table><thead><tr><th>Name</th><th>Description</th><th>Category</th></tr></thead><tbody>"
   1.820 +				for i in $(cd $wok; ls *$pkg*/receipt); do
   1.821 +					pkg=$(dirname $i)
   1.822 +					unset SHORT_DESC CATEGORY
   1.823 +					. $wok/$pkg/receipt
   1.824 +					echo -n "<tr><td><a href="$base/$pkg">$pkg</a></td>"
   1.825 +					echo -n "<td>$SHORT_DESC</td><td>$CATEGORY</td></tr>"
   1.826 +				done
   1.827 +				echo '</tbody></table></section>'
   1.828 +				unset pkg
   1.829 +			fi
   1.830 +			page_footer
   1.831 +			exit 0
   1.832 +		fi
   1.833 +
   1.834 +		# Check for a log file and display summary if it exists.
   1.835 +		summary "$log"
   1.836 +
   1.837 +		# Display <Recook> button only for SliTaz web browser
   1.838 +		if [ -f "$log" ]; then
   1.839 +			case "$HTTP_USER_AGENT" in
   1.840 +				*SliTaz*)
   1.841 +					if [ -f $CACHE/cooker-request -a -n "$HTTP_REFERER" ]; then
   1.842 +						if grep -qs "^$pkg$" $CACHE/recook-packages; then
   1.843 +							show_note i "The package “$pkg” has been requested for recook"
   1.844 +						else
   1.845 +							echo "<a class='button' href='$base/?recook=${pkg//+/%2B}'>Recook $pkg</a>"
   1.846 +						fi
   1.847 +					fi
   1.848 +					;;
   1.849 +			esac
   1.850 +		fi
   1.851 +		;;
   1.852 +
   1.853 +	receipt)
   1.854 +		page_header
   1.855 +		pkg_info
   1.856 +		echo "<a class='button receipt' href='$base/$pkg/receipt'>receipt</a>"
   1.857 +		( cd $wok/$pkg; find stuff -type f 2>/dev/null ) | sort | \
   1.858 +		awk -vb="$base/$pkg" '{printf("<a class=\"button\" href=\"%s/%s\">%s</a>\n", b, $0, $0)}'
   1.859 +
   1.860 +		show_code bash < $wok/$pkg/receipt
   1.861 +		;;
   1.862 +
   1.863 +	stuff)
   1.864 +		page_header
   1.865 +		pkg_info
   1.866 +		file="$pkg/stuff/$arg"
   1.867 +		echo "<a class='button' href='$base/$pkg/receipt'>receipt</a>"
   1.868 +		( cd $wok/$pkg; find stuff -type f 2>/dev/null ) | sort | \
   1.869 +		awk -vb="$base/$pkg" -va="stuff/$arg" '{
   1.870 +			printf("<a class=\"button%s\" href=\"%s/%s\">%s</a>\n", a==$0 ? " receipt" : "", b, $0, $0)
   1.871 +		}'
   1.872 +
   1.873 +		if [ -f "$wok/$file" ]; then
   1.874 +			case $file in
   1.875 +				*.desktop|*.theme)   class="ini" ;;
   1.876 +				*.patch|*.diff|*.u)  class="diff" ;;
   1.877 +				*.sh)                class="bash" ;;
   1.878 +				*.conf*|*.ini)
   1.879 +					class="bash"
   1.880 +					[ -n "$(cut -c1 < $wok/$file | fgrep '[')" ] && class="ini"
   1.881 +					;;
   1.882 +				*.pl)           class="perl" ;;
   1.883 +				*.c|*.h|*.awk)  class="clike" ;;
   1.884 +				*.svg)          class="svg" ;;
   1.885 +				*Makefile*)     class="makefile" ;;
   1.886 +				*.po|*.pot)     class="bash" ;;
   1.887 +				*.css)          class="css" ;;
   1.888 +				*.htm|*.html)   class="html" ;;
   1.889 +				*.js)           class="js" ;;
   1.890 +				*.txt)          class="asciidoc" ;;
   1.891 +				*)
   1.892 +					case $(head -n1 $wok/$file) in
   1.893 +						*!/bin/sh*|*!/bin/bash*) class="bash" ;;
   1.894 +					esac
   1.895 +					if [ -z "$class" -a "$(head -n1 $wok/$file | cut -b1)" == '#' ]; then
   1.896 +						class="bash"
   1.897 +					fi
   1.898 +					if [ -z "$class" ]; then
   1.899 +						# Follow Busybox restrictions. Search for non-printable chars
   1.900 +						if [ $(tr -d '[:alnum:][:punct:][:blank:][:cntrl:]' < "$wok/$file" | wc -c) -gt 0 ]; then
   1.901 +							raw="true"
   1.902 +						fi
   1.903 +					fi
   1.904 +					;;
   1.905 +			esac
   1.906 +
   1.907 +			# Display image
   1.908 +			case $file in
   1.909 +				*.png|*.svg|*.jpg|*.jpeg|*.ico)
   1.910 +					echo "<img src='$base/$pkg/browse/stuff/$arg' style='display: block; max-width: 100%; margin: auto'/>"
   1.911 +					;;
   1.912 +			esac
   1.913 +
   1.914 +			# Display colored listing for all text-based documents (also for *.svg)
   1.915 +			case $file in
   1.916 +				*.png|*.jpg|*.jpeg|*.ico) ;;
   1.917 +				*)
   1.918 +					if [ -z "$raw" ]; then
   1.919 +						cat $wok/$file | show_code $class
   1.920 +					fi
   1.921 +					;;
   1.922 +			esac
   1.923 +
   1.924 +			# Display hex dump for binary files
   1.925 +			if [ -n "$raw" ]; then
   1.926 +				hexdump -C $wok/$file | show_code #| sed 's|^\([0-9a-f][0-9a-f]*\)|<span class="c2">\1</span>|'
   1.927 +			fi
   1.928 +		else
   1.929 +			show_note e "File “$file” absent!"
   1.930 +		fi
   1.931 +		;;
   1.932 +
   1.933 +	files)
   1.934 +		page_header
   1.935 +		pkg_info
   1.936 +
   1.937 +		packaged=$(mktemp)
   1.938 +
   1.939 +		# find main package
   1.940 +		wanted=$(. $wok/$pkg/receipt; echo $WANTED)
   1.941 +		main=${wanted:-$pkg}
   1.942 +		# identify splitted packages
   1.943 +		split="$main $(. $wok/$main/receipt; echo $SPLIT)"
   1.944 +		[ -d "$wok/$main-dev" ] && split="$split $main-dev"
   1.945 +		split="$(echo $split | tr ' ' '\n' | sort -u)"
   1.946 +		# finally we need the version
   1.947 +		ver=$(. $wok/$main/receipt; echo $VERSION$EXTRAVERSION)
   1.948 +
   1.949 +		for p in $split; do
   1.950 +			namever="$p-$ver"
   1.951 +			if [ -d "$wok/$p/taz/$p-$ver" ]; then
   1.952 +				indir=$p
   1.953 +			elif [ -d "$wok/$main/taz/$p-$ver" ]; then
   1.954 +				indir=$main
   1.955 +			fi
   1.956 +			dir="$wok/$indir/taz/$p-$ver/fs"
   1.957 +
   1.958 +			size=$(du -hs $dir | awk '{ sub(/\.0/, ""); print $1 }')
   1.959 +
   1.960 +			echo "<section><h3>Files of package “$namever” ($size):</h3>"
   1.961 +			echo -en '<pre class="files">\n<span class="underline">permissions·lnk·user    ·'
   1.962 +			echo -en 'group   ·     size·date &amp; time ·file name\n</span>'
   1.963 +			find $dir -not -type d -print0 | sort -z | xargs -0 ls -ld --color=always | \
   1.964 +			syntax_highlighter files | \
   1.965 +			sed "s|\([^>]*\)>/.*/fs\([^<]*\)\(<.*\)$|\1 href='$base/$indir/browse/taz/$p-$ver/fs\2'>\2\3|" | \
   1.966 +			awk 'BEGIN { FS="\""; }
   1.967 +				{ gsub("+", "%2B", $2); print; }'
   1.968 +			echo '</pre></section>'
   1.969 +			cat $wok/$indir/taz/$p-$ver/files.list >> $packaged
   1.970 +		done
   1.971 +
   1.972 +		# find repeatedly packaged files
   1.973 +		repeats="$(sort $packaged | uniq -d)"
   1.974 +		if [ -n "$repeats" ]; then
   1.975 +			echo -n '<section><h3>Repeatedly packaged files:</h3><pre class="files">'
   1.976 +			echo "$repeats" | sed 's|^|<span class="c11">!!!</span> |'
   1.977 +			echo "</pre></section>"
   1.978 +		fi
   1.979 +
   1.980 +		# find unpackaged files
   1.981 +		all_files=$(mktemp)
   1.982 +		cd $wok/$main/install; find ! -type d | sed 's|\.||' > $all_files
   1.983 +		orphans="$(sort $all_files $packaged | uniq -u)"
   1.984 +		if [ -n "$orphans" ]; then
   1.985 +			echo -n '<section><h3>Unpackaged files:</h3><pre class="files">'
   1.986 +			echo "$orphans" | awk '
   1.987 +			function tag(text, color) { printf("<span class=\"c%s1\">%s</span> %s\n", color, text, $0); }
   1.988 +			/\/perllocal.pod$/ || /\/\.packlist$/ || /\/share\/bash-completion\// { tag("---", 0); next }
   1.989 +			/\.pod$/  { tag("pod", 5); next }
   1.990 +			/\/share\/man\// { tag("man", 5); next }
   1.991 +			/\/share\/doc\// || /\/share\/gtk-doc\// || /\/share\/info\// || /\/share\/devhelp\// { tag("doc", 5); next }
   1.992 +			/\/share\/icons\// { tag("ico", 2); next }
   1.993 +			/\/share\/locale\// { tag("loc", 4); next }
   1.994 +			/\.h$/ || /\.a$/ || /\.la$/ || /\.pc$/ || /\/bin\/.*-config$/ { tag("dev", 3); next }
   1.995 +			{ tag("???", 1) }
   1.996 +			'
   1.997 +			echo '</pre></section>'
   1.998 +		fi
   1.999 +		;;
  1.1000 +
  1.1001 +	description)
  1.1002 +		page_header
  1.1003 +		pkg_info
  1.1004 +		desc="$WOK$REQUEST_URI.txt"
  1.1005 +		if [ -s "$desc" ]; then
  1.1006 +			echo '<div id="content2">'
  1.1007 +			if [ -n "$md2html" ]; then
  1.1008 +				$md2html $desc
  1.1009 +			else
  1.1010 +				show_code markdown < $desc
  1.1011 +			fi
  1.1012 +			echo '</div>'
  1.1013 +		else
  1.1014 +			show_note w "No description of $pkg"
  1.1015 +		fi
  1.1016 +		;;
  1.1017 +
  1.1018 +	log)
  1.1019 +		page_header
  1.1020 +		pkg_info
  1.1021 +		[ -z "$arg" ] && arg=$(stat -c %Y $LOGS/$pkg.log)
  1.1022 +
  1.1023 +		echo '<div class="btnList">'
  1.1024 +		acc='l'
  1.1025 +		while read log; do
  1.1026 +			timestamp=$(stat -c %Y $log)
  1.1027 +			class=''
  1.1028 +			if [ "$arg" == "$timestamp" ]; then
  1.1029 +				class=' log'
  1.1030 +				logfile="$log"
  1.1031 +			fi
  1.1032 +			echo -n "<a class='button$class' data-acc='$acc' accesskey='$acc' href='$base/$pkg/log/$timestamp'>"
  1.1033 +			echo "$(stat -c %y $log | cut -d: -f1,2)</a>"
  1.1034 +			case $acc in
  1.1035 +				l) acc=0;;
  1.1036 +				*) acc=$((acc+1));;
  1.1037 +			esac
  1.1038 +		done <<EOT
  1.1039 +$(find $LOGS -name "$pkg.log*" | sort)
  1.1040 +EOT
  1.1041 +		echo '</div>'
  1.1042 +
  1.1043 +		if [ -z "$logfile" ]; then
  1.1044 +			show_note e "Requested log is absent"
  1.1045 +			page_footer
  1.1046 +			exit 0
  1.1047 +		fi
  1.1048 +
  1.1049 +		# Define cook variables for syntax highlighter
  1.1050 +		if [ -s "$WOK/$pkg/receipt" ]; then
  1.1051 +			. "$WOK/$pkg/receipt"
  1.1052 +			_wok='/home/slitaz/wok'
  1.1053 +			_src="$_wok/$pkg/source/$PACKAGE-$VERSION"
  1.1054 +			_install="$_wok/$pkg/install"
  1.1055 +			_fs="$_wok/$pkg/taz/$PACKAGE-$VERSION/fs"
  1.1056 +			_stuff="$_wok/$pkg/stuff"
  1.1057 +		fi
  1.1058 +
  1.1059 +#		if [ ! -f "gzlog/$pkg.$arg" ]; then
  1.1060 +#			{
  1.1061 +#				summary "$logfile" links
  1.1062 +#
  1.1063 +#				syntax_highlighter log < $logfile | awk '
  1.1064 +#				BEGIN { print "<pre class=\"log\">"; }
  1.1065 +#				      { printf("<a name=\"l%d\" href=\"#l%d\">%5d</a>  %s\n", NR, NR, NR, $0); }
  1.1066 +#				END   { print "</pre>"; }
  1.1067 +#				'
  1.1068 +#
  1.1069 +#				page_footer
  1.1070 +#			} | gzip > gzlog/$pkg.$arg
  1.1071 +#		fi
  1.1072 +
  1.1073 +		blog=$(basename $logfile)
  1.1074 +		summary "$logfile" links
  1.1075 +
  1.1076 +		# disable next `sed` for the 'like2016' theme
  1.1077 +		theme=$(COOKIE theme); theme=${theme:-default}; [ "$theme" != 'like2016' ] && theme=''
  1.1078 +		cat $logfile | syntax_highlighter log | \
  1.1079 +		sed -e "/(pkg\/local$theme):/ s|: \([^<]*\)|<img src='$base/i/$blog/\1'> \1|" | \
  1.1080 +		awk '
  1.1081 +		BEGIN { print "<pre class=\"log\">"; }
  1.1082 +		      { printf("<a name=\"l%d\" href=\"#l%d\">%5d</a>  %s\n", NR, NR, NR, $0); }
  1.1083 +		END   { print "</pre>"; }
  1.1084 +		'
  1.1085 +		;;
  1.1086 +
  1.1087 +
  1.1088 +	man|doc|info)
  1.1089 +		page_header
  1.1090 +		pkg_info
  1.1091 +		echo '<div style="max-height: 6.4em; overflow: auto; padding: 0 4px">'
  1.1092 +
  1.1093 +		dir="wok/$pkg/install/usr/share/$cmd"
  1.1094 +		[ "$cmd" == 'doc' ] && dir="$dir wok/$pkg/install/usr/share/gtk-doc"
  1.1095 +		if [ "$cmd" == 'doc' -a -z "$arg" ]; then
  1.1096 +			try=$(for i in $dir; do find $i -name 'index.htm*'; done | sed q)
  1.1097 +			[ -n "$try" ] && arg="$try"
  1.1098 +		fi
  1.1099 +		while read i; do
  1.1100 +			[ -s "$i" ] || continue
  1.1101 +			case "$i" in
  1.1102 +				*.jp*g|*.png|*.gif|*.svg|*.css) continue
  1.1103 +			esac
  1.1104 +			i=${i#$dir/}
  1.1105 +			[ -n "$arg" ] || arg="$i"
  1.1106 +			class=''; [ "$arg" == "$i" ] && class=" doc"
  1.1107 +			case "$cmd" in
  1.1108 +				man)
  1.1109 +					case $i in
  1.1110 +						man*) lang='';;
  1.1111 +						*)    lang="${i%%/*}: ";;
  1.1112 +					esac
  1.1113 +					man=$(basename $i .gz)
  1.1114 +					echo "<a class='button$class' href='$base/$pkg/man/$i'>$lang${man%.*} (${man##*.})</a>"
  1.1115 +					;;
  1.1116 +				doc)
  1.1117 +					echo "<a class='button$class' href='$base/$pkg/doc/$i'>$(basename $i .gz)</a>"
  1.1118 +					;;
  1.1119 +				info)
  1.1120 +					info=$(basename $i)
  1.1121 +					echo "<a class='button$class' href='$base/$pkg/info/$i#Top'>${info/.info/}</a>"
  1.1122 +					;;
  1.1123 +			esac
  1.1124 +		done <<EOT
  1.1125 +$(for i in $dir; do find $i -type f; done | sort)
  1.1126 +EOT
  1.1127 +		echo '</div>'
  1.1128 +
  1.1129 +		[ -f "$arg" ] || arg="$dir/$arg"
  1.1130 +		if [ -f "$arg" ]; then
  1.1131 +			tmp="$(mktemp)"
  1.1132 +			docat "$arg" > $tmp
  1.1133 +			[ -s "$tmp" ] &&
  1.1134 +			case "$cmd" in
  1.1135 +				info)
  1.1136 +					echo '<div id="content2" class="texinfo"><pre class="first">'
  1.1137 +					info2html < "$tmp"
  1.1138 +					echo '</pre></div>'
  1.1139 +					;;
  1.1140 +				doc)
  1.1141 +					case "$arg" in
  1.1142 +						*.sgml|*.devhelp2) class='xml';;
  1.1143 +						*.py)       class='python';; # pycurl package
  1.1144 +						*.css)      class='css';;
  1.1145 +						*)          class='asciidoc';;
  1.1146 +					esac
  1.1147 +					case "$arg" in
  1.1148 +						*.htm*)
  1.1149 +							case $arg in
  1.1150 +								wok/*) page="${arg#wok/}"; page="$base/$pkg/browse/${page#*/}";;
  1.1151 +								*)     page="$base/$pkg/browse/install/usr/share/$cmd/$arg";;
  1.1152 +							esac
  1.1153 +							# make the iframe height so long to contain it's content without scrollbar
  1.1154 +							echo "<iframe id='idoc' src='$page' width='100%' onload='resizeIframe(this)'></iframe>"
  1.1155 +							;;
  1.1156 +						*.pdf)
  1.1157 +							case $arg in
  1.1158 +								wok/*) page="${arg#wok/}"; page="$base/$pkg/browse/${page#*/}";;
  1.1159 +								*)     page="$base/$pkg/browse/install/usr/share/$cmd/$arg";;
  1.1160 +							esac
  1.1161 +							cat <<EOT
  1.1162 +<object id="idoc" data="$page" width="100%" height="100%" type="application/pdf" style="min-height: 600px">
  1.1163 +	$(show_note w "Missing PDF plugin.<br/>Get the file <a href="$page">$(basename "$page")</a>.")
  1.1164 +</object>
  1.1165 +EOT
  1.1166 +							;;
  1.1167 +						*)
  1.1168 +							show_code $class < "$tmp"
  1.1169 +							;;
  1.1170 +					esac
  1.1171 +					;;
  1.1172 +				man)
  1.1173 +					#export TEXTDOMAIN='man2html'
  1.1174 +					echo "<div id='content2'>"
  1.1175 +
  1.1176 +					html=$(./man2html "$tmp" | sed -e '1,/<header>/d' -e '/<footer>/,$d' \
  1.1177 +					-e 's|<a href="file:///[^>]*>\([^<]*\)</a>|\1|g' \
  1.1178 +					-e 's|<a href="?[1-9]\+[^>]*>\([^<]*\)</a>|\1|g')
  1.1179 +
  1.1180 +					if [ -n "$(echo "$html" | fgrep 'The requested file /tmp/tmp.')" ]; then
  1.1181 +						# Process the pre-formatted man-cat page
  1.1182 +						echo '<pre>'
  1.1183 +						sed '
  1.1184 +							s|M-bM-^@M-^S|—|g;
  1.1185 +							s|M-bM-^@M-^\\|<b>|g;
  1.1186 +							s|M-bM-^@M-^]|</b>|g
  1.1187 +							s|M-bM-^@M-^X|<u>|g;
  1.1188 +							s|M-bM-^@M-^Y|</u>|g;
  1.1189 +							s|M-BM-||g;
  1.1190 +							' "$tmp"
  1.1191 +						echo '</pre>'
  1.1192 +					else
  1.1193 +						echo "$html"
  1.1194 +					fi
  1.1195 +					echo "</div>"
  1.1196 +					;;
  1.1197 +			esac
  1.1198 +			rm -f $tmp
  1.1199 +		else
  1.1200 +			show_note e "File “$arg” not exists!"
  1.1201 +		fi
  1.1202 +		;;
  1.1203 +
  1.1204 +esac
  1.1205 +
  1.1206 +
  1.1207 +page_footer
  1.1208 +exit 0