gophi/gopher.go
kim (grufwub) 839473750e move most of code from format.go --> gopher.go
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
2020-05-14 20:36:57 +01:00

238 lines
7.7 KiB
Go

package main
import (
"strings"
)
type GopherUrl struct {
Path string
Parameters string
}
const (
/* Just naming some constants */
DOSLineEnd = "\r\n"
UnixLineEnd = "\n"
End = "."
Tab = "\t"
LastLine = End+DOSLineEnd
/* Gopher line formatting */
MaxUserNameLen = 70 /* RFC 1436 standard, though we use user-supplied page-width */
MaxSelectorLen = 255 /* RFC 1436 standard */
SelectorErrorStr = "/max_selector_length_reached"
GophermapRenderErrorStr = ""
GophermapReadErrorStr = "Error reading subgophermap: "
GophermapExecErrorStr = "Error executing gophermap: "
/* Default null values */
NullSelector = "-"
NullHost = "null.host"
NullPort = "0"
/* Replacement strings */
ReplaceStrHostname = "$hostname"
ReplaceStrPort = "$port"
)
/*
* Item type characters:
* Collected from RFC 1436 standard, Wikipedia, Go-gopher project
* and Gophernicus project. Those with ALL-CAPS descriptions in
* [square brackets] defined and used by Gophernicus, a popular
* Gopher server.
*/
type ItemType byte
const (
/* RFC 1436 Standard */
TypeFile = ItemType('0') /* Regular file (text) */
TypeDirectory = ItemType('1') /* Directory (menu) */
TypeDatabase = ItemType('2') /* CCSO flat db; other db */
TypeError = ItemType('3') /* Error message */
TypeMacBinHex = ItemType('4') /* Macintosh BinHex file */
TypeBinArchive = ItemType('5') /* Binary archive (zip, rar, 7zip, tar, gzip, etc), CLIENT MUST READ UNTIL TCP CLOSE */
TypeUUEncoded = ItemType('6') /* UUEncoded archive */
TypeSearch = ItemType('7') /* Query search engine or CGI script */
TypeTelnet = ItemType('8') /* Telnet to: VT100 series server */
TypeBin = ItemType('9') /* Binary file (see also, 5), CLIENT MUST READ UNTIL TCP CLOSE */
TypeTn3270 = ItemType('T') /* Telnet to: tn3270 series server */
TypeGif = ItemType('g') /* GIF format image file (just use I) */
TypeImage = ItemType('I') /* Any format image file */
TypeRedundant = ItemType('+') /* Redundant (indicates mirror of previous item) */
/* GopherII Standard */
TypeCalendar = ItemType('c') /* Calendar file */
TypeDoc = ItemType('d') /* Word-processing document; PDF document */
TypeHtml = ItemType('h') /* HTML document */
TypeInfo = ItemType('i') /* Informational text (not selectable) */
TypeMarkup = ItemType('p') /* Page layout or markup document (plain text w/ ASCII tags) */
TypeMail = ItemType('M') /* Email repository (MBOX) */
TypeAudio = ItemType('s') /* Audio recordings */
TypeXml = ItemType('x') /* eXtensible Markup Language document */
TypeVideo = ItemType(';') /* Video files */
/* Commonly Used */
TypeTitle = ItemType('!') /* [SERVER ONLY] Menu title (set title ONCE per gophermap) */
TypeComment = ItemType('#') /* [SERVER ONLY] Comment, rest of line is ignored */
TypeHiddenFile = ItemType('-') /* [SERVER ONLY] Hide file/directory from directory listing */
TypeEnd = ItemType('.') /* [SERVER ONLY] Last line -- stop processing gophermap default */
TypeSubGophermap = ItemType('=') /* [SERVER ONLY] Include subgophermap / regular file here. */
TypeEndBeginList = ItemType('*') /* [SERVER ONLY] Last line + directory listing -- stop processing gophermap and end on directory listing */
/* Default type */
TypeDefault = TypeBin
/* Gophor specific types */
TypeInfoNotStated = ItemType('I') /* [INTERNAL USE] */
TypeUnknown = ItemType('?') /* [INTERNAL USE] */
)
var FileExtMap = map[string]ItemType{
".out": TypeBin,
".a": TypeBin,
".o": TypeBin,
".ko": TypeBin, /* ... Though tbh, kernel extensions?!!! */
".msi": TypeBin,
".exe": TypeBin,
".gophermap": TypeDirectory,
".lz": TypeBinArchive,
".gz": TypeBinArchive,
".bz2": TypeBinArchive,
".7z": TypeBinArchive,
".zip": TypeBinArchive,
".gitignore": TypeFile,
".txt": TypeFile,
".json": TypeFile,
".yaml": TypeFile,
".ocaml": TypeFile,
".s": TypeFile,
".c": TypeFile,
".py": TypeFile,
".h": TypeFile,
".go": TypeFile,
".fs": TypeFile,
".odin": TypeFile,
".nanorc": TypeFile,
".bashrc": TypeFile,
".mkshrc": TypeFile,
".vimrc": TypeFile,
".vim": TypeFile,
".viminfo": TypeFile,
".sh": TypeFile,
".conf": TypeFile,
".xinitrc": TypeFile,
".jstarrc": TypeFile,
".joerc": TypeFile,
".jpicorc": TypeFile,
".profile": TypeFile,
".bash_profile": TypeFile,
".bash_logout": TypeFile,
".log": TypeFile,
".ovpn": TypeFile,
".md": TypeMarkup,
".xml": TypeXml,
".doc": TypeDoc,
".docx": TypeDoc,
".pdf": TypeDoc,
".jpg": TypeImage,
".jpeg": TypeImage,
".png": TypeImage,
".gif": TypeImage,
".html": TypeHtml,
".htm": TypeHtml,
".ogg": TypeAudio,
".mp3": TypeAudio,
".wav": TypeAudio,
".mod": TypeAudio,
".it": TypeAudio,
".xm": TypeAudio,
".mid": TypeAudio,
".vgm": TypeAudio,
".opus": TypeAudio,
".m4a": TypeAudio,
".aac": TypeAudio,
".mp4": TypeVideo,
".mkv": TypeVideo,
".webm": TypeVideo,
}
/* Build error line */
func buildErrorLine(selector string) []byte {
ret := string(TypeError)
ret += selector + DOSLineEnd
ret += LastLine
return []byte(ret)
}
/* Build gopher compliant line with supplied information */
func buildLine(t ItemType, name, selector, host string, port string) []byte {
ret := string(t)
/* Add name, truncate name if too long */
if len(name) > Config.PageWidth {
ret += name[:Config.PageWidth-5]+"..."+Tab
} else {
ret += name+Tab
}
/* Add selector. If too long use err, skip if empty */
selectorLen := len(selector)
if selectorLen > MaxSelectorLen {
ret += SelectorErrorStr+Tab
} else if selectorLen > 0 {
ret += selector+Tab
}
/* Add host + port */
ret += host+Tab+port+DOSLineEnd
return []byte(ret)
}
/* Build gopher compliant info line */
func buildInfoLine(content string) []byte {
return buildLine(TypeInfo, content, NullSelector, NullHost, NullPort)
}
/* Get item type for named file on disk */
func getItemType(name string) ItemType {
/* Split, name MUST be lower */
split := strings.Split(strings.ToLower(name), ".")
/* First we look at how many '.' in name string */
splitLen := len(split)
switch splitLen {
case 0:
/* Always return TypeDefault. We can never tell */
return TypeDefault
default:
/* Get index of str after last ".", look in FileExtMap */
fileType, ok := FileExtMap["."+split[splitLen-1]]
if ok {
return fileType
} else {
return TypeDefault
}
}
}
/* Build a line separator of supplied width */
func buildLineSeparator(count int) string {
ret := ""
for i := 0; i < count; i += 1 {
ret += "_"
}
return ret
}