afewmail / afew

an initial tagging script for notmuch mail
ISC License
325 stars 98 forks source link

overwrapping path in maildir #190

Open tanyo13 opened 6 years ago

tanyo13 commented 6 years ago

Hello,

Move-mail function can abort when mailboxes have overwrapping path names.

I have entries something like the following:

[MailMover] folders = main/INBOX main/INBOX.archive main/INBOX = 'NOT tag:inbox':main/INBOX.archive main/INBOX.archive = 'tag:deleted':main/INBOX.Trash

When two files for a message that matches 'NOT tag:inbox' exist, one in main/INBOX and the other in main/INBOX.archive, afew --move-mail fails with the following stack trace:

File "/usr/local/bin/afew", line 11, in sys.exit(main()) File "/usr/local/lib/python3.6/site-packages/afew/commands.py", line 159, in main inner_main(args, database, query_string) File "/usr/local/lib/python3.6/site-packages/afew/main.py", line 33, in main mover.move(maildir, rules) File "/usr/local/lib/python3.6/site-packages/afew/MailMover.py", line 75, in move shutil.copy2(fname, self.get_new_name(fname, destination)) File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/shutil.py", line 257, in copy2 copyfile(src, dst, follow_symlinks=follow_symlinks) File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/shutil.py", line 104, in copyfile raise SameFileError("{!r} and {!r} are the same file".format(src, dst)) shutil.SameFileError: '.../main/INBOX.archive/cur/1523257381_0.1544....' and '.../main/INBOX.archive/cur/1523257381_0.1544....' are the same file

This is I think because selecting the file in the specified maildir is done using "if maildir in name". Around line 63 in method move() in MailMover.py, to_move_fnames is defined as: to_move_fnames = [name for name in all_message_fnames if maildir in name] If you replace "maildir in name" is with "maildir + '/cur' in name", the problem is gone, though I do not know if that is a correct fix.

mjg commented 6 years ago

The correct fix should check that both paths have the same leading components up to maildir:

fullmaildirs = [ os.path.join(self.db_path, maildir, subdir) for subdir in ['new', 'cur'] ]
any([ fullmaildir  == os.path.commonprefix(fullmaildir, name) for fullmaildir in fullmaildirs ])

Or a regex...