]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/IMAP.pm
ds: support greeting protocols
[public-inbox.git] / lib / PublicInbox / IMAP.pm
index bc34f4feea1e8ae7b6fe1c1bc5956f1c0d5b3d4f..89a278c14e90683395eb16756341d669fb86a84e 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 #
 # Each instance of this represents an IMAP client connected to
@@ -36,7 +36,6 @@ use parent qw(PublicInbox::DS);
 use PublicInbox::Eml;
 use PublicInbox::EmlContentFoo qw(parse_content_disposition);
 use PublicInbox::DS qw(now);
-use PublicInbox::Syscall qw(EPOLLIN EPOLLONESHOT);
 use PublicInbox::GitAsyncCat;
 use Text::ParseWords qw(parse_line);
 use Errno qw(EAGAIN);
@@ -99,33 +98,15 @@ undef %FETCH_NEED;
 my $valid_range = '[0-9]+|[0-9]+:[0-9]+|[0-9]+:\*';
 $valid_range = qr/\A(?:$valid_range)(?:,(?:$valid_range))*\z/;
 
-# RFC 3501 5.4. Autologout Timer needs to be >= 30min
-$PublicInbox::DS::EXPTIME = 60 * 30;
-
-sub greet ($) {
+sub do_greet {
        my ($self) = @_;
        my $capa = capa($self);
        $self->write(\"* OK [$capa] public-inbox-imapd ready\r\n");
 }
 
-sub new ($$$) {
-       my ($class, $sock, $imapd) = @_;
-       my $self = bless { imapd => $imapd }, 'PublicInbox::IMAP_preauth';
-       my $ev = EPOLLIN;
-       my $wbuf;
-       if ($sock->can('accept_SSL') && !$sock->accept_SSL) {
-               return CORE::close($sock) if $! != EAGAIN;
-               $ev = PublicInbox::TLS::epollbit() or return CORE::close($sock);
-               $wbuf = [ \&PublicInbox::DS::accept_tls_step, \&greet ];
-       }
-       $self->SUPER::new($sock, $ev | EPOLLONESHOT);
-       if ($wbuf) {
-               $self->{wbuf} = $wbuf;
-       } else {
-               greet($self);
-       }
-       $self->update_idle_time;
-       $self;
+sub new {
+       my (undef, $sock, $imapd) = @_;
+       (bless { imapd => $imapd }, 'PublicInbox::IMAP_preauth')->greet($sock)
 }
 
 sub logged_in { 1 }
@@ -323,7 +304,6 @@ sub idle_tick_all {
        $IDLERS = undef;
        for my $i (values %$old) {
                next if ($i->{wbuf} || !exists($i->{-idle_tag}));
-               $i->update_idle_time or next;
                $IDLERS->{fileno($i->{sock})} = $i;
                $i->write(\"* OK Still here\r\n");
        }
@@ -398,14 +378,14 @@ sub inbox_lookup ($$;$) {
                                die "BUG: unexpected dummy mailbox: $mailbox\n";
                $uid_base = $1 * UID_SLICE;
 
-               # ->num_highwater caches for writers, so use ->meta_accessor
-               $uidmax = $ibx->mm->meta_accessor('num_highwater') // 0;
+               $uidmax = $ibx->mm->num_highwater // 0;
                if ($examine) {
                        $self->{uid_base} = $uid_base;
                        $self->{ibx} = $ibx;
                        $self->{uo2m} = uo2m_ary_new($self, \$exists);
                } else {
-                       $exists = $over->imap_exists;
+                       my $uid_end = $uid_base + UID_SLICE;
+                       $exists = $over->imap_exists($uid_base, $uid_end);
                }
                ensure_slices_exist($self->{imapd}, $ibx, $over->max);
        } else {
@@ -877,12 +857,12 @@ sub eml_index_offs_i { # PublicInbox::Eml::each_part callback
 # prepares an index for BODY[$SECTION_IDX] fetches
 sub eml_body_idx ($$) {
        my ($eml, $section_idx) = @_;
-       my $idx = $eml->{imap_all_parts} //= do {
+       my $idx = $eml->{imap_all_parts} // do {
                my $all = {};
                $eml->each_part(\&eml_index_offs_i, $all, 0, 1);
                # top-level of multipart, BODY[0] not allowed (nz-number)
                delete $all->{0};
-               $all;
+               $eml->{imap_all_parts} = $all;
        };
        $idx->{$section_idx};
 }
@@ -1159,15 +1139,6 @@ sub cmd_search ($$$;) {
        search_common($self, $tag, $query, 1);
 }
 
-sub args_ok ($$) { # duplicated from PublicInbox::NNTP
-       my ($cb, $argc) = @_;
-       my $tot = prototype $cb;
-       my ($nreq, undef) = split(';', $tot);
-       $nreq = ($nreq =~ tr/$//) - 1;
-       $tot = ($tot =~ tr/$//) - 1;
-       ($argc <= $tot && $argc >= $nreq);
-}
-
 # returns 1 if we can continue, 0 if not due to buffered writes or disconnect
 sub process_line ($$) {
        my ($self, $l) = @_;
@@ -1226,8 +1197,6 @@ sub long_step {
                out($self, " deferred[$fd] aborted - %0.6f", $elapsed);
                $self->close;
        } elsif ($more) { # $self->{wbuf}:
-               $self->update_idle_time;
-
                # control passed to ibx_async_cat if $more == \undef
                requeue_once($self) if !ref($more);
        } else { # all done!
@@ -1269,7 +1238,6 @@ sub event_step {
 
        return unless $self->flush_write && $self->{sock} && !$self->{long_cb};
 
-       $self->update_idle_time;
        # only read more requests if we've drained the write buffer,
        # otherwise we can be buffering infinitely w/o backpressure
 
@@ -1295,7 +1263,6 @@ sub event_step {
 
        return $self->close if $r < 0;
        $self->rbuf_idle($rbuf);
-       $self->update_idle_time;
 
        # maybe there's more pipelined data, or we'll have
        # to register it for socket-readiness notifications
@@ -1334,14 +1301,14 @@ sub cmd_starttls ($$) {
        undef;
 }
 
-# for graceful shutdown in PublicInbox::Daemon:
-sub busy {
-       my ($self, $now) = @_;
+sub busy { # for graceful shutdown in PublicInbox::Daemon:
+       my ($self) = @_;
        if (defined($self->{-idle_tag})) {
                $self->write(\"* BYE server shutting down\r\n");
                return; # not busy anymore
        }
-       ($self->{rbuf} || $self->{wbuf} || $self->not_idle_long($now));
+       defined($self->{rbuf}) || defined($self->{wbuf}) ||
+               !$self->write(\"* BYE server shutting down\r\n");
 }
 
 sub close {