aboutsummaryrefslogtreecommitdiffstats
path: root/commands/msgview
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-03-24 09:26:06 +0100
committerRobin Jarry <robin@jarry.cc>2022-03-24 15:30:10 +0100
commitd64ceba2cc8d8d1624348a76c7e7a02e385e6d0a (patch)
tree70adf3aa3b2224a57be48f98905db64f0d6c6c3c /commands/msgview
parentd66930749a9f8eaa19acab78d57585a170f17429 (diff)
downloadaerc-d64ceba2cc8d8d1624348a76c7e7a02e385e6d0a.tar.gz
save: add -a option to save all attachments
Allow saving all message parts that have the content disposition "attachment" header to a folder. Suggested-by: Ondřej Synáček <ondrej@synacek.org> Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Koni Marti <koni.marti@gmail.com> Tested-by: Moritz Poldrack <moritz@poldrack.dev>
Diffstat (limited to 'commands/msgview')
-rw-r--r--commands/msgview/save.go62
1 files changed, 47 insertions, 15 deletions
diff --git a/commands/msgview/save.go b/commands/msgview/save.go
index 48add989..350739ab 100644
--- a/commands/msgview/save.go
+++ b/commands/msgview/save.go
@@ -13,6 +13,7 @@ import (
"github.com/mitchellh/go-homedir"
"git.sr.ht/~rjarry/aerc/commands"
+ "git.sr.ht/~rjarry/aerc/lib"
"git.sr.ht/~rjarry/aerc/logging"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/widgets"
@@ -33,31 +34,36 @@ func (Save) Complete(aerc *widgets.Aerc, args []string) []string {
return commands.CompletePath(path)
}
+type saveParams struct {
+ force bool
+ createDirs bool
+ trailingSlash bool
+ attachments bool
+}
+
func (Save) Execute(aerc *widgets.Aerc, args []string) error {
- opts, optind, err := getopt.Getopts(args, "fp")
+ opts, optind, err := getopt.Getopts(args, "fpa")
if err != nil {
return err
}
- var (
- force bool
- createDirs bool
- trailingSlash bool
- )
+ var params saveParams
for _, opt := range opts {
switch opt.Option {
case 'f':
- force = true
+ params.force = true
case 'p':
- createDirs = true
+ params.createDirs = true
+ case 'a':
+ params.attachments = true
}
}
defaultPath := aerc.Config().General.DefaultSavePath
// we either need a path or a defaultPath
if defaultPath == "" && len(args) == optind {
- return errors.New("Usage: :save [-fp] <path>")
+ return errors.New("Usage: :save [-fpa] <path>")
}
// as a convenience we join with spaces, so that the user doesn't need to
@@ -68,10 +74,10 @@ func (Save) Execute(aerc *widgets.Aerc, args []string) error {
// it gets stripped by Clean.
// we auto generate a name if a directory was given
if len(path) > 0 {
- trailingSlash = path[len(path)-1] == '/'
+ params.trailingSlash = path[len(path)-1] == '/'
} else if len(defaultPath) > 0 && len(path) == 0 {
// empty path, so we might have a default that ends in a trailingSlash
- trailingSlash = defaultPath[len(defaultPath)-1] == '/'
+ params.trailingSlash = defaultPath[len(defaultPath)-1] == '/'
}
// Absolute paths are taken as is so that the user can override the default
@@ -89,27 +95,53 @@ func (Save) Execute(aerc *widgets.Aerc, args []string) error {
if !ok {
return fmt.Errorf("SelectedTab is not a MessageViewer")
}
+
+ store := mv.Store()
+
+ if params.attachments {
+ parts := mv.AttachmentParts()
+ if len(parts) == 0 {
+ return fmt.Errorf("This message has no attachments")
+ }
+ params.trailingSlash = true
+ for _, pi := range parts {
+ if err := savePart(pi, path, store, aerc, &params); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
pi := mv.SelectedMessagePart()
+ return savePart(pi, path, store, aerc, &params)
+}
+
+func savePart(
+ pi *widgets.PartInfo,
+ path string,
+ store *lib.MessageStore,
+ aerc *widgets.Aerc,
+ params *saveParams,
+) error {
- if trailingSlash || isDirExists(path) {
+ if params.trailingSlash || isDirExists(path) {
filename := generateFilename(pi.Part)
path = filepath.Join(path, filename)
}
dir := filepath.Dir(path)
- if createDirs && dir != "" {
+ if params.createDirs && dir != "" {
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
}
- if pathExists(path) && !force {
+ if pathExists(path) && !params.force {
return fmt.Errorf("%q already exists and -f not given", path)
}
ch := make(chan error, 1)
- store := mv.Store()
store.FetchBodyPart(pi.Msg.Uid, pi.Index, func(reader io.Reader) {
f, err := os.Create(path)
if err != nil {