use v5.10.1;
use parent qw(PublicInbox::IPC PublicInbox::LeiInput);
use Errno qw(EEXIST ENOENT);
+use PublicInbox::Syscall qw(rename_noreplace);
sub export_kw_md { # LeiMailSync->each_src callback
my ($oidbin, $id, $self, $mdir) = @_;
my $lei = $self->{lei};
for my $d (@try) {
my $src = "$mdir/$d/$$id";
-
- # we use link(2) + unlink(2) since rename(2) may
- # inadvertently clobber if the "uniquefilename" part wasn't
- # actually unique.
- if (link($src, $dst)) { # success
- # unlink(2) may ENOENT from parallel invocation,
- # ignore it, but not other serious errors
- if (!unlink($src) and $! != ENOENT) {
- $lei->child_error(1, "E: unlink($src): $!");
- }
- $lei->{sto}->ipc_do('lms_mv_src', "maildir:$mdir",
+ if (rename_noreplace($src, $dst)) { # success
+ $self->{lms}->mv_src("maildir:$mdir",
$oidbin, $id, $bn);
- return; # success anyways if link(2) worked
+ return; # success
} elsif ($! == EEXIST) { # lost race with lei/store?
return;
} elsif ($! != ENOENT) {
- $lei->child_error(1, "E: link($src -> $dst): $!");
+ $lei->child_error(1,
+ "E: rename_noreplace($src -> $dst): $!");
} # else loop @try
}
my $e = $!;
# both tries failed
my $oidhex = unpack('H*', $oidbin);
my $src = "$mdir/{".join(',', @try)."}/$$id";
- $lei->child_error(1, "link($src -> $dst) ($oidhex): $e");
+ $lei->child_error(1, "rename_noreplace($src -> $dst) ($oidhex): $e");
for (@try) { return if -e "$mdir/$_/$$id" }
- $lei->{sto}->ipc_do('lms_clear_src', "maildir:$mdir", $id);
+ $self->{lms}->clear_src("maildir:$mdir", $id);
}
sub export_kw_imap { # LeiMailSync->each_src callback
# overrides PublicInbox::LeiInput::input_path_url
sub input_path_url {
my ($self, $input, @args) = @_;
- my $lms = $self->{-lms_ro} //= $self->{lse}->lms;
+ $self->{lms}->lms_write_prepare;
if ($input =~ /\Amaildir:(.+)/i) {
my $mdir = $1;
require PublicInbox::LeiToMail; # kw2suffix
- $lms->each_src($input, \&export_kw_md, $self, $mdir);
+ $self->{lms}->each_src($input, \&export_kw_md, $self, $mdir);
} elsif ($input =~ m!\Aimaps?://!i) {
my $uri = PublicInbox::URIimap->new($input);
my $mic = $self->{nwr}->mic_for_folder($uri);
- $lms->each_src($$uri, \&export_kw_imap, $self, $mic);
- $mic->expunge;
+ if ($mic && !$self->{nwr}->can_store_flags($mic)) {
+ my $m = "$input does not support PERMANENTFLAGS";
+ if (defined $self->{lei}->{opt}->{all}) {
+ $self->{lei}->qerr("# $m");
+ } else { # set error code if user explicitly requested
+ $self->{lei}->child_error(0, "E: $m");
+ }
+ return;
+ }
+ if ($mic) {
+ $self->{lms}->each_src($$uri, \&export_kw_imap,
+ $self, $mic);
+ $mic->expunge;
+ } else {
+ $self->{lei}->child_error(0, "$input unavailable: $@");
+ }
} else { die "BUG: $input not supported" }
- my $wait = $self->{lei}->{sto}->ipc_do('done');
}
sub lei_export_kw {
my $sto = $lei->_lei_store or return $lei->fail(<<EOM);
lei/store uninitialized, see lei-import(1)
EOM
- my $lse = $sto->search;
- my $lms = $lse->lms or return $lei->fail(<<EOM);
+ my $lms = $lei->lms or return $lei->fail(<<EOM);
lei mail_sync uninitialized, see lei-import(1)
EOM
- my $opt = $lei->{opt};
- if (defined(my $all = $opt->{all})) { # --all=<local|remote>
+ if (defined(my $all = $lei->{opt}->{all})) { # --all=<local|remote>
$lms->group2folders($lei, $all, \@folders) or return;
+ @folders = grep(/\A(?:maildir|imaps?):/i, @folders);
} else {
- my $err = $lms->arg2folder($lei, \@folders);
- $lei->qerr(@{$err->{qerr}}) if $err->{qerr};
- return $lei->fail($err->{fail}) if $err->{fail};
+ $lms->arg2folder($lei, \@folders); # may die
}
- my $self = bless { lse => $lse }, __PACKAGE__;
+ $lms->lms_pause;
+ my $self = bless { lse => $sto->search, lms => $lms }, __PACKAGE__;
$lei->{opt}->{'mail-sync'} = 1; # for prepare_inputs
$self->prepare_inputs($lei, \@folders) or return;
- my $j = $opt->{jobs} // scalar(@{$self->{inputs}}) || 1;
if (my @ro = grep(!/\A(?:maildir|imaps?):/i, @folders)) {
return $lei->fail("cannot export to read-only folders: @ro");
}
- my $m = $opt->{mode} // 'merge';
+ my $m = $lei->{opt}->{mode} // 'merge';
if ($m eq 'merge') { # default
$self->{-merge_kw} = 1;
} elsif ($m eq 'set') {
$self->{nwr} = bless $net, 'PublicInbox::NetWriter';
$self->{imap_mod_kw} = $net->can($self->{-merge_kw} ?
'imap_add_kw' : 'imap_set_kw');
+ $self->{nwr}->{-skip_creat} = 1;
}
- undef $lms; # for fork
- my $ops = {};
- $sto->write_prepare($lei);
- $lei->{auth}->op_merge($ops, $self) if $lei->{auth};
- $self->{-wq_nr_workers} = $j // 1; # locked
- (my $op_c, $ops) = $lei->workers_start($self, $j, $ops);
- $lei->{wq1} = $self;
$lei->{-err_type} = 'non-fatal';
- net_merge_all_done($self) unless $lei->{auth};
- $lei->wait_wq_events($op_c, $ops); # net_merge_all_done if !{auth}
+ $lei->wq1_start($self);
}
sub _complete_export_kw {
my ($lei, @argv) = @_;
- my $sto = $lei->_lei_store or return;
- my $lms = $sto->search->lms or return;
+ my $lms = $lei->lms or return ();
my $match_cb = $lei->complete_url_prepare(\@argv);
- map { $match_cb->($_) } $lms->folders;
+ # filter-out read-only sources:
+ my @k = grep(m!(?:maildir|imaps?):!,
+ $lms->folders($argv[-1] // undef, 1));
+ my @m = map { $match_cb->($_) } @k;
+ @m ? @m : @k;
}
no warnings 'once';