about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--commands/msgview/save.go57
-rw-r--r--doc/aerc.1.scd4
2 files changed, 56 insertions, 5 deletions
diff --git a/commands/msgview/save.go b/commands/msgview/save.go
index 4dabd52..b15f42d 100644
--- a/commands/msgview/save.go
+++ b/commands/msgview/save.go
@@ -6,9 +6,11 @@ import (
 	"io"
 	"mime/quotedprintable"
 	"os"
+	"path/filepath"
 	"time"
 
 	"git.sr.ht/~sircmpwn/aerc/widgets"
+	"git.sr.ht/~sircmpwn/getopt"
 	"github.com/mitchellh/go-homedir"
 )
 
@@ -17,9 +19,24 @@ func init() {
 }
 
 func Save(aerc *widgets.Aerc, args []string) error {
-	if len(args) < 2 {
-		return errors.New("Usage: :save <path>")
+	opts, optind, err := getopt.Getopts(args, "p")
+	if err != nil {
+		return err
 	}
+	var (
+		mkdirs bool
+		path   string
+	)
+	for _, opt := range opts {
+		switch opt.Option {
+		case 'p':
+			mkdirs = true
+		}
+	}
+	if len(args) <= optind {
+		return errors.New("Usage: :save [-p] <path>")
+	}
+	path = args[optind]
 
 	mv := aerc.SelectedTab().(*widgets.MessageViewer)
 	p := mv.CurrentPart()
@@ -33,12 +50,44 @@ func Save(aerc *widgets.Aerc, args []string) error {
 			reader = quotedprintable.NewReader(reader)
 		}
 
-		target, err := homedir.Expand(args[1])
+		var pathIsDir bool
+		if path[len(path)-1:] == "/" {
+			pathIsDir = true
+		}
+		// Note: path expansion has to happen after test for trailing /,
+		// since it is stripped when path is expanded
+		path, err := homedir.Expand(path)
 		if err != nil {
 			aerc.PushError(" " + err.Error())
-			return
 		}
 
+		pathinfo, err := os.Stat(path)
+		if err == nil && pathinfo.IsDir() {
+			pathIsDir = true
+		} else if os.IsExist(err) && pathIsDir {
+			aerc.PushError("The given directory is an existing file")
+		}
+
+		// Use attachment name as filename if given path is a directory
+		save_file := filepath.Base(path)
+		save_dir := filepath.Dir(path)
+		if pathIsDir {
+			save_dir = path
+			if filename, ok := p.Part.DispositionParams["filename"]; ok {
+				save_file = filename
+			}
+		}
+		if _, err := os.Stat(save_dir); os.IsNotExist(err) {
+			if mkdirs {
+				os.MkdirAll(save_dir, 0755)
+			} else {
+				aerc.PushError("Target directory does not exist, use " +
+					":save with the -p option to create it")
+				return
+			}
+		}
+		target := filepath.Clean(filepath.Join(save_dir, save_file))
+
 		f, err := os.Create(target)
 		if err != nil {
 			aerc.PushError(" " + err.Error())
diff --git a/doc/aerc.1.scd b/doc/aerc.1.scd
index 229868f..7b09531 100644
--- a/doc/aerc.1.scd
+++ b/doc/aerc.1.scd
@@ -119,9 +119,11 @@ message list, the message in the message viewer, etc).
 	Downloads and pipes the current message part into the given shell command,
 	and opens a new terminal tab to show the result.
 
-*save* <path>
+*save* [-p] <path>
 	Saves the current message part to the given path.
 
+	*-p*: Make any directories in the path that do not exist
+
 *close*
 	Closes the message viewer.