diff options
author | Moritz Poldrack <git@moritz.sh> | 2023-06-17 16:46:31 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-06-17 23:19:24 +0200 |
commit | 8ec2f0c1e59286f05de63b683f7316a7a40e7b46 (patch) | |
tree | a1a2157e15c1623e4b03363ed9496c741f9e8abf | |
parent | b13c45797a1ea2d27f162c0fde0b640d7b24471e (diff) | |
download | aerc-8ec2f0c1e59286f05de63b683f7316a7a40e7b46.tar.gz |
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 <git@moritz.sh>
Acked-by: Koni Marti <koni.marti@gmail.com>
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | commands/msgview/save.go | 22 | ||||
-rw-r--r-- | commands/msgview/save_test.go | 24 |
3 files changed, 45 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6291761d..0aecd62d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - `:archive` now works on servers using a different delimiter +- `:save -a` now works with multiple attachments with the same filename ### Changed 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) diff --git a/commands/msgview/save_test.go b/commands/msgview/save_test.go new file mode 100644 index 00000000..d6b7e757 --- /dev/null +++ b/commands/msgview/save_test.go @@ -0,0 +1,24 @@ +package msgview + +import "testing" + +func TestGetCollisionlessFilename(t *testing.T) { + tests := []struct { + originalFilename string + expectedNewName string + existingFiles map[string]struct{} + }{ + {"test", "test", map[string]struct{}{}}, + {"test", "test", map[string]struct{}{"other-file": {}}}, + {"test.txt", "test.txt", map[string]struct{}{"test.log": {}}}, + {"test.txt", "test_1.txt", map[string]struct{}{"test.txt": {}}}, + {"test.txt", "test_2.txt", map[string]struct{}{"test.txt": {}, "test_1.txt": {}}}, + {"test.txt", "test_1.txt", map[string]struct{}{"test.txt": {}, "test_2.txt": {}}}, + } + for _, tt := range tests { + actual := getCollisionlessFilename(tt.originalFilename, tt.existingFiles) + if actual != tt.expectedNewName { + t.Errorf("expected %s, actual %s", tt.expectedNewName, actual) + } + } +} |