1e6adcc7d14492bd8c354473678788aaa3de8b1c
[cwebfiles.git] / static / index.html
1 <!DOCTYPE html>
2 <html>
3   <head>
4     <script>
5 function hex(str) {
6   var res = "";
7   var achar = 'a'.charCodeAt(0)
8   for (var i=0; i<str.length; i++) {
9     var c = str.charCodeAt(i)
10     res += String.fromCharCode((c>>4)+achar) + String.fromCharCode((c&0xf)+achar)
11   }
12   return res
13 }
14
15 function dehex(str) {
16   var res = ""
17   var achar = 'a'.charCodeAt(0)
18   for (var i=0; i<str.length; i+=2) {
19     var c1 = str.charCodeAt(i)-achar, c2 = str.charCodeAt(i+1)-achar
20     res += String.fromCharCode((c1<<4)+c2)
21   }
22   return res
23 }
24
25 function cgireq(script, qs, body, cb) {
26   var req = new XMLHttpRequest()
27   req.open((body!=null)?'POST':'GET', '/cgi-bin/cwebfiles/'+script+(qs?'?'+qs:''), !!cb)
28   if (cb) {
29     req.onloadend = function() {
30       cb(req.status, req.responseText)
31     }
32   }
33   req.send(body)
34   if (!cb) {
35     return {status: req.status, data: req.responseText}
36   }
37 }
38
39 function login(user, pass, cb) {
40   return cgireq('login', null, user+':'+pass, cb)
41 }
42
43 function listdir(path, cb) {
44   cgireq('listdir', hex(path), null, function(status, data) {
45     if (status != 200) return cb(status, data, null)
46     var listing = data.split('\n').filter(function(line) {
47       return line.trim().length > 0
48     }).map(function(line) {
49       var parts = line.split(' ')
50       return {name: dehex(parts[0]), size: parseInt(parts[1]), mode: parseInt(parts[2])}
51     })
52     cb(status, data, listing)
53   })
54 }
55
56 var S_IFMT = parseInt("0170000",8) // bit mask for the file type bit fields
57 var S_IFSOCK = parseInt("0140000",8) // socket
58 var S_IFLNK = parseInt("0120000",8) // symbolic link
59 var S_IFREG = parseInt("0100000",8) // regular file
60 var S_IFBLK = parseInt("0060000",8) // block device
61 var S_IFDIR = parseInt("0040000",8) // directory
62 var S_IFCHR = parseInt("0020000",8) // character device
63 var S_IFIFO = parseInt("0010000",8) // FIFO
64
65 var S_ISUID = parseInt("0004000",8) // set UID bit
66 var S_ISGID = parseInt("0002000",8) // set-group-ID bit (see below)
67 var S_ISVTX = parseInt("0001000",8) // sticky bit (see below)
68
69 var S_IRWXU = parseInt("00700",8) // mask for file owner permissions
70 var S_IRUSR = parseInt("00400",8) // owner has read permission
71 var S_IWUSR = parseInt("00200",8) // owner has write permission
72 var S_IXUSR = parseInt("00100",8) // owner has execute permission
73 var S_IRWXG = parseInt("00070",8) // mask for group permissions
74 var S_IRGRP = parseInt("00040",8) // group has read permission
75 var S_IWGRP = parseInt("00020",8) // group has write permission
76 var S_IXGRP = parseInt("00010",8) // group has execute permission
77 var S_IRWXO = parseInt("00007",8) // mask for permissions for others (not in group)
78 var S_IROTH = parseInt("00004",8) // others have read permission
79 var S_IWOTH = parseInt("00002",8) // others have write permission
80 var S_IXOTH = parseInt("00001",8) // others have execute permission
81
82
83 var typechars = {}
84 typechars[S_IFSOCK] = 's'
85 typechars[S_IFLNK] = 'l'
86 typechars[S_IFREG] = '-'
87 typechars[S_IFBLK] = 'b'
88 typechars[S_IFDIR] = 'd'
89 typechars[S_IFCHR] = 'c'
90 typechars[S_IFIFO] = 'p'
91
92 function escapehtml(text) {
93   return text.replace(/&/g, '&amp;')
94               .replace(/</g, '&lt;')
95               .replace(/>/g, '&gt;')
96               .replace(/"/g, '&quot;')
97 }
98
99 var loc = '/'
100
101 function dive(hexedname) { __listdir(loc + dehex(hexedname) + '/'); }
102
103 function format_entry(entry) {
104   var modeline = ""
105   modeline += typechars[entry.mode&S_IFMT]
106   modeline += (entry.mode&S_IRUSR) ? 'r' : '-'
107   modeline += (entry.mode&S_IWUSR) ? 'w' : '-'
108   modeline += (entry.mode&S_ISUID) ? ((entry.mode&S_IXUSR) ? 's' : 'S') : ((entry.mode&S_IXUSR) ? 'x' : '-')
109   modeline += (entry.mode&S_IRGRP) ? 'r' : '-'
110   modeline += (entry.mode&S_IWGRP) ? 'w' : '-'
111   modeline += (entry.mode&S_ISGID) ? ((entry.mode&S_IXGRP) ? 's' : 'S') : ((entry.mode&S_IXGRP) ? 'x' : '-')
112   modeline += (entry.mode&S_IROTH) ? 'r' : '-'
113   modeline += (entry.mode&S_IWOTH) ? 'w' : '-'
114   modeline += (entry.mode&S_ISVTX) ? ((entry.mode&S_IXOTH) ? 's' : 'S') : ((entry.mode&S_IXOTH) ? 'x' : '-')
115   
116   var markred = (entry.mode&(S_ISUID|S_ISGID))
117   if (markred) {
118     modeline = '<span style="color: red">'+modeline+'</span>'
119   }
120   
121   var showsize = (entry.mode&S_IFMT) == S_IFREG
122   
123   var escaped_name = escapehtml(entry.name)
124   
125   var clickcode = ''
126   if ((entry.mode&S_IFMT) == S_IFDIR) clickcode = "dive('"+hex(entry.name)+"')"
127   
128   return '<tr><td>'+modeline+'</td><td '+(clickcode?'class="clickme" ':'')+'onclick="'+clickcode+'">'+escaped_name+'</td><td>'+(showsize?entry.size:'')+'</td></tr>'
129 }
130
131 function renderloc(path) {
132   var parts = path.split('/')
133   var curpath = '/';
134   var linkparts = parts.map(function(dir, i) {
135     var esc = (i==0) ? 'main directory' : escapehtml(dir)
136     if (i != 0) curpath += dir + '/'
137     var hexpath = hex(curpath)
138     var clickcode = "__listdir(dehex('"+hexpath+"'))"
139     return '<span class="clickme" onclick="'+clickcode+'">'+esc+'</span>'
140   })
141   return '<div id="loc">'+linkparts.join(' / ')+'</div>'
142 }
143
144 function __listdir(path) {
145   listdir(path, function(status, err, listing) {
146     if (status != 200) {
147       alert(err)
148       return
149     }
150     loc = path
151     var body = document.getElementsByTagName('body')[0]
152     body.innerHTML = renderloc(path)
153                    + '<table><thead><tr><th>mode</th><th>name</th><th>size</th></tr></thead><tbody>'+listing.filter(function(e) {
154       return e.name != '.' && e.name != '..'
155     }).map(function(e) {
156       return format_entry(e)
157     }).join('')+'</tbody></table>'
158     /*listing.forEach(function(e) {
159       //e.mode = e.mode.toString(8)
160       console.log(Object.keys(e).map(function(k) {
161         return k+':'+e[k]
162       }).join(', '))
163     })*/
164   })
165 }
166
167
168     </script>
169     <style>
170       .clickme {
171         text-decoration: underline;
172         color: blue;
173         cursor: pointer;
174       }
175     </style>
176   </head>
177   <body onload="__listdir('/')">
178   </body>
179 </html>