aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2016-03-05 15:52:27 +0100
committerGuilhem Moulin <guilhem@fripost.org>2016-03-05 15:52:27 +0100
commit56e27b9e4c27fe037695515c8afa84fd8a31cf6d (patch)
treeab018b39dca0db776c1513ba735d9eb0f6db2411
parente9e360cbe894b5674a3ffe433e5d727cf8368715 (diff)
pullimap: mark downloaded messages as \Seen
-rwxr-xr-xinterimap4
-rw-r--r--lib/Net/IMAP/InterIMAP.pm17
-rwxr-xr-xpullimap10
3 files changed, 25 insertions, 6 deletions
diff --git a/interimap b/interimap
index f8989dc..b377d4e 100755
--- a/interimap
+++ b/interimap
@@ -2,7 +2,7 @@
#----------------------------------------------------------------------
# Fast bidirectional synchronization for QRESYNC-capable IMAP servers
-# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+# Copyright © 2015,2016 Guilhem Moulin <guilhem@fripost.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -65,12 +65,12 @@ usage(1) if defined $COMMAND and defined $CONFIG{watch};
usage(1) if $CONFIG{target} and !(defined $COMMAND and ($COMMAND eq 'delete'or $COMMAND eq 'rename'));
$CONFIG{watch} = 60 if defined $CONFIG{watch} and $CONFIG{watch} == 0;
@ARGV = map {uc $_ eq 'INBOX' ? 'INBOX' : $_ } @ARGV; # INBOX is case-insensitive
+die "Invalid mailbox name $_" foreach grep !/\A([\x01-\x7F]+)\z/, @ARGV;
my $CONF = read_config( delete $CONFIG{config} // $NAME
, [qw/_ local remote/]
, database => qr/\A(\P{Control}+)\z/
- , logfile => qr/\A(\/\P{Control}+)\z/
, 'list-mailbox' => qr/\A([\x01-\x09\x0B\x0C\x0E-\x7F]+)\z/
, 'list-select-opts' => qr/\A([\x21\x23\x24\x26\x27\x2B-\x5B\x5E-\x7A\x7C-\x7E]+)\z/
, 'ignore-mailbox' => qr/\A([\x01-\x09\x0B\x0C\x0E-\x7F]+)\z/
diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm
index 7d6e468..15682b3 100644
--- a/lib/Net/IMAP/InterIMAP.pm
+++ b/lib/Net/IMAP/InterIMAP.pm
@@ -58,6 +58,7 @@ my %OPTIONS = (
command => qr/\A(\P{Control}+)\z/,
'null-stderr' => qr/\A(YES|NO)\z/i,
compress => qr/\A($RE_ATOM_CHAR+(?: $RE_ATOM_CHAR+)*)\z/,
+ logfile => qr/\A(\/\P{Control}+)\z/,
SSL_protocols => qr/\A(!?$RE_SSL_PROTO(?: !?$RE_SSL_PROTO)*)\z/,
SSL_fingerprint => qr/\A((?:[A-Za-z0-9]+\$)?\p{AHex}+)\z/,
SSL_cipherlist => qr/\A(\P{Control}+)\z/,
@@ -535,9 +536,10 @@ sub logger($@) {
if (defined $self->{'logger-fd'}->fileno and defined $self->{'logger-fd'}->fileno
and $self->{'logger-fd'}->fileno != fileno STDERR) {
my ($s, $us) = Time::HiRes::gettimeofday();
- $prefix = POSIX::strftime("%b %e %H:%M:%S", localtime($s)).".$us ";
+ $prefix = POSIX::strftime("%b %e %H:%M:%S", localtime($s)).".$us";
+ $prefix .= ' ' if defined $self->{name} or $self->{_STATE} eq 'SELECTED';
}
- $prefix .= $self->{name} // '';
+ $prefix .= $self->{name} if defined $self->{name};
$prefix .= "($self->{_SELECTED})" if $self->{_STATE} eq 'SELECTED';
$prefix .= ': ' unless $prefix eq '';
$self->{'logger-fd'}->say($prefix, @_);
@@ -1255,6 +1257,17 @@ sub push_flag_updates($$@) {
}
+# $self->silent_store($set, $mod, @flags)
+# Set / Add / Update the flags list on the UID $set.
+# /!\ there is no check that messages flags been set!
+sub silent_store($$$@) {
+ my $self = shift;
+ my $set = shift;
+ my $mod = shift;
+ $self->_send("UID STORE $set ${mod}FLAGS.SILENT (".join(' ', @_).")");
+}
+
+
#############################################################################
# Private methods
diff --git a/pullimap b/pullimap
index d1a2f4a..e79e644 100755
--- a/pullimap
+++ b/pullimap
@@ -29,7 +29,7 @@ use Getopt::Long qw/:config posix_default no_ignore_case gnu_getopt auto_version
use List::Util 'first';
use lib 'lib';
-use Net::IMAP::InterIMAP 'read_config';
+use Net::IMAP::InterIMAP qw/read_config compact_set/;
my %CONFIG;
sub usage(;$) {
@@ -140,11 +140,16 @@ do {
writeUID(1);
}
else {
+ # put the remaining UIDs in the @ignore list: these messages
+ # have already been delivered, but the process exited before the
+ # statefile was updated
while (defined (my $uid = readUID())) {
push @ignore, $uid;
}
}
+ # use BODY.PEEK[] so if something gets wrong, unpulled messages
+ # won't be marked as \Seen in the mailbox
my $attrs = join ' ', qw/ENVELOPE INTERNALDATE BODY.PEEK[]/;
my @uid;
@@ -163,7 +168,8 @@ do {
writeUID($uid);
}, @ignore);
- # TODO mark (@ignore, @uid) as seen
+ # now that everything has been deliverd, mark @ignore and @uid as \Seen
+ $IMAP->silent_store(compact_set(@ignore, @uid), '+', '\Seen') if @ignore or @uid;
# update the statefile
sysseek($STATE, 4, SEEK_SET) // die "Can't seek: $!";