From 14e5d6b258c79b5982aafb804fdeeac35a21598c Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 06:56:04 +0200 Subject: Check return value after a SQL UPDATE. --- imapsync | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/imapsync b/imapsync index fec37f0..41e3538 100755 --- a/imapsync +++ b/imapsync @@ -337,7 +337,8 @@ sub sync_tree($$%) { # $missing's $mbx2, which is not in the database and # doesn't exist on $exists msg($exists, "Rename mailbox $mbx to $mbx2[0]"); - $sth->{rename}->execute($mbx2[0],$idx); + $sth->{rename}->execute($mbx2[0],$idx) or + msg('database', "WARNING: Can't rename $mbx to $mbx2[0]"); $IMAP->{$exists}->{client}->rename($mbx, $mbx2[0]); $DBH->commit(); mv_tree($IMAP->{$exists}->{mailboxes}, $mbx, $mbx2[0], %children); @@ -375,7 +376,8 @@ sub sync_tree($$%) { # database as associated with $mbx2, which exists on # $missing but not on $exists msg($missing, "Rename mailbox $mbx2 to $mbx"); - $sth->{rename}->execute($mbx,$idx); + $sth->{rename}->execute($mbx,$idx) or + msg('database', "WARNING: Can't rename $mbx2 to $mbx2"); $IMAP->{$missing}->{client}->rename($mbx2, $mbx); $DBH->commit(); mv_tree($IMAP->{$missing}->{mailboxes}, $mbx2, $mbx, %children); @@ -992,8 +994,10 @@ sub sync_messages($$;$$) { # don't store the new UIDNEXTs before to avoid downloading these # mails again in the event of a crash - $STH_UPDATE_LOCAL->execute($lIMAP->get_cache( qw/UIDNEXT HIGHESTMODSEQ/), $idx); - $STH_UPDATE_REMOTE->execute($rIMAP->get_cache(qw/UIDNEXT HIGHESTMODSEQ/), $idx); + $STH_UPDATE_LOCAL->execute($lIMAP->get_cache( qw/UIDNEXT HIGHESTMODSEQ/), $idx) or + msg('database', "WARNING: Can't update remote UIDNEXT/HIGHESTMODSEQ for $mailbox"); + $STH_UPDATE_REMOTE->execute($rIMAP->get_cache(qw/UIDNEXT HIGHESTMODSEQ/), $idx) or + msg('database', "WARNING: Can't update remote UIDNEXT/HIGHESTMODSEQ for $mailbox"); $DBH->commit(); } @@ -1139,8 +1143,10 @@ while(1) { elsif (sync_known_messages($IDX, $MAILBOX)) { # sync updates to known messages before fetching new messages # get_cache is safe after pull_update - $STH_UPDATE_LOCAL_HIGHESTMODSEQ->execute( $lIMAP->get_cache('HIGHESTMODSEQ'), $IDX); - $STH_UPDATE_REMOTE_HIGHESTMODSEQ->execute($rIMAP->get_cache('HIGHESTMODSEQ'), $IDX); + $STH_UPDATE_LOCAL_HIGHESTMODSEQ->execute( $lIMAP->get_cache('HIGHESTMODSEQ'), $IDX) and + msg('database', "WARNING: Can't update local HIGHESTMODSEQ for $MAILBOX"); + $STH_UPDATE_REMOTE_HIGHESTMODSEQ->execute($rIMAP->get_cache('HIGHESTMODSEQ'), $IDX) or + msg('database', "WARNING: Can't update remote HIGHESTMODSEQ for $MAILBOX"); $DBH->commit(); } sync_messages($IDX, $MAILBOX); -- cgit v1.2.3 From dd1bc08323df6fbd478fb665eff5e36f72e22fd0 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 06:57:22 +0200 Subject: wibble --- imapsync | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/imapsync b/imapsync index 41e3538..540797e 100755 --- a/imapsync +++ b/imapsync @@ -421,7 +421,7 @@ sub sync_tree($$%) { foreach qw/local remote/; $sth{$_.'_by_uidvalidity'} = $DBH->prepare("SELECT idx,mailbox FROM mailboxes NATURAL JOIN $_ WHERE UIDVALIDITY = ?") foreach qw/local remote/; - $sth{rename} = $DBH->prepare("UPDATE mailboxes SET mailbox = ? WHERE idx = ?"); + $sth{rename} = $DBH->prepare(q{UPDATE mailboxes SET mailbox = ? WHERE idx = ?}); my $updated = 0; while (my ($mbx,$children) = each %$tree) { @@ -447,8 +447,8 @@ sub sync_tree($$%) { # Syncronize subscription list my @SUBSCRIPTIONS; { - my $sth_search = $DBH->prepare("SELECT idx,subscribed FROM mailboxes WHERE mailbox = ?"); - my $sth_subscribe = $DBH->prepare("UPDATE mailboxes SET subscribed = ? WHERE idx = ?"); + my $sth_search = $DBH->prepare(q{SELECT idx,subscribed FROM mailboxes WHERE mailbox = ?}); + my $sth_subscribe = $DBH->prepare(q{UPDATE mailboxes SET subscribed = ? WHERE idx = ?}); my %mailboxes; $mailboxes{$_} = 1 foreach (keys %{$IMAP->{local}->{mailboxes}}, keys %{$IMAP->{remote}->{mailboxes}}); @@ -511,11 +511,11 @@ my @SUBSCRIPTIONS; # Clean database: remove mailboxes that no longer exist { - my $sth = $DBH->prepare("SELECT idx,mailbox,subscribed FROM mailboxes"); - my $sth_delete_mailboxes = $DBH->prepare("DELETE FROM mailboxes WHERE idx = ?"); - my $sth_delete_local = $DBH->prepare("DELETE FROM local WHERE idx = ?"); - my $sth_delete_remote = $DBH->prepare("DELETE FROM remote WHERE idx = ?"); - my $sth_delete_mapping = $DBH->prepare("DELETE FROM mapping WHERE idx = ?"); + my $sth = $DBH->prepare(q{SELECT idx,mailbox,subscribed FROM mailboxes}); + my $sth_delete_mailboxes = $DBH->prepare(q{DELETE FROM mailboxes WHERE idx = ?}); + my $sth_delete_local = $DBH->prepare(q{DELETE FROM local WHERE idx = ?}); + my $sth_delete_remote = $DBH->prepare(q{DELETE FROM remote WHERE idx = ?}); + my $sth_delete_mapping = $DBH->prepare(q{DELETE FROM mapping WHERE idx = ?}); my @idx; $sth->execute(); @@ -622,7 +622,7 @@ sub download_missing($$$@) { my $uid = $mail->{UID}; my $from = first { defined $_ and @$_ } @{$mail->{ENVELOPE}}[2,3,4]; $from = (defined $from and @$from) ? $from->[0]->[2].'@'.$from->[0]->[3] : ''; - msg("$source($mailbox): UID $uid from <$from> ($mail->{INTERNALDATE})") unless $CONFIG{quiet}; + msg(undef, "$source($mailbox): UID $uid from <$from> ($mail->{INTERNALDATE})") unless $CONFIG{quiet}; callback_new_message($idx, $mailbox, $source, $mail, \@uids, $buff, \$bufflen) }); @@ -637,8 +637,8 @@ sub flag_conflict($$$$$) { my %flags = map {$_ => 1} (split(/ /, $lFlags), split(/ /, $rFlags)); my $flags = join ' ', sort(keys %flags); - msg("WARNING: Conflicting flag update in $mailbox for local UID $lUID ($lFlags) ". - "and remote UID $rUID ($rFlags). Setting both to the union ($flags)."); + msg(undef, "WARNING: Conflicting flag update in $mailbox for local UID $lUID ($lFlags) ". + "and remote UID $rUID ($rFlags). Setting both to the union ($flags)."); return $flags } @@ -649,7 +649,7 @@ sub delete_mapping($$) { my ($idx, $lUID) = @_; my $r = $STH_DELETE_MAPPING->execute($idx, $lUID); die if $r > 1; # sanity check - msg("WARNING: Can't delete (idx,lUID) = ($idx,$lUID) from the database") if $r == 0; + msg('database', "WARNING: Can't delete (idx,lUID) = ($idx,$lUID)") if $r == 0; } @@ -701,7 +701,7 @@ sub repair($$) { } else { # conflict - msg("WARNING: Missed flag update in $mailbox for (lUID,rUID) = ($lUID,$rUID). Repairing.") + msg(undef, "WARNING: Missed flag update in $mailbox for (lUID,rUID) = ($lUID,$rUID). Repairing.") if $lModified->{$lUID}->[0] <= $cache->{lHIGHESTMODSEQ} and $rModified->{$rUID}->[0] <= $cache->{rHIGHESTMODSEQ}; # set both $lUID and $rUID to the union of $lFlags and $rFlags @@ -714,7 +714,7 @@ sub repair($$) { } elsif (!defined $lModified->{$lUID} and !defined $rModified->{$rUID}) { unless ($lVanished{$lUID} and $rVanished{$rUID}) { - msg("WARNING: Pair (lUID,rUID) = ($lUID,$rUID) vanished from $mailbox. Repairing."); + msg(undef, "WARNING: Pair (lUID,rUID) = ($lUID,$rUID) vanished from $mailbox. Repairing."); push @delete_mapping, $lUID; } } @@ -723,7 +723,7 @@ sub repair($$) { if ($lVanished{$lUID}) { push @rToRemove, $rUID; } else { - msg("local($mailbox): WARNING: UID $lUID disappeared. Downloading remote UID $rUID again."); + msg("local($mailbox)", "WARNING: UID $lUID disappeared. Downloading remote UID $rUID again."); push @rMissing, $rUID; } } @@ -732,7 +732,7 @@ sub repair($$) { if ($rVanished{$rUID}) { push @lToRemove, $lUID; } else { - msg("remote($mailbox): WARNING: UID $rUID disappeared. Downloading local UID $lUID again."); + msg("remote($mailbox)", "WARNING: UID $rUID disappeared. Downloading local UID $lUID again."); push @lMissing, $lUID; } } @@ -761,15 +761,15 @@ sub repair($$) { # Process UID found in IMAP but not in the mapping table. - msg("remote($mailbox): WARNING: No match for vanished local UID $_. Ignoring.") foreach keys %lVanished; - msg("local($mailbox): WARNING: No match for vanished remote UID $_. Ignoring.") foreach keys %rVanished; + msg("remote($mailbox)", "WARNING: No match for vanished local UID $_. Ignoring.") foreach keys %lVanished; + msg("local($mailbox)", "WARNING: No match for vanished remote UID $_. Ignoring.") foreach keys %rVanished; foreach my $lUID (keys %$lModified) { - msg("remote($mailbox): WARNING: No match for modified local UID $lUID. Downloading again."); + msg("remote($mailbox)", "WARNING: No match for modified local UID $lUID. Downloading again."); push @lMissing, $lUID; } foreach my $rUID (keys %$rModified) { - msg("local($mailbox): WARNING: No match for modified remote UID $rUID. Downloading again."); + msg("local($mailbox)", "WARNING: No match for modified remote UID $rUID. Downloading again."); push @rMissing, $rUID; } @@ -817,7 +817,7 @@ sub sync_known_messages($$) { my ($rUID) = $STH_GET_REMOTE_UID->fetchrow_array(); die if defined $STH_GET_REMOTE_UID->fetchrow_arrayref(); # sanity check if (!defined $rUID) { - msg("remote($mailbox): WARNING: No match for vanished local UID $lUID. Ignoring."); + msg("remote($mailbox)", "WARNING: No match for vanished local UID $lUID. Ignoring."); } elsif (!exists $rVanished{$rUID}) { push @rToRemove, $rUID; @@ -828,7 +828,7 @@ sub sync_known_messages($$) { my ($lUID) = $STH_GET_LOCAL_UID->fetchrow_array(); die if defined $STH_GET_LOCAL_UID->fetchrow_arrayref(); # sanity check if (!defined $lUID) { - msg("local($mailbox): WARNING: No match for vanished remote UID $rUID. Ignoring."); + msg("local($mailbox)", "WARNING: No match for vanished remote UID $rUID. Ignoring."); } elsif (!exists $lVanished{$lUID}) { push @lToRemove, $lUID; @@ -863,7 +863,7 @@ sub sync_known_messages($$) { my ($rUID) = $STH_GET_REMOTE_UID->fetchrow_array(); die if defined $STH_GET_REMOTE_UID->fetchrow_arrayref(); # sanity check if (!defined $rUID) { - msg("remote($mailbox): WARNING: No match for modified local UID $lUID. Try '--repair'."); + msg("remote($mailbox)", "WARNING: No match for modified local UID $lUID. Try '--repair'."); } elsif (defined (my $rFlags = $rModified->{$rUID})) { unless ($lFlags eq $rFlags) { @@ -884,7 +884,7 @@ sub sync_known_messages($$) { my ($lUID) = $STH_GET_LOCAL_UID->fetchrow_array(); die if defined $STH_GET_LOCAL_UID->fetchrow_arrayref(); # sanity check if (!defined $lUID) { - msg("local($mailbox): WARNING: No match for modified remote UID $rUID. Try '--repair'."); + msg("local($mailbox)", "WARNING: No match for modified remote UID $rUID. Try '--repair'."); } elsif (!exists $lModified->{$lUID}) { # conflicts are taken care of above @@ -917,7 +917,7 @@ sub callback_new_message($$$$;$$$) { my $length = length $mail->{RFC822}; if ($length == 0) { - msg("$name($mailbox): WARNING: Ignoring new 0-length message (UID $mail->{UID})"); + msg("$name($mailbox)", "WARNING: Ignoring new 0-length message (UID $mail->{UID})"); return; } -- cgit v1.2.3 From 32c088302a585fbba4890c8ff9ba5de7f9161ac6 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 06:58:27 +0200 Subject: Fix bug in synchronizing the subscription list. --- imapsync | 54 ++++++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/imapsync b/imapsync index 540797e..52d0157 100755 --- a/imapsync +++ b/imapsync @@ -454,58 +454,52 @@ my @SUBSCRIPTIONS; $mailboxes{$_} = 1 foreach (keys %{$IMAP->{local}->{mailboxes}}, keys %{$IMAP->{remote}->{mailboxes}}); foreach my $mbx (keys %mailboxes) { - if (subscribed_mbx('local',$mbx) xor subscribed_mbx('remote',$mbx)) { - my ($subscribed,$unsubscribed) = subscribed_mbx('local',$mbx) ? ('local','remote') : ('remote','local'); - - $sth_search->execute($mbx); - my $row = $sth_search->fetch(); - die if defined $sth_search->fetch(); # sanity check + $sth_search->execute($mbx); + my $row = $sth_search->fetch(); + die if defined $sth_search->fetch(); # sanity check + my ($lSubscribed,$rSubscribed) = map {subscribed_mbx($_,$mbx)} qw/local remote/; + if ($lSubscribed == $rSubscribed) { + if (defined $row) { + my ($idx,$status) = @$row; + if (defined $status and $status != $lSubscribed) { + $sth_subscribe->execute($lSubscribed, $idx) or + msg('database', "WARNING: Can't (un)subscribe $mbx"); + $DBH->commit(); + } + } + } + else { + my ($subscribed,$unsubscribed) = $lSubscribed ? qw/local remote/ : qw/remote local/; if (defined $row) { my ($idx,$status) = @$row; if ($status) { # $mbx was SUBSCRIBEd before, UNSUBSCRIBE it now msg($subscribed, "Unsubscribe to mailbox $mbx"); - $sth_subscribe->execute(0,$idx); + $sth_subscribe->execute(0,$idx) or + msg('database', "WARNING: Can't unsubscribe $mbx"); $IMAP->{$subscribed}->{client}->unsubscribe($mbx); $DBH->commit(); - $IMAP->{$subscribed}->{mailboxes}->{$mbx} = - grep {lc $_ ne lc '\Subscribed'} @{$IMAP->{$subscribed}->{mailboxes}->{$mbx} // []}; + $lSubscribed = $rSubscribed = 0; } else { # $mbx was UNSUBSCRIBEd before, SUBSCRIBE it now msg($unsubscribed, "Subscribe to mailbox $mbx"); - $sth_subscribe->execute(1,$idx); + $sth_subscribe->execute(1,$idx) or + msg('database', "WARNING: Can't subscribe $mbx"); $IMAP->{$unsubscribed}->{client}->subscribe($mbx); $DBH->commit(); - $IMAP->{$unsubscribed}->{mailboxes}->{$mbx} //= []; - push @{$IMAP->{$unsubscribed}->{mailboxes}->{$mbx}}, '\Subscribed'; + $lSubscribed = $rSubscribed = 1; } } else { # $mbx is unknown; assume the user wants to SUBSCRIBE msg($unsubscribed, "Subscribe to mailbox $mbx"); $IMAP->{$unsubscribed}->{client}->subscribe($mbx); - $IMAP->{$unsubscribed}->{mailboxes}->{$mbx} //= []; - push @{$IMAP->{$unsubscribed}->{mailboxes}->{$mbx}}, '\Subscribed'; - } - } - else { - $sth_search->execute($mbx); - my $row = $sth_search->fetch(); - die if defined $sth_search->fetch(); # sanity check - - if (defined $row) { - my ($idx,$status) = @$row; - unless (defined $status and $status != 0) { - my $subscribed = subscribed_mbx('local',$mbx) ? 1 : 0; - $sth_subscribe->execute($subscribed, $idx); - $DBH->commit(); - } + $lSubscribed = $rSubscribed = 1; } } - push @SUBSCRIPTIONS, $mbx if subscribed_mbx('local', $mbx) and - subscribed_mbx('remote',$mbx); + push @SUBSCRIPTIONS, $mbx if $lSubscribed; } } -- cgit v1.2.3 From 60ca37597c8cab4816405f470c871796d9c3c242 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 06:59:00 +0200 Subject: Fix typo in systemd service file. --- imapsync.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imapsync.service b/imapsync.service index e3a47e4..af63425 100644 --- a/imapsync.service +++ b/imapsync.service @@ -6,4 +6,4 @@ After=network.target ExecStart=/usr/bin/imapsync [Install] -WantedBy=multi-user.target +WantedBy=default.target -- cgit v1.2.3 From 81c6e4cd299d6f97f8d83dfd537df4d68e40771b Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 06:59:52 +0200 Subject: typo --- imapsync | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imapsync b/imapsync index 52d0157..9a4e2e9 100755 --- a/imapsync +++ b/imapsync @@ -1137,7 +1137,7 @@ while(1) { elsif (sync_known_messages($IDX, $MAILBOX)) { # sync updates to known messages before fetching new messages # get_cache is safe after pull_update - $STH_UPDATE_LOCAL_HIGHESTMODSEQ->execute( $lIMAP->get_cache('HIGHESTMODSEQ'), $IDX) and + $STH_UPDATE_LOCAL_HIGHESTMODSEQ->execute( $lIMAP->get_cache('HIGHESTMODSEQ'), $IDX) or msg('database', "WARNING: Can't update local HIGHESTMODSEQ for $MAILBOX"); $STH_UPDATE_REMOTE_HIGHESTMODSEQ->execute($rIMAP->get_cache('HIGHESTMODSEQ'), $IDX) or msg('database', "WARNING: Can't update remote HIGHESTMODSEQ for $MAILBOX"); -- cgit v1.2.3 From 0ceb23a6c85c1c77dfac5e8eac6bf66657d08d07 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 15:50:44 +0200 Subject: wibble --- imapsync | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imapsync b/imapsync index 9a4e2e9..c0da7d6 100755 --- a/imapsync +++ b/imapsync @@ -98,8 +98,8 @@ sub cleanup() { close $LOGGER_FD if defined $LOGGER_FD; $DBH->disconnect() if defined $DBH; } -$SIG{$_} = sub { cleanup(); msg($!); exit 1; } foreach qw/INT TERM/; -$SIG{$_} = sub { cleanup(); msg($!); exit 0; } foreach qw/HUP/; +$SIG{$_} = sub { cleanup(); msg(undef, $!); exit 1; } foreach qw/INT TERM/; +$SIG{$_} = sub { cleanup(); msg(undef, $!); exit 0; } foreach qw/HUP/; ############################################################################# @@ -444,7 +444,7 @@ sub sync_tree($$%) { } } -# Syncronize subscription list +# Synchronize subscription list my @SUBSCRIPTIONS; { my $sth_search = $DBH->prepare(q{SELECT idx,subscribed FROM mailboxes WHERE mailbox = ?}); @@ -1021,7 +1021,7 @@ my ($MAILBOX, $IDX); $STH_LIST_INTERRUPTED->execute(); while (defined (my $row = $STH_LIST_INTERRUPTED->fetchrow_arrayref())) { ($IDX, $MAILBOX) = @$row; - msg("Resuming interrupted sync for $MAILBOX"); + msg(undef, "Resuming interrupted sync for $MAILBOX"); my %lUIDs; $STH_GET_INTERRUPTED_BY_IDX->execute($IDX); -- cgit v1.2.3 From 464862335d1bc09437d4238214d30a1db7b829bd Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 15:53:13 +0200 Subject: bugfix: Fetching new messages from local and adding them to remote modifies its UIDNEXT. So we need to check again the first $source (remote) whenever the last one (local) added new messages to it. --- imapsync | 46 ++++++++++++++++++++++++++-------------------- lib/Net/IMAP/Sync.pm | 4 ++-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/imapsync b/imapsync index c0da7d6..25e65d6 100755 --- a/imapsync +++ b/imapsync @@ -961,26 +961,32 @@ sub callback_new_message_flush($$$@) { # the given UIDs. sub sync_messages($$;$$) { my ($idx, $mailbox, $lIgnore, $rIgnore) = @_; - my ($buff, $bufflen, @lUIDs); - - # get new messages from remote (except @$rIgnore) and APPEND them to local - ($buff, $bufflen) = ([], 0); - undef $buff if $lIMAP->incapable('MULTIAPPEND'); - $rIMAP->pull_new_messages(sub($) { - callback_new_message($idx, $mailbox, 'remote', shift, \@lUIDs, $buff, \$bufflen) - }, @{$rIgnore // []}); - push @lUIDs, callback_new_message_flush($idx, $mailbox, 'remote', @$buff) - if defined $buff and @$buff; - - # get new messages from local (except @$lIgnore and the newly allocated local - # UIDs @lUIDs) and APPEND them to remote - ($buff, $bufflen) = ([], 0); - undef $buff if $rIMAP->incapable('MULTIAPPEND'); - $lIMAP->pull_new_messages(sub($) { - callback_new_message($idx, $mailbox, 'local', shift, undef, $buff, \$bufflen) - }, @{$lIgnore // []}, @lUIDs); - callback_new_message_flush($idx, $mailbox, 'local', @$buff) - if defined $buff and @$buff; + + my %ignore = (local => ($lIgnore // []), remote => ($rIgnore // [])); + my $loop; + do { + # get new messages from $source (except @{$ignore{$source}}) and APPEND them to $target + foreach my $source (qw/remote local/) { # pull remote mails first + my $target = $source eq 'remote' ? 'local' : 'remote'; + my $buff = [] unless ($target eq 'local' ? $lIMAP : $rIMAP)->incapable('MULTIAPPEND'); + my $bufflen = 0; + my @tUIDs; + + ($source eq 'remote' ? $rIMAP : $lIMAP)->pull_new_messages(sub($) { + callback_new_message($idx, $mailbox, $source, shift, \@tUIDs, $buff, \$bufflen) + }, @{$ignore{$source}}); + + push @tUIDs, callback_new_message_flush($idx, $mailbox, $source, @$buff) + if defined $buff and @$buff; + push @{$ignore{$target}}, @tUIDs; + + $loop = @tUIDs ? 1 : 0; + } + # since $source modifies $target's UIDNEXT upon new mails, we + # need to check again the first $source (remote) whenever the + # last one (local) added new messages to it + } + while ($loop); # both local and remote UIDNEXT are now up to date; proceed with # pending flag updates and vanished messages diff --git a/lib/Net/IMAP/Sync.pm b/lib/Net/IMAP/Sync.pm index 26303a6..bf56519 100644 --- a/lib/Net/IMAP/Sync.pm +++ b/lib/Net/IMAP/Sync.pm @@ -657,12 +657,12 @@ sub append($$@) { my @uids; foreach (split /,/, $uidset) { if (/\A([0-9]+)\z/) { - $UIDNEXT = $1 + 1 if $UIDNEXT <= $1; + $UIDNEXT = $1 + 1 if defined $UIDNEXT and $UIDNEXT <= $1; push @uids, $1; } elsif (/\A([0-9]+):([0-9]+)\z/) { my ($min, $max) = $1 <= $2 ? ($1,$2) : ($2,$1); push @uids, ($min .. $max); - $UIDNEXT = $max + 1 if $UIDNEXT <= $max; + $UIDNEXT = $max + 1 if defined $UIDNEXT and $UIDNEXT <= $max; } else { $self->panic($_); } -- cgit v1.2.3 From 9784997b21a30a2c5a8db3742a42faebad9e169d Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 19:42:35 +0200 Subject: typo --- imapsync | 21 ++++++++------------- lib/Net/IMAP/Sync.pm | 1 - 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/imapsync b/imapsync index 25e65d6..b9d2d31 100755 --- a/imapsync +++ b/imapsync @@ -93,13 +93,13 @@ my $DBH; # Clean after us sub cleanup() { - logger("Cleaning up...") if $CONFIG{debug}; + logger(undef, "Cleaning up...") if $CONFIG{debug}; unlink $LOCKFILE if defined $LOCKFILE and -f $LOCKFILE; close $LOGGER_FD if defined $LOGGER_FD; $DBH->disconnect() if defined $DBH; } -$SIG{$_} = sub { cleanup(); msg(undef, $!); exit 1; } foreach qw/INT TERM/; -$SIG{$_} = sub { cleanup(); msg(undef, $!); exit 0; } foreach qw/HUP/; +$SIG{$_} = sub { msg(undef, $!); cleanup(); exit 1; } foreach qw/INT TERM/; +$SIG{$_} = sub { msg(undef, $!); cleanup(); exit 0; } foreach qw/HUP/; ############################################################################# @@ -627,7 +627,7 @@ sub download_missing($$$@) { # Solve a flag update conflict (by taking the union of the two flag lists). sub flag_conflict($$$$$) { - my ($mailbox, $lUID, $lFlags, $rUID, $rFlags); + my ($mailbox, $lUID, $lFlags, $rUID, $rFlags) = @_; my %flags = map {$_ => 1} (split(/ /, $lFlags), split(/ /, $rFlags)); my $flags = join ' ', sort(keys %flags); @@ -947,7 +947,8 @@ sub callback_new_message_flush($$$@) { my ($lUIDs, $rUIDs) = $name eq 'local' ? (\@sUID,\@tUID) : (\@tUID,\@sUID); for (my $k=0; $k<=$#messages; $k++) { - logger("Adding mapping (lUID,rUID) = ($lUIDs->[$k],$rUIDs->[$k]) for $mailbox") if $CONFIG{debug}; + logger(undef, "Adding mapping (lUID,rUID) = ($lUIDs->[$k],$rUIDs->[$k]) for $mailbox") + if $CONFIG{debug}; $STH_INSERT_MAPPING->execute($idx, $lUIDs->[$k], $rUIDs->[$k]); } $DBH->commit(); # commit only once per batch @@ -1102,10 +1103,7 @@ while (@REPAIR) { $rIMAP->select($MAILBOX); repair($IDX, $MAILBOX); } -if ($CONFIG{repair}) { - cleanup(); - exit 0; -} +exit 0 if $CONFIG{repair}; while(1) { @@ -1153,10 +1151,7 @@ while(1) { } } # clean state! - if ($CONFIG{oneshot}) { - cleanup(); - exit 0; - } + exit 0 if $CONFIG{oneshot}; wait_notifications(900); } diff --git a/lib/Net/IMAP/Sync.pm b/lib/Net/IMAP/Sync.pm index bf56519..3216483 100644 --- a/lib/Net/IMAP/Sync.pm +++ b/lib/Net/IMAP/Sync.pm @@ -736,7 +736,6 @@ sub slurp($) { # select(2) to block/timeout due to the raw socket not being # ready. unless (ref $stdout eq 'IO::Socket::SSL' and $stdout->pending() > 0) { - my $sel = IO::Select::->new($stdout); my ($ok) = $self->{_SEL_OUT}->can_read(0); return $read unless defined $ok; } -- cgit v1.2.3 From 8993a9dcb8dedb43e8f8c1b86e1f193da29bcf64 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 26 Jul 2015 19:52:52 +0200 Subject: Make --oneshot the default mode and disable watch mode. Due to multiple bugs in dovecot 2.13 and 2.18's implementation of the NOTIFY extension [RFC5465]: http://dovecot.org/pipermail/dovecot/2015-July/101473.html http://dovecot.org/pipermail/dovecot/2015-July/101474.html http://dovecot.org/pipermail/dovecot/2015-July/101514.html --- imapsync | 9 +++++---- imapsync.1 | 19 +------------------ 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/imapsync b/imapsync index b9d2d31..339979c 100755 --- a/imapsync +++ b/imapsync @@ -47,7 +47,6 @@ sub usage(;$) { print STDERR "Synchronize the given MAILBOXes between two QRESYNC-capable IMAP4rev1 servers.\n" ."Options:\n" ." --config=FILE Specify an alternate configuration file\n" - ." -1, --oneshot Exit as soon as all mailboxes are synchronized\n" ." --repair List the database anomalies and try to repair them\n" ." -q, --quiet Try to be quiet\n" ." --debug Turn on debug mode\n" @@ -55,7 +54,7 @@ sub usage(;$) { } exit $rv; } -usage(1) unless GetOptions(\%CONFIG, qw/config=s quiet|q oneshot|1 repair debug help|h/); +usage(1) unless GetOptions(\%CONFIG, qw/config=s quiet|q repair debug help|h/); usage(0) if $CONFIG{help}; @@ -224,7 +223,9 @@ foreach my $name (qw/local remote/) { #my $mailboxes = $client->list((uc $config{'subscribed-only'} eq 'TRUE' ? '(SUBSCRIBED)' : '' ) # .$config{mailboxes}, 'SUBSCRIBED'); # $client->notify('SELECTED', 'MAILBOXES ('.join(' ', keys %$mailboxes).')'); - $client->notify(qw/SELECTED SUBSCRIBED/) unless $CONFIG{oneshot}; + # XXX NOTIFY doesn't work as expected for INBOX + # http://dovecot.org/pipermail/dovecot/2015-July/101514.html + #$client->notify(qw/SELECTED SUBSCRIBED/) if $CONFIG{watch}; # 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 @@ -1151,7 +1152,7 @@ while(1) { } } # clean state! - exit 0 if $CONFIG{oneshot}; + exit 0 unless $CONFIG{watch}; wait_notifications(900); } diff --git a/imapsync.1 b/imapsync.1 index f4f6965..8c22222 100644 --- a/imapsync.1 +++ b/imapsync.1 @@ -10,8 +10,7 @@ imapsync \- IMAP-to-IMAP synchronization program for QRESYNC-capable servers .SH DESCRIPTION .PP .B imapsync\fR performs stateful synchronization between two IMAP4rev1 -servers, then (unless the flag \fB\-\-oneshot\fR is set) keeps both -connection open and wait for new changes to arrive. +servers. Such synchronization is made possible by the QRESYNC extension from [RFC7162]; for convenience reasons support for LIST\-EXTENDED [RFC5258], LIST\-STATUS [RFC5819] and UIDPLUS [RFC4315] is also required. @@ -76,15 +75,6 @@ By default \fBimapsync\fR synchronizes each mailbox listed by the providing extra arguments limits the synchronization to the given \fIMAILBOX\fRes only. -.PP -In its default mode (unless the flag \fB\-\-oneshot\fR or -\fB\-\-repair\fR is set), \fBimapsync\fR does not exit once all -mailboxes have been synchronized. Instead, it keeps both connection -open and uses the NOTIFY command from [RFC5465] to be notified of new -changes (on any mailbox) as soon as they arrive. If no update is sent -in 15 minutes, a NOOP command is issued in order not to trigger the -servers' inactivity timeout and be logged out. - .PP If the synchronization was interrupted during a previous run while some messages were being replicated (but before the UIDNEXT or HIGHESTMODSEQ @@ -103,13 +93,6 @@ Specify an alternate configuration file. Relative paths start from \fI$XDG_CONFIG_HOME\fR, or \fI~/.config\fR if the XDG_CONFIG_HOME environment variable is unset. -.TP -.B \-1\fR, \fB\-\-oneshot\fR -Exit as soon as all mailboxes are synchronized, instead of passively -waiting for updates from the open connections. -Using \fB\-\-oneshot\fR removes the requirement that IMAP servers must -advertise support the NOTIFY extension [RFC5465]. - .TP .B \-\-repair List the database anomalies and try to repair them. -- cgit v1.2.3