package main
import (
"html"
"log"
"net/http"
"net/url"
"os"
"sort"
"strings"
"time"
"github.com/dustin/go-humanize"
"github.com/spf13/afero"
)
func (r *wfmRequest) listFiles(hi string) {
i := icons(r.modern)
d, err := afero.ReadDir(r.fs, r.uDir)
if err != nil {
htErr(r.w, "Unable to read directory", err)
return
}
sl := []string{}
sortFiles(d, &sl, r.eSort)
header(r.w, r.uDir, r.eSort, "")
toolbars(r.w, r.uDir, r.userName, sl, i, r.rwAccess)
qeDir := strings.ReplaceAll(url.PathEscape(r.uDir), `%2F`, `/`)
z := 0
var total uint64
// List Directories First
for _, f := range d {
var ldir bool
var li string
if f.Mode()&os.ModeSymlink == os.ModeSymlink {
ls, err := r.fs.Stat(r.uDir + "/" + f.Name())
if err != nil {
continue
}
ldir = ls.IsDir()
li = i["li"]
}
if !f.IsDir() && !ldir {
continue
}
if !*showDot && f.Name()[0:1] == "." {
continue
}
if f.Name() == hi {
r.w.Write([]byte(`
`))
} else if z%2 == 0 {
r.w.Write([]byte(` `))
} else {
r.w.Write([]byte(` `))
}
z++
qeFile := url.PathEscape(f.Name())
heFile := html.EscapeString(f.Name())
nUrl, err := url.JoinPath(wfmPfx, qeDir, qeFile)
if err != nil {
log.Printf("Unable to parse url: %v", err)
}
if r.eSort != "" {
nUrl += `?sort=` + r.eSort
}
r.w.Write([]byte(`
` + i["di"] + heFile + `/ ` + li + `
(` + humanize.Time(f.ModTime()) + `) ` + f.ModTime().Format(time.Stamp) + `
`))
if r.rwAccess {
r.w.Write([]byte(`
` + i["re"] + `
` + i["mv"] + `
` + i["rm"] + `
`))
}
r.w.Write([]byte(`
`))
}
// List Files
for _, f := range d {
var ldir bool
var li string
if f.Mode()&os.ModeSymlink == os.ModeSymlink {
ls, err := r.fs.Stat(r.uDir + "/" + f.Name())
if err != nil {
continue
}
ldir = ls.IsDir()
li = i["li"]
}
if f.IsDir() || ldir {
continue
}
if !*showDot && f.Name()[0:1] == "." {
continue
}
if f.Name() == hi {
r.w.Write([]byte(``))
} else if z%2 == 0 {
r.w.Write([]byte(` `))
} else {
r.w.Write([]byte(` `))
}
z++
qeFile := url.PathEscape(f.Name())
heFile := html.EscapeString(f.Name())
nUrl, err := url.JoinPath(wfmPfx, qeDir, qeFile)
if err != nil {
log.Printf("Unable to parse url: %v", err)
}
r.w.Write([]byte(`
` + fileIcon(qeFile, r.modern) + ` ` + heFile + ` ` + li + `
` + humanize.Bytes(uint64(f.Size())) + `
(` + humanize.Time(f.ModTime()) + `) ` + f.ModTime().Format(time.Stamp) + `
` + i["dn"] + `
`))
if r.rwAccess {
r.w.Write([]byte(`
` + i["ed"] + `
` + i["re"] + `
` + i["mv"] + `
` + i["rm"] + `
`))
}
r.w.Write([]byte(`
`))
total = total + uint64(f.Size())
}
// Footer
r.w.Write([]byte(`Total ` +
humanize.Bytes(total) + ` ` + "\n\t\n"))
footer(r.w)
}
func toolbars(w http.ResponseWriter, uDir, user string, sl []string, i map[string]string, rw bool) {
eDir := html.EscapeString(uDir)
qeDir := url.PathEscape(uDir)
// Topbar
w.Write([]byte(`
`))
// Toolbar
w.Write([]byte(`
`))
// Sortby and File List Header
w.Write([]byte(`
` + sl[1] + `
` + sl[3] + `
` + sl[5] + `
`))
}
func sortFiles(f []os.FileInfo, l *[]string, by string) {
switch by {
// size
case "sa":
sort.Slice(f, func(i, j int) bool {
return f[i].Size() < f[j].Size()
})
*l = []string{"na", "Name", "sd", "v Size", "ta", "Time Modified"}
return
case "sd":
sort.Slice(f, func(i, j int) bool {
return f[i].Size() > f[j].Size()
})
*l = []string{"na", "Name", "sa", "^ Size", "ta", "Time Modified"}
return
// time
case "ta":
sort.Slice(f, func(i, j int) bool {
return f[i].ModTime().Before(f[j].ModTime())
})
*l = []string{"na", "Name", "sa", "Size", "td", "v Time Modified"}
return
case "td":
sort.Slice(f, func(i, j int) bool {
return f[i].ModTime().After(f[j].ModTime())
})
*l = []string{"na", "Name", "sa", "Size", "ta", "^ Time Modified"}
return
// name
case "nd":
sort.Slice(f, func(i, j int) bool {
return f[i].Name() > f[j].Name()
})
*l = []string{"na", "^ Name", "sa", "Size", "ta", "Time Modified"}
return
default:
*l = []string{"nd", "v Name", "sa", "Size", "ta", "Time Modified"}
return
}
}
func icons(b bool) map[string]string {
if b {
return map[string]string{
"fi": "🗒 ",
"di": "📂 ",
"li": " 🔗 ",
"rm": "❌",
"mv": "🚚",
"re": "💬",
"ed": "📝",
"dn": "💾",
"tcd": "🍱 ",
"tup": "🔺 ",
"tho": "🏠 ",
"tre": "🌀 ",
"trm": "❌ ",
"tmv": "🚚 ",
"tln": "🌐 ",
"tfi": "📒 ",
"tdi": "📂 ",
"tul": "🚀 ",
"tid": "🎫 ",
"tve": "🧰 ",
}
}
return map[string]string{
"fi": " ",
"di": " ",
"li": " (link);",
"rm": "[rm]",
"mv": "[mv]",
"re": "[re]",
"ed": "[ed]",
"dn": "[dn]",
"tup": "^ ",
"tho": "~ ",
"tre": "® ",
"tid": "User: ",
"tve": "WFM ",
}
}
func fileIcon(f string, m bool) string {
if !m {
return "·"
}
s := strings.Split(f, ".")
switch strings.ToLower(s[len(s)-1]) {
case "iso", "udf":
return "💿"
case "mp4", "mov", "qt", "avi", "mpg", "mpeg", "mkv":
return "🎬"
case "gif", "png", "jpg", "jpeg", "ico", "webp", "bmp", "tif", "tiff", "heif", "heic":
return "🖼"
case "deb", "rpm", "dpkg", "apk", "msi", "pkg":
return "🎁"
case "zip", "rar", "7z", "z", "gz", "bz2", "xz", "lz", "tgz", "tbz", "txz", "arj", "lha", "tar":
return "📦"
case "imd", "img", "raw", "dd", "tap", "dsk", "dmg":
return "💾"
case "txt", "log", "csv", "md", "mhtml", "html", "htm", "cfg", "conf", "ini", "json", "xml":
return "📄"
case "pdf", "ps", "doc", "docx", "xls", "xlsx", "rtf":
return "📚"
case "url", "desktop", "webloc":
return "🌐"
}
return "📒"
}