X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FNNTP.pm;h=e41e3f64d71e1cab5e8322e3c0bbc1c8ac514b5b;hb=c4e57273ce3a7d305ceb21225dae32ece935740f;hp=f4208f878d9cd7e8a091609b25f22badfd001f65;hpb=4685b1d88ffe1f18334bfdd12977ece1fe9d11ce;p=public-inbox.git diff --git a/lib/PublicInbox/NNTP.pm b/lib/PublicInbox/NNTP.pm index f4208f87..e41e3f64 100644 --- a/lib/PublicInbox/NNTP.pm +++ b/lib/PublicInbox/NNTP.pm @@ -7,11 +7,7 @@ use strict; use warnings; use base qw(PublicInbox::DS); use fields qw(nntpd article ng); -use PublicInbox::Search; -use PublicInbox::Msgmap; use PublicInbox::MID qw(mid_escape); -use PublicInbox::Git; -require PublicInbox::EvCleanup; use Email::Simple; use POSIX qw(strftime); use PublicInbox::DS qw(now); @@ -29,8 +25,9 @@ use constant { use PublicInbox::Syscall qw(EPOLLIN EPOLLONESHOT); use Errno qw(EAGAIN); -my @OVERVIEW = qw(Subject From Date Message-ID References Xref); -my $OVERVIEW_FMT = join(":\r\n", @OVERVIEW, qw(Bytes Lines)) . ":\r\n"; +my @OVERVIEW = qw(Subject From Date Message-ID References); +my $OVERVIEW_FMT = join(":\r\n", @OVERVIEW, qw(Bytes Lines), '') . + "Xref:full\r\n"; my $LIST_HEADERS = join("\r\n", @OVERVIEW, qw(:bytes :lines Xref To Cc)) . "\r\n"; my $CAPABILITIES = <<""; @@ -43,37 +40,6 @@ HDR\r OVER\r my $have_deflate; -my $EXPMAP; # fd -> [ idle_time, $self ] -my $expt; -our $EXPTIME = 180; # 3 minutes - -sub update_idle_time ($) { - my ($self) = @_; - my $sock = $self->{sock} or return; - $EXPMAP->{fileno($sock)} = [ now(), $self ]; -} - -sub expire_old () { - my $now = now(); - my $exp = $EXPTIME; - my $old = $now - $exp; - my $nr = 0; - my %new; - while (my ($fd, $v) = each %$EXPMAP) { - my ($idle_time, $nntp) = @$v; - if ($idle_time < $old) { - if (!$nntp->shutdn) { - ++$nr; - $new{$fd} = $v; - } - } else { - ++$nr; - $new{$fd} = $v; - } - } - $EXPMAP = \%new; - $expt = PublicInbox::EvCleanup::later(*expire_old) if $nr; -} sub greet ($) { $_[0]->write($_[0]->{nntpd}->{greet}) }; @@ -94,8 +60,7 @@ sub new ($$$) { } else { greet($self); } - update_idle_time($self); - $expt ||= PublicInbox::EvCleanup::later(*expire_old); + $self->update_idle_time; $self; } @@ -113,10 +78,7 @@ sub process_line ($$) { my ($self, $l) = @_; my ($req, @args) = split(/[ \t]/, $l); return 1 unless defined($req); # skip blank line - $req = eval { - no strict 'refs'; - *{'cmd_'.lc($req)}{CODE}; - }; + $req = $self->can('cmd_'.lc($req)); return res($self, '500 command not recognized') unless $req; return res($self, r501) unless args_ok($req, scalar @args); @@ -205,11 +167,7 @@ sub cmd_list ($;$$) { my $arg = shift @args; $arg =~ tr/A-Z./a-z_/; $arg = "list_$arg"; - - $arg = eval { - no strict 'refs'; - *{$arg}{CODE}; - }; + $arg = $self->can($arg); return r501 unless $arg && args_ok($arg, scalar @args); more($self, '215 information follows'); $arg->($self, @args); @@ -222,22 +180,34 @@ sub cmd_list ($;$$) { '.' } -sub cmd_listgroup ($;$) { - my ($self, $group) = @_; +sub cmd_listgroup ($;$$) { + my ($self, $group, $range) = @_; if (defined $group) { my $res = cmd_group($self, $group); return $res if ($res !~ /\A211 /); more($self, $res); } - - $self->{ng} or return '412 no newsgroup selected'; - my $n = 0; - long_response($self, sub { - my $ary = $self->{ng}->mm->ids_after(\$n); - scalar @$ary or return; - more($self, join("\r\n", @$ary)); - 1; - }); + my $ng = $self->{ng} or return '412 no newsgroup selected'; + my $mm = $ng->mm; + if (defined $range) { + my $r = get_range($self, $range); + return $r unless ref $r; + my ($beg, $end) = @$r; + long_response($self, sub { + $r = $mm->msg_range(\$beg, $end, 'num'); + scalar(@$r) or return; + more($self, join("\r\n", map { $_->[0] } @$r)); + 1; + }); + } else { # grab every article number + my $n = 0; + long_response($self, sub { + my $ary = $mm->ids_after(\$n); + scalar(@$ary) or return; + more($self, join("\r\n", @$ary)); + 1; + }); + } } sub parse_time ($$;$) { @@ -640,7 +610,7 @@ sub long_response ($$) { out($self, " deferred[$fd] aborted - %0.6f", $diff); $self->close; } elsif ($more) { # $self->{wbuf}: - update_idle_time($self); + $self->update_idle_time; # COMPRESS users all share the same DEFLATE context. # Flush it here to ensure clients don't see @@ -973,7 +943,7 @@ sub event_step { return unless $self->flush_write && $self->{sock}; - update_idle_time($self); + $self->update_idle_time; # only read more requests if we've drained the write buffer, # otherwise we can be buffering infinitely w/o backpressure @@ -984,7 +954,7 @@ sub event_step { my $off = bytes::length($$rbuf); $r = $self->do_read($rbuf, LINE_MAX, $off) or return; } - while ($r > 0 && $$rbuf =~ s/\A[ \t\r\n]*([^\r\n]*)\r?\n//) { + while ($r > 0 && $$rbuf =~ s/\A[ \t]*([^\n]*?)\r?\n//) { my $line = $1; return $self->close if $line =~ /[[:cntrl:]]/s; my $t0 = now(); @@ -998,25 +968,17 @@ sub event_step { my $len = bytes::length($$rbuf); return $self->close if ($len >= LINE_MAX); $self->rbuf_idle($rbuf); - update_idle_time($self); + $self->update_idle_time; # maybe there's more pipelined data, or we'll have # to register it for socket-readiness notifications $self->requeue unless $self->{wbuf}; } -sub not_idle_long ($$) { - my ($self, $now) = @_; - my $sock = $self->{sock} or return; - my $ary = $EXPMAP->{fileno($sock)} or return; - my $exp_at = $ary->[0] + $EXPTIME; - $exp_at > $now; -} - # for graceful shutdown in PublicInbox::Daemon: sub busy { my ($self, $now) = @_; - ($self->{rbuf} || $self->{wbuf} || not_idle_long($self, $now)); + ($self->{rbuf} || $self->{wbuf} || $self->not_idle_long($now)); } # this is an import to prevent "perl -c" from complaining about fields