]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/LeiExportKw.pm
lei export-kw: relax IMAP URL matching
[public-inbox.git] / lib / PublicInbox / LeiExportKw.pm
index db4f7441d3b753293b51e7a5604e7d98b64fbfb0..82a4db04f987e45287618004ae9a22d17bfe566b 100644 (file)
@@ -59,18 +59,62 @@ sub export_kw_md { # LeiMailSync->each_src callback
        $self->{lei}->child_error(1, "link($orig, $dst) ($oidhex): $e");
 }
 
+sub export_kw_imap { # LeiMailSync->each_src callback
+       my ($oidbin, $id, $self, $mic) = @_;
+       my $oidhex = unpack('H*', $oidbin);
+       my $sto_kw = $self->{lse}->oid_keywords($oidhex) or return;
+       $self->{imap_mod_kw}->($self->{nwr}, $mic, $id, [ keys %$sto_kw ]);
+}
+
 # overrides PublicInbox::LeiInput::input_path_url
 sub input_path_url {
        my ($self, $input, @args) = @_;
        my $lms = $self->{lms} //= $self->{lse}->lms;
        $lms->lms_begin;
-       if ($input =~ s/\Amaildir://i) {
+       if ($input =~ /\Amaildir:(.+)/i) {
+               my $mdir = $1;
                require PublicInbox::LeiToMail; # kw2suffix
-               $lms->each_src("maildir:$input", \&export_kw_md, $self, $input);
-       }
+               $lms->each_src($input, \&export_kw_md, $self, $mdir);
+       } elsif ($input =~ m!\Aimaps?://!) {
+               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;
+       } else { die "BUG: $input not supported" }
        $lms->lms_commit;
 }
 
+sub match_imap_url ($$) {
+       my ($all, $url) = @_; # $all = [ $lms->folders ];
+       require PublicInbox::URIimap;
+       my $cli = PublicInbox::URIimap->new($url)->canonical;
+       my ($s, $h, $mb) = ($cli->scheme, $cli->host, $cli->mailbox);
+       my @uri = map { PublicInbox::URIimap->new($_)->canonical }
+               grep(m!\A\Q$s\E://.*?\Q$h\E\b.*?/\Q$mb\E\b!, @$all);
+       my @match;
+       for my $x (@uri) {
+               next if $x->mailbox ne $cli->mailbox;
+               next if $x->host ne $cli->host;
+               next if $x->port != $cli->port;
+               my $x_uidval = $x->uidvalidity;
+               next if ($cli->uidvalidity // $x_uidval) != $x_uidval;
+
+               # allow nothing in CLI to possibly match ";AUTH=ANONYMOUS"
+               if (defined($x->auth) && !defined($cli->auth) &&
+                               !defined($cli->user)) {
+                       push @match, $x;
+               # or maybe user was forgotten on CLI:
+               } elsif (defined($x->user) && !defined($cli->user)) {
+                       push @match, $x;
+               } elsif (($x->user//"\0") eq ($cli->user//"\0")) {
+                       push @match, $x;
+               }
+       }
+       return $match[0] if scalar(@match) <= 1;
+       warn "E: `$url' is ambiguous:\n\t", join("\n\t", @match), "\n";
+       undef;
+}
+
 sub lei_export_kw {
        my ($lei, @folders) = @_;
        my $sto = $lei->_lei_store or return $lei->fail(<<EOM);
@@ -120,6 +164,16 @@ EOM
                                my $d = 'maildir:'.$lei->rel2abs($_);
                                push(@no, $_) unless $all{$d};
                                $_ = $d;
+                       } elsif (m!\Aimaps?://!i) {
+                               my $orig = $_;
+                               if (my $canon = match_imap_url(\@all, $orig)) {
+                                       $lei->qerr(<<EOM);
+# using `$canon' instead of `$orig'
+EOM
+                                       $_ = $canon;
+                               } else {
+                                       push @no, $orig;
+                               }
                        } else {
                                push @no, $_;
                        }
@@ -137,11 +191,6 @@ EOF
        if (my @ro = grep(!/\A(?:maildir|imaps?):/, @folders)) {
                return $lei->fail("cannot export to read-only folders: @ro");
        }
-       if (my $net = $lei->{net}) {
-               require PublicInbox::NetWriter;
-               bless $net, 'PublicInbox::NetWriter';
-       }
-       undef $lms;
        my $m = $opt->{mode} // 'merge';
        if ($m eq 'merge') { # default
                $self->{-merge_kw} = 1;
@@ -151,6 +200,13 @@ EOF
 --mode=$m not supported (`set' or `merge')
 EOM
        }
+       if (my $net = $lei->{net}) {
+               require PublicInbox::NetWriter;
+               $self->{nwr} = bless $net, 'PublicInbox::NetWriter';
+               $self->{imap_mod_kw} = $net->can($self->{-merge_kw} ?
+                                       'imap_add_kw' : 'imap_set_kw');
+       }
+       undef $lms;
        my $ops = {};
        $lei->{auth}->op_merge($ops, $self) if $lei->{auth};
        $self->{-wq_nr_workers} = $j // 1; # locked