*.deb extraction utility (also *.dsc by wrapping “dpkg-source -x”)
[shellsnippets/shellsnippets.git] / mksh / annex.cgi
1 #!/bin/mksh
2 # $MirOS: src/share/misc/licence.template,v 1.28 2008/11/14 15:33:44 tg Rel $
3 #-
4 # Copyright © 2012
5 #       Thorsten Glaser <tg@mirbsd.org>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un‐
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person’s immediate fault when using the work as intended.
21
22 export LC_ALL=C.UTF-8
23 unset LANGUAGE
24
25 [[ $1 = -s ]] || if [[ $REQUEST_METHOD = GET && $HTTPS = on && \
26     -n $REMOTE_USER && $REMOTE_USER = "$AUTHENTICATE_UID" ]]; then
27         [[ $PATH_INFO = /* ]] && \
28             exec sudo -u "$REMOTE_USER" "$(realpath "$0")" -s "$PATH_INFO" \
29             "$QUERY_STRING"
30         print Status: 301 Redirect
31         print Location: $SCRIPT_NAME/
32         print
33         print Please add the trailing slash after the .cgi
34         exit 1
35 else
36         print Content-type: text/plain\; charset=UTF-8
37         print
38         print Error in request arguments.
39         exit 1
40 fi
41
42 me=$(realpath "$0")
43 cd $(dirname "$(dirname "$me")")
44 basedir=$(realpath .)
45 shift
46 pi=$1
47 QUERY_STRING=$2
48
49 function qsdecode {
50         local _x=$1
51
52         _x=${_x//\\/\\\\}
53         print -- "${_x//[%]/\\x}"
54 }
55
56 function qsparse {
57         local _saveIFS _q _s _k _v _a
58
59         # no 'key=value' at all: make q be everything
60         if [[ $QUERY_STRING != *=* ]]; then
61                 qs_q=$(qsdecode "$QUERY_STRING")
62                 qskeys=(q)
63                 return
64         fi
65
66         _saveIFS=$IFS
67         IFS=';&'
68         set -A _q -- $QUERY_STRING
69         IFS=$_saveIFS
70
71         set -A qskeys
72         for _s in "${_q[@]}"; do
73                 # skip not 'key=value' parts
74                 [[ $_s = *=* ]] || continue
75
76                 _k=$(qsdecode "${_s%%=*}")
77                 _v=$(qsdecode "${_s#*=}")
78
79                 if [[ $_k = *'[]' ]]; then
80                         _a=1
81                         _k=${_k%??}
82                 else
83                         _a=0
84                 fi
85
86                 # limit keys to alphanumeric and underscore
87                 # as they must fit as part of an mksh variable
88                 [[ $_k = +([0-9A-Za-z_]) ]] || continue
89
90                 if (( _a )); then
91                         in_array qskeys $_k || eval set -A qs_$k
92                         nameref _A=qs_$_k
93                         _A+=("$_v")
94                 else
95                         # eval is evil, but… as long as we don’t have
96                         # associative arrays in mksh… this works
97                         eval qs_$_k=\$_v
98                 fi
99                 in_array qskeys $_k || qskeys+=("$_k")
100         done
101 }
102
103 function in_array {
104         nameref _arr=$1
105         local _val=$2 _x
106
107         for _x in "${_arr[@]}"; do
108                 [[ $_x = "$_val" ]] && return 0
109         done
110         return 1
111 }
112
113 qsparse
114
115 pi=${pi##*(/)}
116 pi=${pi%%*(/)}
117
118 function e403 {
119         print Status: 403 Forbidden
120         print Content-type: text/plain\; charset=UTF-8
121         print
122         print Du kumms hier nisch rein!
123         exit 1
124 }
125
126 if [[ -n $pi ]]; then
127         i=$(realpath "$pi")
128         [[ -n $i && $i = "$basedir"/* ]] || e403
129 fi
130
131 [[ -e ${pi:-.} && -r ${pi:-.} ]] || e403
132
133 [[ -n $pi ]] && if [[ ! -d $pi ]]; then
134         if in_array qskeys type; then
135                 ct=$qs_type
136         else
137                 ct=$(file -biL "$pi")
138         fi
139         print -r Content-type: "$ct"
140         print
141         cat "$pi"
142         exit 0
143 fi
144
145 [[ -n $pi ]] && cd "$pi"
146 set -A dirs
147 set -A files
148 for i in *; do
149         [[ -e $i && -r $i ]] || continue
150         if [[ -d $i ]]; then
151                 dirs+=("$i")
152         else
153                 files+=("$i")
154         fi
155 done
156
157 function h {
158         typeset x="$*"
159
160         x=${x//'&'/"&amp;"}
161         x=${x//'<'/"&lt;"}
162         x=${x//'>'/"&gt;"}
163
164         print -r -- "$x"
165 }
166
167 cat <<EOF
168 Content-type: text/html; charset=UTF-8
169
170 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
171  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
172 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
173  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
174  <title>$pi/ – Index for nik’s Annex</title>
175 </head><body>
176 <h1>Index of $pi/ in nik’s Annex</h1>
177 EOF
178
179 if (( !${#dirs[*]} && !${#files[*]} )); then
180         print '<p>No content found.</p>'
181 else
182         print '<table width="100%" border="0">'
183         for i in "${dirs[@]}"; do
184                 print "<tr><td align=\"right\" style=\"width:20;\">[DIR]</td><td><a href=\"$(h "$i")/\">$(h "$i")/</a></td></tr>"
185         done
186         for i in "${files[@]}"; do
187                 sz=$(stat -Lc '%s' "$i")
188                 if (( ${#sz} < 10 )); then
189                         if (( sz >= 1048576 )); then
190                                 if (( sz > 210000000 )); then
191                                         sz=$(( (sz + 524288) / 1048576)) MiB
192                                 else
193                                         (( sz = (sz * 10 + 524288) / 1048576 ))
194                                         x=${sz%?}
195                                         sz=$x.${sz#$x} MiB
196                                 fi
197                         elif (( sz >= 1024 )); then
198                                 sz=$(( (sz * 100 + 512) / 1024))
199                                 x=${sz%??}
200                                 sz=$x.${sz#$x} KiB
201                         fi
202                 else
203                         sz=$(bc -q <<<$'scale=2\n'"$sz/1073741824") GiB
204                 fi
205                 print "<tr><td align=\"right\" style=\"width:20;\">$sz</td><td><a href=\"$(h "$i")\">$(h "$i")</a> (<a href=\"$(h "$i")?type=application/octet-stream\">download</a>)</td></tr>"
206         done
207         print '</table>'
208 fi
209
210 print '</body></html>'
211 exit 0