Permit sorting of files in automatic directory listings by various factors.

This commit is contained in:
Solderpunk 2020-06-27 18:52:29 +02:00
parent 6da5ec79dd
commit 3f98a9edf1
3 changed files with 45 additions and 15 deletions

View File

@ -92,3 +92,5 @@ The following options can be set in `/etc/molly.conf`:
* `LogPath`: Path to log file (default value `molly.log`). Note that
all intermediate directories must exist, Molly Brown won't create
them for you.
* `DirectorySort`: A string specifying how to sort files in automatically generated directory listings. Must be one of "Name", "Size" or "Time" (default value "Name").
* `DirectoryReverse`: Boolean, if true automatically generated directory listings will list files in descending order of whatever `DirectorySort` is set to (default value false).

View File

@ -1,23 +1,26 @@
package main
import (
"errors"
"github.com/BurntSushi/toml"
)
type Config struct {
Port int
Hostname string
CertPath string
KeyPath string
DocBase string
HomeDocBase string
GeminiExt string
DefaultLang string
LogPath string
TempRedirects map[string]string
PermRedirects map[string]string
CGIPaths []string
SCGIPaths map[string]string
Port int
Hostname string
CertPath string
KeyPath string
DocBase string
HomeDocBase string
GeminiExt string
DefaultLang string
LogPath string
TempRedirects map[string]string
PermRedirects map[string]string
CGIPaths []string
SCGIPaths map[string]string
DirectorySort string
DirectoryReverse bool
}
type MollyFile struct {
@ -43,6 +46,7 @@ func getConfig(filename string) (Config, error) {
config.PermRedirects = make(map[string]string)
config.CGIPaths = make([]string, 0)
config.SCGIPaths = make(map[string]string)
config.DirectorySort = "Name"
// Return defaults if no filename given
if filename == "" {
@ -54,5 +58,13 @@ func getConfig(filename string) (Config, error) {
if err != nil {
return config, err
}
// Validate pseudo-enums
switch config.DirectorySort {
case "Name", "Size", "Time":
default:
return config, errors.New("Invalid DirectorySort value.")
}
return config, nil
}

View File

@ -14,6 +14,7 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
)
@ -154,7 +155,7 @@ func handleGeminiRequest(conn net.Conn, config Config, logEntries chan LogEntry)
} else {
conn.Write([]byte("20 text/gemini\r\n"))
log.Status = 20
conn.Write([]byte(generateDirectoryListing(URL, path)))
conn.Write([]byte(generateDirectoryListing(URL, path, config)))
}
return
}
@ -263,7 +264,7 @@ func parseMollyFiles(path string, info os.FileInfo, config *Config) {
}
func generateDirectoryListing(URL *url.URL, path string) string {
func generateDirectoryListing(URL *url.URL, path string, config Config) string {
var listing string
files, err := ioutil.ReadDir(path)
if err != nil {
@ -287,6 +288,21 @@ func generateDirectoryListing(URL *url.URL, path string) string {
up := filepath.Dir(URL.Path)
listing += fmt.Sprintf("=> %s %s\n", up, "..")
}
// Sort files
sort.SliceStable(files, func(i, j int) bool {
if config.DirectoryReverse {
i, j = j, i
}
if config.DirectorySort == "Name" {
return files[i].Name() < files[j].Name()
} else if config.DirectorySort == "Size" {
return files[i].Size() < files[j].Size()
} else if config.DirectorySort == "Time" {
return files[i].ModTime().Before(files[j].ModTime())
}
return false // Should not happen
})
// Format lines
for _, file := range files {
// Skip dotfiles
if strings.HasPrefix(file.Name(), ".") {