aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorPaul Wise <pabs3@bonedaddy.net>2023-05-28 10:29:46 +0800
committerDavid Bremner <david@tethera.net>2023-05-28 15:34:42 -0300
commit239fdbbbf0cbd6cd6ebafb87e88cdb3cded75364 (patch)
tree820829b9bc8897dc4cf2c0e5129ad0e416943e01 /contrib
parent18e35950dad8daa485d86e244ffd5d5e6a63d03a (diff)
notmuch-mutt: check that the search cache Maildir is not a real Maildir
This prevents data loss when users configure the search cache Maildir to be a real Maildir containing their real mail data, since the search cache Maildir is expected to contain only symlinks to the real mail data. Prevents: <ZCsQBNmbzwkvbpHA@localhost.localdomain>
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/notmuch-mutt/notmuch-mutt46
1 files changed, 46 insertions, 0 deletions
diff --git a/contrib/notmuch-mutt/notmuch-mutt b/contrib/notmuch-mutt/notmuch-mutt
index 875fd032..1ac68065 100755
--- a/contrib/notmuch-mutt/notmuch-mutt
+++ b/contrib/notmuch-mutt/notmuch-mutt
@@ -13,6 +13,7 @@ use warnings;
use File::Path;
use File::Basename;
+use File::Find;
use Getopt::Long qw(:config no_getopt_compat);
use Mail::Header;
use Mail::Box::Maildir;
@@ -25,6 +26,50 @@ my $xdg_cache_dir = "$ENV{HOME}/.cache";
$xdg_cache_dir = $ENV{XDG_CACHE_HOME} if $ENV{XDG_CACHE_HOME};
my $cache_dir = "$xdg_cache_dir/notmuch/mutt";
+sub die_dir($$) {
+ my ($maildir, $error) = @_;
+ die "notmuch-mutt: search cache maildir $maildir $error\n".
+ "Please ensure that the notmuch-mutt search cache Maildir\n".
+ "contains no subfolders or real mail data, only symlinks to mail\n";
+}
+
+sub die_subdir($$$) {
+ my ($maildir, $subdir, $error) = @_;
+ die_dir($maildir, "subdir $subdir $error");
+}
+
+# check that the search cache maildir is that and not a real maildir
+# otherwise there could be data loss when the search cache is emptied
+sub check_search_cache_maildir($) {
+ my ($maildir) = (@_);
+
+ return unless -e $maildir;
+
+ -d $maildir or die_dir($maildir, 'is not a directory');
+
+ opendir(my $mdh, $maildir) or die_dir($maildir, "cannot be opened: $!");
+ my @contents = grep { !/^\.\.?$/ } readdir $mdh;
+ closedir $mdh;
+
+ my @required = ('cur', 'new', 'tmp');
+ foreach my $d (@required) {
+ -l "$maildir/$d" and die_dir($maildir, "contains symlink $d");
+ -e "$maildir/$d" or die_subdir($maildir, $d, 'is missing');
+ -d "$maildir/$d" or die_subdir($maildir, $d, 'is not a directory');
+ find(sub {
+ $_ eq '.' and return;
+ $_ eq '..' and return;
+ -l $_ or die_subdir($maildir, $d, "contains non-symlink $_");
+ }, "$maildir/$d");
+ }
+
+ my %required = map { $_ => 1 } @required;
+ foreach my $d (@contents) {
+ -l "$maildir/$d" and die_dir( $maildir, "contains symlink $d");
+ -d "$maildir/$d" or die_dir( $maildir, "contains non-directory $d");
+ exists($required[$d]) or die_dir( $maildir, "contains directory $d");
+ }
+}
# create an empty search cache maildir (if missing) or empty existing one
sub empty_search_cache_maildir($) {
@@ -45,6 +90,7 @@ sub search($$$) {
push @args, "--duplicate=1" if $remove_dups;
push @args, $query;
+ check_search_cache_maildir($maildir);
empty_search_cache_maildir($maildir);
open my $pipe, '-|', @args or die "Running @args failed: $!\n";
while (<$pipe>) {