]> diplodocus.org Git - minc/blobdiff - minc
Correct minor oops in last.
[minc] / minc
diff --git a/minc b/minc
index 0fcceb1..f8d54dd 100755 (executable)
--- a/minc
+++ b/minc
@@ -37,6 +37,8 @@ rest of the line.
 use strict;
 use warnings;
 
+$SIG{'PIPE'} = 'IGNORE';
+
 use Data::Dumper;
 use Errno;
 use Fcntl qw(O_WRONLY O_EXCL O_CREAT);
@@ -178,13 +180,8 @@ our (@start_hooks, @stop_hooks, @filter_hooks, @post_store_hooks);
 our $SCAN_P_FOLDER = 0.1;
 our $SCAN_P_MESSAGE = 0.0625;
 our $SCAN_P_FROM = 0.175;
-
-our $folder_sorter =
-  sub { my ($a,$b) = @_;
-      $a eq 'inbox' and return -1;
-      $b eq 'inbox' and return 1;
-      return $a cmp $b;
-};
+our @folder_sort_list = (qr/^inbox$/);
+our $folder_sorter = sub { sort_by_list(@_, @folder_sort_list) };
 
 my $mh;
 
@@ -245,6 +242,26 @@ sub log_headers {
 ###############################################################################
 # Utility procedures
 
+sub sort_by_list {
+    my $a = shift;
+    my $b = shift;
+
+    for my $i (@_) {
+        my $am = $a =~ $i;
+        my $bm = $b =~ $i;
+        if ($am) {
+            if ($bm) {
+                last;
+            }
+            return -1;
+        } elsif ($bm) {
+            return 1;
+        }
+    }
+
+    return $a cmp $b;
+}
+
 sub mkfolder {
     my $folder = shift;
     my $target;
@@ -277,7 +294,7 @@ sub getfiles {
     }
 
     if (@result <= 2) {
-        exit(0);
+        return ();
     }
 
     STDOUT->autoflush(1);
@@ -288,6 +305,7 @@ sub getfiles {
     return @result;
 }
 
+my %msgnum_cache;
 sub get_highest_msgnum {
     my $mhfolder = shift;
     my $dir;
@@ -295,6 +313,10 @@ sub get_highest_msgnum {
     my $highest;
     my $msgnum;
 
+    if (defined($msgnum_cache{$mhfolder})) {
+        return $msgnum_cache{$mhfolder}++;
+    }
+
     $dir = "$mh/$mhfolder";
     if (not opendir(DIR, $dir)) {
         die("opendir($dir): $!");
@@ -320,7 +342,71 @@ sub get_highest_msgnum {
         }
     }
 
-    return $highest;
+    $msgnum_cache{$mhfolder} = $highest;
+    return $msgnum_cache{$mhfolder}++;
+}
+
+sub mark {
+    my $folder = shift;
+    my $msgnum = shift;
+    my $seq = shift;
+    my $fn = "$mh/$folder/.mh_sequences";
+    my $fh;
+    my @sequences;
+
+    if (not open($fh, $fn)) {
+        $!{ENOENT} or die("open($fn): $!");
+    } else {
+        @sequences = <$fh>;
+        chomp(@sequences);
+    }
+
+    my $marked = 0;
+    open($fh, '>', $fn) or die("open(>$fn): $!");
+    for $_ (@sequences) {
+        if (/^$seq: (.*)/) {
+            my @parts;
+            my @result;
+            my $done = 0;
+            for my $part (split(' ', $1)) {
+                if (not $done) {
+                    my ($st, $en) = split('-', $part);
+                    if ((defined($en) and ($msgnum >= $st and $msgnum <= $en))
+                        or $msgnum == $st) {
+                        # It's already there.
+                        $done = 1;
+                    }
+                    if (defined($en)) {
+                        if ($st - 1 == $msgnum) {
+                            $part = "$msgnum-$en";
+                            $done = 1;
+                        } elsif ($en + 1 == $msgnum) {
+                            $part = "$st-$msgnum";
+                            $done = 1;
+                        }
+                    } else {
+                        if ($part - 1 == $msgnum) {
+                            $part = "$msgnum-$part";
+                            $done = 1;
+                        } elsif ($part + 1 == $msgnum) {
+                            $part = "$part-$msgnum";
+                            $done = 1;
+                        }
+                    }
+                }
+                push(@result, $part);
+            }
+            if (not $done) {
+                push(@result, $msgnum);
+            }
+            print($fh "$seq: ", join(' ', @result), "\n");
+            $marked = 1;
+        } else {
+            print($fh "$_\n");
+        }
+    }
+    $marked or print($fh "$seq: $msgnum\n");
+    close($fh) or die("close(>$fn): $!");
 }
 
 sub store_message {
@@ -397,15 +483,7 @@ sub store_message {
         if ($mhfolder eq 'SPAM') {
             push(@SPAM, $msgnum);
         } else {
-            $status = system('mark', "+$mhfolder", "$msgnum", '-sequence',
-                             'unseen', '-add');
-            # XXX need to handle signalled and stopped, and print
-            # the exit code or signal number.
-            if (not WIFEXITED($status)) {
-                die("Failed to run mark");
-            } elsif (WEXITSTATUS($status) != 0) {
-                die("Failed to mark message unseen.");
-            }
+            mark($mhfolder, $msgnum, 'unseen');
         }
     }
 
@@ -473,7 +551,7 @@ sub find_mh_folder {
     my $header;
     my $contents;
     my $pair;
-    my $match;
+    my $regexp;
     my $expression;
     my $result;
 
@@ -493,8 +571,8 @@ sub find_mh_folder {
                 if ($header =~ /$MAGIC_TO_REGEX/i) {
                     foreach $contents (@{$headers{lc($header)}}) {
                         foreach $pair (@filter) {
-                            ($match, $expression) = @$pair;
-                            if ($contents =~ /$match/i) {
+                            ($regexp, $expression) = @$pair;
+                            if ($contents =~ $regexp) {
                                 if (eval "\$result = \"$expression\"") {
                                     return $result;
                                 }
@@ -511,10 +589,10 @@ sub find_mh_folder {
         # Walk the list of message headers matching the filter's
         # specified header.
         foreach $contents (@{$headers{lc($header)}}) {
-            # Walk the filter's list of match/expression pairs.
+            # Walk the filter's list of regexp/expression pairs.
             foreach $pair (@filter) {
-                ($match, $expression) = @$pair;
-                if ($contents =~ /$match/i) {
+                ($regexp, $expression) = @$pair;
+                if ($contents =~ $regexp) {
                     if (eval "\$result = \"$expression\"") {
                         return $result;
                     }
@@ -527,6 +605,7 @@ sub find_mh_folder {
 }
 
 sub filter_mail {
+    @_ or return ();
     my $msgcount = @_ - 2; # don't count . and ..
     my $len = length($msgcount);
     my @baton;
@@ -584,8 +663,6 @@ sub filter_mail {
             for ($from, $subject) {
                 tr/\x00-\x1f\x80-\xff/ /;
             }
-            print("\r");
-            print(' ' x $COLUMNS);
             printf("\r\%-${nf}s \%${nm}d \%-${nF}s \%s\n",
                    substr($mhfolder, 0, $nf), substr($msgnum, 0, $nm),
                    substr($from, 0, $nF),
@@ -596,7 +673,6 @@ sub filter_mail {
             $hook->(\%batons, \%headers, $mhfolder, $msgnum);
         }
 
-        print("\r");
         printf(" \%${len}d SPAM \%${len}d saved \%${len}d/%1d",
                $spam, $saved, $spam + $saved, $msgcount);
 
@@ -668,6 +744,35 @@ sub update_dot_folders {
     build_dot_folders($folders, $fh);
 }
 
+# XXX Could use some unification with getfiles...
+sub maildir_spam {
+    my $dir = "$MAILDIR/spam";
+
+    if (not chdir($dir)) {
+        print(STDERR "skipping maildir spam: chdir($dir): $!\n");
+        return;
+    }
+
+    if (not opendir(DIR, '.')) {
+        print(STDERR "skipping maildir spam: opendir($dir): $!\n");
+        return;
+    }
+
+    $! = 0;
+    my @spams = readdir(DIR);
+    if ($! != 0) {
+        print(STDERR "skipping maildir spam: readdir($dir): $!\n");
+        return;
+    }
+
+    closedir(DIR);
+
+    for my $msg (@spams) {
+        ($msg eq '.' or $msg eq '..') and next;
+        store_message($msg, 'SPAM');
+    }
+}
+
 \f
 MAIN: {
     my $st;
@@ -692,7 +797,9 @@ MAIN: {
                 }
                 getfiles('.'));
 
-    $run and update_dot_folders(\%folders);
+    $run and %folders and update_dot_folders(\%folders);
+
+    maildir_spam();
 
     @SPAM and (exec('scan', '+SPAM', @SPAM) or die);
 }