From 8ec2f0c1e59286f05de63b683f7316a7a40e7b46 Mon Sep 17 00:00:00 2001 From: Moritz Poldrack Date: Sat, 17 Jun 2023 16:46:31 +0200 Subject: save: fix saving of multiple files with the same name When an email has multiple attachments with the same name, aerc currently only saves one of them. This patch adds a counter to them. the file has an extension, the counter is added before the extension. Signed-off-by: Moritz Poldrack Acked-by: Koni Marti --- commands/msgview/save.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'commands/msgview/save.go') diff --git a/commands/msgview/save.go b/commands/msgview/save.go index 5bd4c188..170ef7c1 100644 --- a/commands/msgview/save.go +++ b/commands/msgview/save.go @@ -115,8 +115,9 @@ func (s Save) Execute(aerc *widgets.Aerc, args []string) error { return fmt.Errorf("This message has no attachments") } params.trailingSlash = true + names := make(map[string]struct{}) for _, pi := range parts { - if err := savePart(pi, path, mv, aerc, ¶ms); err != nil { + if err := savePart(pi, path, mv, aerc, ¶ms, names); err != nil { return err } } @@ -124,7 +125,7 @@ func (s Save) Execute(aerc *widgets.Aerc, args []string) error { } pi := mv.SelectedMessagePart() - return savePart(pi, path, mv, aerc, ¶ms) + return savePart(pi, path, mv, aerc, ¶ms, make(map[string]struct{})) } func savePart( @@ -133,6 +134,7 @@ func savePart( mv *widgets.MessageViewer, aerc *widgets.Aerc, params *saveParams, + names map[string]struct{}, ) error { if params.trailingSlash || isDirExists(path) { filename := generateFilename(pi.Part) @@ -147,6 +149,9 @@ func savePart( } } + path = getCollisionlessFilename(path, names) + names[path] = struct{}{} + if pathExists(path) && !params.force { return fmt.Errorf("%q already exists and -f not given", path) } @@ -181,6 +186,19 @@ func savePart( return nil } +func getCollisionlessFilename(path string, existing map[string]struct{}) string { + ext := filepath.Ext(path) + name := strings.TrimSuffix(path, ext) + _, exists := existing[path] + counter := 1 + for exists { + path = fmt.Sprintf("%s_%d%s", name, counter, ext) + counter++ + _, exists = existing[path] + } + return path +} + // isDir returns true if path is a directory and exists func isDirExists(path string) bool { pathinfo, err := os.Stat(path) -- cgit