]> git.g-eek.se Git - interimap.git/commitdiff
Add an option --watch to keep the connections open and wait for changes.
authorGuilhem Moulin <guilhem@fripost.org>
Mon, 7 Sep 2015 22:59:39 +0000 (00:59 +0200)
committerGuilhem Moulin <guilhem@fripost.org>
Mon, 7 Sep 2015 22:59:39 +0000 (00:59 +0200)
interimap
interimap.1
interimap.service
lib/Net/IMAP/InterIMAP.pm

index 9998427d1dc60cb99b00ade74d14c5612b5b984f..ed80b5afe1a98c7cf7ba0b1cdfef5e92107f8668 100755 (executable)
--- a/interimap
+++ b/interimap
@@ -53,7 +53,7 @@ sub usage(;$) {
 }
 
 my @COMMANDS = qw/repair delete rename/;
-usage(1) unless GetOptions(\%CONFIG, qw/config=s quiet|q target=s@ debug help|h/, @COMMANDS);
+usage(1) unless GetOptions(\%CONFIG, qw/config=s quiet|q target=s@ debug help|h watch:i/, @COMMANDS);
 usage(0) if $CONFIG{help};
 my $COMMAND = do {
     my @command = grep {exists $CONFIG{$_}} @COMMANDS;
@@ -61,6 +61,8 @@ my $COMMAND = do {
     $command[0]
 };
 usage(1) if defined $COMMAND and (($COMMAND eq 'delete' and !@ARGV) or $COMMAND eq 'rename' and $#ARGV != 1);
+usage(1) if defined $COMMAND and defined $CONFIG{watch};
+$CONFIG{watch} = 60 if defined $CONFIG{watch} and $CONFIG{watch} == 0;
 @ARGV = map {uc $_ eq 'INBOX' ? 'INBOX' : $_ } @ARGV; # INBOX is case-insensitive
 
 
@@ -225,6 +227,17 @@ logger(undef, ">>> $NAME $VERSION");
 #############################################################################
 # Connect to the local and remote IMAP servers
 
+my $LIST = '"" ';
+my @LIST_PARAMS;
+if (!defined $COMMAND or $COMMAND eq 'repair') {
+    $LIST  = '('.uc($CONF->{_}->{'list-select-opts'}).') '.$LIST if defined $CONF->{_}->{'list-select-opts'};
+    $LIST .= (defined $CONF->{_}->{'list-mailbox'} ? '('.$CONF->{_}->{'list-mailbox'}.')' : '*') unless @ARGV;
+    @LIST_PARAMS = ('SUBSCRIBED', 'STATUS (UIDVALIDITY UIDNEXT HIGHESTMODSEQ)');
+}
+$LIST .= $#ARGV == 0 ? Net::IMAP::InterIMAP::quote($ARGV[0])
+       : ('('.join(' ',map {Net::IMAP::InterIMAP::quote($_)} @ARGV).')') if @ARGV;
+
+
 my $IMAP;
 foreach my $name (qw/local remote/) {
     my %config = %{$CONF->{$name}};
@@ -250,19 +263,9 @@ foreach my $name (qw/local remote/) {
     # XXX We shouldn't need to ask for STATUS responses here, and use
     #     NOTIFY's STATUS indicator instead.  However Dovecot violates RFC
     #     5464: http://dovecot.org/pipermail/dovecot/2015-July/101474.html
-
-    my $list = '"" ';
-    my @params;
-    if (!defined $COMMAND or $COMMAND eq 'repair') {
-        $list  = '('.uc($CONF->{_}->{'list-select-opts'}).') '.$list if defined $CONF->{_}->{'list-select-opts'};
-        $list .= (defined $CONF->{_}->{'list-mailbox'} ? '('.$CONF->{_}->{'list-mailbox'}.')' : '*') unless @ARGV;
-        @params = ('SUBSCRIBED', 'STATUS (UIDVALIDITY UIDNEXT HIGHESTMODSEQ)');
-    }
-    $list .= $#ARGV == 0 ? Net::IMAP::InterIMAP::quote($ARGV[0])
-           : ('('.join(' ',map {Net::IMAP::InterIMAP::quote($_)} @ARGV).')') if @ARGV;
-    @{$IMAP->{$name}}{qw/mailboxes delims/} = $client->list($list, @params);
 }
 
+@{$IMAP->{$_}}{qw/mailboxes delims/} = $IMAP->{$_}->{client}->list($LIST, @LIST_PARAMS) for qw/local remote/;
 
 ##############################################################################
 #
@@ -414,7 +417,7 @@ elsif (defined $COMMAND and $COMMAND eq 'rename') {
 # Synchronize mailbox and subscription lists
 
 my @MAILBOXES;
-{
+sub sync_mailbox_list() {
     my %mailboxes;
     $mailboxes{$_} = 1 foreach keys %{$IMAP->{local}->{mailboxes}};
     $mailboxes{$_} = 1 foreach keys %{$IMAP->{remote}->{mailboxes}};
@@ -501,8 +504,9 @@ my @MAILBOXES;
         }
     }
 }
+
+sync_mailbox_list();
 my ($lIMAP, $rIMAP) = map {$IMAP->{$_}->{client}} qw/local remote/;
-undef $IMAP;
 
 
 #############################################################################
@@ -1189,8 +1193,25 @@ while(1) {
         }
     }
     # clean state!
-    exit 0 unless defined $COMMAND and $COMMAND eq 'watch';
-    wait_notifications(900);
+    exit 0 unless $CONFIG{watch};
+
+    # we need to issue a NOOP command or go back to AUTH state since the
+    # LIST command may not report the correct HIGHESTMODSEQ value for
+    # the mailbox currently selected.
+    if (defined $MAILBOX) {
+        # Prefer UNSELECT over NOOP commands as it requires a single command per cycle
+        if ($lIMAP->incapable('UNSELECT') or $rIMAP->incapable('UNSELECT')) {
+            $_->noop() foreach ($lIMAP, $rIMAP);
+        } else {
+            $_->unselect() foreach ($lIMAP, $rIMAP);
+            undef $MAILBOX;
+        }
+    }
+
+    sleep $CONFIG{watch};
+    # Refresh the mailbox list and status
+    @{$IMAP->{$_}}{qw/mailboxes delims/} = $IMAP->{$_}->{client}->list($LIST, @LIST_PARAMS) for qw/local remote/;
+    sync_mailbox_list();
 }
 
 END {
index 00b87e342725949288045fb1e7308eb1d437e4b3..44235fcb47a4a061a7c78257990f61893a240e14 100644 (file)
@@ -144,6 +144,12 @@ Limit the scope of a \fB\-\-delete\fR or \fB\-\-rename\fR command
 to the given target.  Can be repeated to act on multiple targets.  By
 default all three targets are considered.
 
+.TP
+.B \fB\-\-watch\fR[\fB=\fR\fIseconds\fR]
+Don't exit after a successful synchronization, and keep synchronizing
+forevever instead.  Sleep for the given number of \fIseconds\fR (or
+\(lq60\(rq if omitted) between two synchronizations.
+
 .TP
 .B \-q\fR, \fB\-\-quiet\fR
 Try to be quiet.
index 7f2d03501ac5de9015201ffa2b3ee9e22d0652b1..2dc15069ca417b7a2744a21fec52d057d65ebbdb 100644 (file)
@@ -4,9 +4,9 @@ Wants=network-online.target
 After=network-online.target
 
 [Service]
-ExecStart=/usr/bin/interimap
-RestartSec=60s
-Restart=always
+ExecStart=/usr/bin/interimap --watch
+RestartSec=10min
+Restart=on-failure
 
 [Install]
 WantedBy=default.target
index 35d207578a5ba75aca3903e9481d5d9b1fa219ce..97756f4490f44413412c88e1f77060c69ac31cfd 100644 (file)
@@ -526,6 +526,25 @@ sub examine($$;$$) {
 }
 
 
+# $self->unselect()
+#   Issue an UNSELECT command (cf. RFC 3691). Upon success, change the
+#   state to AUTH.
+sub unselect($) {
+    my $self = shift;
+
+    $self->_send('UNSELECT');
+
+    $self->{_STATE} = 'AUTH';
+    delete $self->{_SELECTED};
+
+    # it is safe to wipe cached VANISHED responses or FLAG updates,
+    # because interesting stuff must have made the mailbox dirty so
+    # we'll get back to it
+    $self->{_VANISHED} = [];
+    $self->{_MODIFIED} = {};
+}
+
+
 # $self->logout()
 #   Issue a LOGOUT command.  Change the state to LOGOUT.
 sub logout($) {