Support directories in path to :save

This adds new functionality to :save in the message view for specifying
directories in the path. A new flag, -p, is also added to :save for
automatically creating any directories in the path that do not exist.

If the path ends in a / (e.g. "Downloads/mail/") or if the path is an
existing directory, the part's file name is the filename from the mail
header for the part. Otherwise, it uses the last element in the path as
the filename (e.g. 'blah.jpg' is the filename if the path is
'Downloads/mail/blah.jpg')
This commit is contained in:
Clayton Craft 2019-06-11 11:26:13 -07:00 committed by Drew DeVault
parent 61206c6ac6
commit e56ceb099e
2 changed files with 56 additions and 5 deletions

View File

@ -6,9 +6,11 @@ import (
"io" "io"
"mime/quotedprintable" "mime/quotedprintable"
"os" "os"
"path/filepath"
"time" "time"
"git.sr.ht/~sircmpwn/aerc/widgets" "git.sr.ht/~sircmpwn/aerc/widgets"
"git.sr.ht/~sircmpwn/getopt"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
) )
@ -17,9 +19,24 @@ func init() {
} }
func Save(aerc *widgets.Aerc, args []string) error { func Save(aerc *widgets.Aerc, args []string) error {
if len(args) < 2 { opts, optind, err := getopt.Getopts(args, "p")
return errors.New("Usage: :save <path>") 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) mv := aerc.SelectedTab().(*widgets.MessageViewer)
p := mv.CurrentPart() p := mv.CurrentPart()
@ -33,12 +50,44 @@ func Save(aerc *widgets.Aerc, args []string) error {
reader = quotedprintable.NewReader(reader) 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 { if err != nil {
aerc.PushError(" " + err.Error()) 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) f, err := os.Create(target)
if err != nil { if err != nil {
aerc.PushError(" " + err.Error()) aerc.PushError(" " + err.Error())

View File

@ -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, Downloads and pipes the current message part into the given shell command,
and opens a new terminal tab to show the result. and opens a new terminal tab to show the result.
*save* <path> *save* [-p] <path>
Saves the current message part to the given path. Saves the current message part to the given path.
*-p*: Make any directories in the path that do not exist
*close* *close*
Closes the message viewer. Closes the message viewer.