summaryrefslogtreecommitdiff
path: root/gopher
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-09-07 12:36:17 -0600
committertjpcc <tjp@ctrl-c.club>2023-09-07 12:36:17 -0600
commit38ff3807b3b97da22006b5bdcf03fdfaaa4b0582 (patch)
tree2b66d01de970a14bbf6d9a29acb3a1499c82f9e7 /gopher
parent9330d8546fff5e0397b4eec1a24bf37277a6b745 (diff)
all the gopher CGI handlers to support gophernicus behaviorsv1.3.0
Diffstat (limited to 'gopher')
-rw-r--r--gopher/gophermap/extended.go47
-rw-r--r--gopher/gophermap/extended_test.go6
-rw-r--r--gopher/gophermap/listdir.go91
-rw-r--r--gopher/gophermap/testdata/customlist_output.gophermap4
-rw-r--r--gopher/gophermap/testdata/file4.txt (renamed from gopher/gophermap/testdata/file4)0
-rw-r--r--gopher/gophermap/testdata/subdir/gophertag1
-rw-r--r--gopher/gophermap/testdata/subdir2/gophermap1
-rw-r--r--gopher/response.go2
8 files changed, 91 insertions, 61 deletions
diff --git a/gopher/gophermap/extended.go b/gopher/gophermap/extended.go
index d9fedd0..a0360fc 100644
--- a/gopher/gophermap/extended.go
+++ b/gopher/gophermap/extended.go
@@ -7,10 +7,12 @@ import (
"net/url"
"os"
"path/filepath"
+ "sort"
"strconv"
"strings"
"tildegit.org/tjp/sliderule/gopher"
+ "tildegit.org/tjp/sliderule/internal"
"tildegit.org/tjp/sliderule/internal/types"
)
@@ -139,6 +141,8 @@ const (
UserListType types.Status = '~'
// VHostListType generates a listing of virtual hosts.
+ //
+ // It is not supported in sliderule.
VHostListType types.Status = '%'
// InclusionType causes another gophermap to be included at this location.
@@ -151,8 +155,16 @@ const (
EndDocType types.Status = '.'
)
+type FileSystemSettings struct {
+ ParseExtended bool
+ Exec bool
+ ListUsers bool
+ DirMaps []string
+ DirTag string
+}
+
// Compatible builds a standards-compliant gophermap from the current extended menu.
-func (edoc ExtendedMapDocument) Compatible(cwd string) (gopher.MapDocument, string, error) {
+func (edoc ExtendedMapDocument) Compatible(cwd string, settings FileSystemSettings) (gopher.MapDocument, string, error) {
doc := gopher.MapDocument{}
title := ""
@@ -172,9 +184,32 @@ func (edoc ExtendedMapDocument) Compatible(cwd string) (gopher.MapDocument, stri
return nil, "", InvalidLine(num)
}
extensions[from] = types.Status(to[0])
- case UserListType: //TODO
- return nil, "", errors.New("User listings '~' are not supported")
- case VHostListType: //TODO
+ case UserListType:
+ if !settings.ListUsers {
+ doc = append(doc, gopher.MapItem{
+ Type: gopher.InfoMessageType,
+ Display: "~",
+ Selector: edoc.Location.Path,
+ Hostname: edoc.Location.Hostname(),
+ Port: edoc.Location.Port(),
+ })
+ }
+
+ users, err := internal.ListUsersWithHomeSubdir("public_gopher", 4)
+ if err != nil {
+ return nil, "", err
+ }
+ sort.Strings(users)
+ for _, user := range users {
+ doc = append(doc, gopher.MapItem{
+ Type: gopher.MenuType,
+ Display: "~" + user,
+ Selector: "/~" + user,
+ Hostname: edoc.Location.Hostname(),
+ Port: edoc.Location.Port(),
+ })
+ }
+ case VHostListType:
return nil, "", errors.New("Virtual host listings '%' are not supported")
case InclusionType:
location := filepath.Join(cwd, item.Selector)
@@ -183,13 +218,13 @@ func (edoc ExtendedMapDocument) Compatible(cwd string) (gopher.MapDocument, stri
return nil, "", err
}
- lines, _, err := subEdoc.Compatible(filepath.Dir(location))
+ lines, _, err := subEdoc.Compatible(filepath.Dir(location), settings)
if err != nil {
return nil, "", err
}
doc = append(doc, lines...)
case DirListType:
- dirlist, err := listDir(cwd, edoc.Location, hidden, extensions)
+ dirlist, err := listDir(cwd, edoc.Location, settings, hidden, extensions)
if err != nil {
return nil, "", err
}
diff --git a/gopher/gophermap/extended_test.go b/gopher/gophermap/extended_test.go
index e956df1..2d9e9b1 100644
--- a/gopher/gophermap/extended_test.go
+++ b/gopher/gophermap/extended_test.go
@@ -31,7 +31,11 @@ func TestExtendedDoc(t *testing.T) {
t.Fatal(err)
}
- doc, _, err := edoc.Compatible("testdata")
+ doc, _, err := edoc.Compatible("testdata", FileSystemSettings{
+ ParseExtended: true,
+ DirMaps: []string{"gophermap"},
+ DirTag: "gophertag",
+ })
if err != nil {
t.Fatal(err)
}
diff --git a/gopher/gophermap/listdir.go b/gopher/gophermap/listdir.go
index 8d66277..a2c5214 100644
--- a/gopher/gophermap/listdir.go
+++ b/gopher/gophermap/listdir.go
@@ -6,6 +6,7 @@ import (
"os"
"path"
"path/filepath"
+ "slices"
"strings"
"tildegit.org/tjp/sliderule/gopher"
@@ -13,11 +14,11 @@ import (
)
// ListDir builds a gopher menu representing the contents of a directory.
-func ListDir(dir string, location *url.URL) (gopher.MapDocument, error) {
- return listDir(dir, location, nil, nil)
+func ListDir(dir string, location *url.URL, settings FileSystemSettings) (gopher.MapDocument, error) {
+ return listDir(dir, location, settings, nil, nil)
}
-func listDir(dir string, location *url.URL, hidden map[string]struct{}, extensions map[string]types.Status) (gopher.MapDocument, error) {
+func listDir(dir string, location *url.URL, settings FileSystemSettings, hidden map[string]struct{}, extensions map[string]types.Status) (gopher.MapDocument, error) {
contents, err := os.ReadDir(dir)
if err != nil {
return nil, err
@@ -28,55 +29,36 @@ func listDir(dir string, location *url.URL, hidden map[string]struct{}, extensio
for _, entry := range contents {
name := entry.Name()
- if _, ok := hidden[name]; ok || name == "gophermap" {
+ inf, err := entry.Info()
+ if err != nil {
+ return nil, err
+ }
+ if inf.Mode()&4 == 0 {
+ continue
+ }
+
+ if _, ok := hidden[name]; ok || slices.Contains(settings.DirMaps, name) {
continue
}
var code types.Status
- ext := strings.TrimPrefix(filepath.Ext(name), ".")
if entry.IsDir() {
code = gopher.MenuType
- } else if c, ok := extensions[ext]; ok && ext != "" {
- code = c
} else {
- switch ext {
- case "gophermap":
- code = gopher.MenuType
- case "exe", "bin", "out":
- code = gopher.BinaryFileType
- case "gif":
- code = gopher.GifFileType
- case "jpg", "jpeg", "tif", "tiff":
- code = gopher.ImageFileType
- case "bmp":
- code = gopher.BitmapType
- case "mp4", "mov", "avi", "wmv", "webm":
- code = gopher.MovieFileType
- case "pcm", "aiff", "mp3", "aac", "ogg", "wma", "flac", "alac":
- code = gopher.SoundFileType
- case "doc", "docx", "odt", "fodt":
- code = gopher.DocumentType
- case "html":
- code = gopher.HTMLType
- case "png":
- code = gopher.PngImageFileType
- case "rtf":
- code = gopher.RtfDocumentType
- case "wav":
- code = gopher.WavSoundFileType
- case "pdf":
- code = gopher.PdfDocumentType
- case "xml", "atom":
- code = gopher.XmlDocumentType
- default:
- code = gopher.TextFileType
+ ext := strings.TrimPrefix(filepath.Ext(name), ".")
+ if c, ok := extensions[ext]; ok {
+ code = c
+ } else if c, ok := extensions[name]; ok {
+ code = c
+ } else {
+ code = gopher.GuessItemType(name)
}
}
doc = append(doc, gopher.MapItem{
Type: code,
- Display: displayName(dir, entry),
+ Display: displayName(dir, entry, settings),
Selector: path.Join(path.Dir(location.Path), name),
Hostname: location.Hostname(),
Port: location.Port(),
@@ -86,32 +68,37 @@ func listDir(dir string, location *url.URL, hidden map[string]struct{}, extensio
return doc, nil
}
-func displayName(dir string, entry os.DirEntry) string {
+func displayName(dir string, entry os.DirEntry, settings FileSystemSettings) string {
fname := entry.Name()
+ fullpath := filepath.Join(dir, fname)
- // if is a gophermap, use !title or filename
- if strings.HasSuffix(fname, ".gophermap") {
- if title := gophermapTitle(dir, fname); title != "" {
+ if entry.Type().IsRegular() && settings.ParseExtended && (strings.HasSuffix(fname, ".gophermap") || slices.Contains(settings.DirMaps, fname)) {
+ if title := gophermapTitle(fullpath); title != "" {
return title
}
- return fname
}
if entry.IsDir() {
- if tag := tagTitle(dir, fname); tag != "" {
- return tag
+ if settings.DirTag != "" {
+ if tag := tagTitle(filepath.Join(fullpath, settings.DirTag)); tag != "" {
+ return tag
+ }
}
- if title := gophermapTitle(dir, filepath.Join(fname, "gophermap")); title != "" {
- return title
+ if settings.ParseExtended {
+ for _, mapname := range settings.DirMaps {
+ if title := gophermapTitle(filepath.Join(fullpath, mapname)); title != "" {
+ return title
+ }
+ }
}
}
return fname
}
-func gophermapTitle(dir, name string) string {
- file, err := os.Open(filepath.Join(dir, name))
+func gophermapTitle(path string) string {
+ file, err := os.Open(path)
if err != nil {
return ""
}
@@ -131,8 +118,8 @@ func gophermapTitle(dir, name string) string {
return strings.TrimRight(line[1:], "\r\n")
}
-func tagTitle(parent, name string) string {
- file, err := os.Open(filepath.Join(parent, name, "gophertag"))
+func tagTitle(path string) string {
+ file, err := os.Open(path)
if err != nil {
return ""
}
diff --git a/gopher/gophermap/testdata/customlist_output.gophermap b/gopher/gophermap/testdata/customlist_output.gophermap
index 1a96644..e5cc99d 100644
--- a/gopher/gophermap/testdata/customlist_output.gophermap
+++ b/gopher/gophermap/testdata/customlist_output.gophermap
@@ -8,5 +8,7 @@ i /customlist.gophermap localhost.localdomain 70
1This is the document title /customlist.gophermap localhost.localdomain 70
1customlist_output.gophermap /customlist_output.gophermap localhost.localdomain 70
9file3.executablething /file3.executablething localhost.localdomain 70
-0file4 /file4 localhost.localdomain 70
+0file4.txt /file4.txt localhost.localdomain 70
+1subdir title /subdir localhost.localdomain 70
+1subdir2 title /subdir2 localhost.localdomain 70
.
diff --git a/gopher/gophermap/testdata/file4 b/gopher/gophermap/testdata/file4.txt
index e69de29..e69de29 100644
--- a/gopher/gophermap/testdata/file4
+++ b/gopher/gophermap/testdata/file4.txt
diff --git a/gopher/gophermap/testdata/subdir/gophertag b/gopher/gophermap/testdata/subdir/gophertag
new file mode 100644
index 0000000..73a248e
--- /dev/null
+++ b/gopher/gophermap/testdata/subdir/gophertag
@@ -0,0 +1 @@
+subdir title
diff --git a/gopher/gophermap/testdata/subdir2/gophermap b/gopher/gophermap/testdata/subdir2/gophermap
new file mode 100644
index 0000000..bba9538
--- /dev/null
+++ b/gopher/gophermap/testdata/subdir2/gophermap
@@ -0,0 +1 @@
+!subdir2 title
diff --git a/gopher/response.go b/gopher/response.go
index 1ad7f1d..46f9db0 100644
--- a/gopher/response.go
+++ b/gopher/response.go
@@ -121,7 +121,7 @@ func Error(err error) *MapItem {
// File builds a minimal response delivering a file's contents.
//
-// Meta is nil and Status is 0 in this response.
+// Meta is nil in this response.
func File(status types.Status, contents io.Reader) *types.Response {
return &types.Response{Status: status, Body: contents}
}