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