From 56e27b9e4c27fe037695515c8afa84fd8a31cf6d Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 5 Mar 2016 15:52:27 +0100 Subject: [PATCH] pullimap: mark downloaded messages as \Seen --- interimap | 4 ++-- lib/Net/IMAP/InterIMAP.pm | 17 +++++++++++++++-- pullimap | 10 ++++++++-- 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 +# Copyright © 2015,2016 Guilhem Moulin # # 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: $!"; -- 2.39.2