diff --git a/client.go b/client.go index 07be1c7..4ff6a05 100644 --- a/client.go +++ b/client.go @@ -5,7 +5,6 @@ import ( "io/ioutil" "os" "os/exec" - // "os/user" "regexp" "strconv" "strings" @@ -17,6 +16,7 @@ import ( "tildegit.org/sloum/bombadillo/gopher" "tildegit.org/sloum/bombadillo/http" "tildegit.org/sloum/bombadillo/telnet" + // "tildegit.org/sloum/mailcap" ) //------------------------------------------------\\ @@ -460,6 +460,8 @@ func (c *client) getCurrentPageRawData() (string, error) { func (c *client) saveFile(u Url, name string) { var file []byte var err error + c.SetMessage(fmt.Sprintf("Saving %s ...", name), false) + c.DrawMessage() switch u.Scheme { case "gopher": file, err = gopher.Retrieve(u.Host, u.Port, u.Resource) @@ -488,6 +490,22 @@ func (c *client) saveFile(u Url, name string) { c.DrawMessage() } +func (c *client) saveFileFromData(d, name string) { + data := []byte(d) + c.SetMessage(fmt.Sprintf("Saving %s ...", name), false) + c.DrawMessage() + savePath := c.Options["savelocation"] + name + err := ioutil.WriteFile(savePath, data, 0644) + if err != nil { + c.SetMessage("Error writing file to disk", true) + c.DrawMessage() + return + } + + c.SetMessage(fmt.Sprintf("File saved to: %s", savePath), false) + c.DrawMessage() +} + func (c *client) doLinkCommand(action, target string) { num, err := strconv.Atoi(target) if err != nil { @@ -779,19 +797,29 @@ func (c *client) Visit(url string) { switch u.Scheme { case "gopher": - content, links, err := gopher.Visit(u.Mime, u.Host, u.Port, u.Resource) - if err != nil { - c.SetMessage(err.Error(), true) - c.DrawMessage() - return + if u.DownloadOnly { + nameSplit := strings.Split(u.Resource, "/") + filename := nameSplit[len(nameSplit) - 1] + filename = strings.Trim(filename, " \t\r\n\v\f\a") + if filename == "" { + filename = "gopherfile" + } + c.saveFile(u, filename) + } else { + content, links, err := gopher.Visit(u.Mime, u.Host, u.Port, u.Resource) + if err != nil { + c.SetMessage(err.Error(), true) + c.DrawMessage() + return + } + pg := MakePage(u, content, links) + pg.WrapContent(c.Width - 1) + c.PageState.Add(pg) + c.SetPercentRead() + c.ClearMessage() + c.SetHeaderUrl() + c.Draw() } - pg := MakePage(u, content, links) - pg.WrapContent(c.Width - 1) - c.PageState.Add(pg) - c.SetPercentRead() - c.ClearMessage() - c.SetHeaderUrl() - c.Draw() case "gemini": capsule, err := gemini.Visit(u.Host, u.Port, u.Resource) if err != nil { @@ -810,8 +838,59 @@ func (c *client) Visit(url string) { c.SetHeaderUrl() c.Draw() } else { - c.SetMessage("Still mulling how to handle binary files... come back soon", false) + c.SetMessage("The file is non-text: (o)pen or (w)rite to disk", false) c.DrawMessage() + var ch rune + for { + ch = cui.Getch() + if ch == 'o' || ch == 'w' { + break + } + } + switch ch { + case 'o': + mime := fmt.Sprintf("%s/%s", capsule.MimeMaj, capsule.MimeMin) + var term bool + if c.Options["terminalonly"] == "true" { + term = true + } else { + term = false + } + mcEntry, err := mc.FindMatch(mime, "view", term) + if err != nil { + c.SetMessage(err.Error(), true) + c.DrawMessage() + return + } + file, err := ioutil.TempFile("/tmp/", "bombadillo-*.tmp") + if err != nil { + c.SetMessage("Unable to create temporary file for opening, aborting file open", true) + c.DrawMessage() + return + } + // defer os.Remove(file.Name()) + file.Write([]byte(capsule.Content)) + com, e := mcEntry.Command(file.Name()) + if e != nil { + c.SetMessage(e.Error(), true) + c.DrawMessage() + return + } + com.Stdin = os.Stdin + com.Stdout = os.Stdout + com.Stderr = os.Stderr + if c.Options["terminalonly"] == "true" { + cui.Clear("screen") + } + com.Run() + c.SetMessage("File opened by an appropriate program", true) + c.DrawMessage() + c.Draw() + case 'w': + nameSplit := strings.Split(u.Resource, "/") + filename := nameSplit[len(nameSplit) - 1] + c.saveFileFromData(capsule.Content, filename) + } } case 3: c.SetMessage("[3] Redirect. Follow redirect? y or any other key for no", false) diff --git a/defaults.go b/defaults.go index 2d8ac8c..8d744de 100644 --- a/defaults.go +++ b/defaults.go @@ -17,5 +17,6 @@ var defaultOptions = map[string]string{ "telnetcommand": "telnet", "configlocation": userinfo.HomeDir, "theme": "normal", // "normal", "inverted" + "terminalonly": "true", } diff --git a/main.go b/main.go index 0e5c803..1e7c6bc 100644 --- a/main.go +++ b/main.go @@ -15,6 +15,7 @@ import ( "tildegit.org/sloum/bombadillo/config" "tildegit.org/sloum/bombadillo/cui" + "tildegit.org/sloum/mailcap" ) const version = "2.0.0" @@ -22,23 +23,7 @@ const version = "2.0.0" var bombadillo *client var helplocation string = "gopher://colorfield.space:70/1/bombadillo-info" var settings config.Config - - -// func saveFileFromData(v gopher.View) error { - // quickMessage("Saving file...", false) - // urlsplit := strings.Split(v.Address.Full, "/") - // filename := urlsplit[len(urlsplit)-1] - // saveMsg := fmt.Sprintf("Saved file as %q", options["savelocation"]+filename) - // err := ioutil.WriteFile(options["savelocation"]+filename, []byte(strings.Join(v.Content, "")), 0644) - // if err != nil { - // quickMessage("Saving file...", true) - // return err - // } - - // quickMessage(saveMsg, false) - // return nil -// } - +var mc *mailcap.Mailcap func saveConfig() error { var opts strings.Builder @@ -106,6 +91,10 @@ func main() { } args := flag.Args() + // Build the mailcap db + // So that we can open files from gemini + mc = mailcap.NewMailcap() + cui.Tput("rmam") // turn off line wrapping cui.Tput("smcup") // use alternate screen defer cui.Exit()