+ my $ng = $self->{ng} or return '412 no newsgroup selected';
+ (defined $range && $range =~ /[<>]/) and
+ return '420 No article(s) selected'; # no message IDs
+
+ $range = $self->{article} unless defined $range;
+ my $r = get_range($self, $range);
+ return $r unless ref $r;
+ my ($beg, $end) = @$r;
+ my $mm = $ng->mm;
+ my $srch = $ng->search;
+ more($self, '224 Overview information follows');
+
+ long_response($self, sub {
+ my $h = search_header_for($srch, $beg, 'references');
+ more($self, "$beg $h") if defined($h);
+ $beg++ < $end;
+ });
+}
+
+sub over_line ($$$$) {
+ my ($self, $ng, $num, $smsg) = @_;
+ # n.b. field access and procedural calls can be
+ # 10%-15% faster than OO method calls:
+ my $s = join("\t", $num,
+ $smsg->{subject},
+ $smsg->{from},
+ PublicInbox::SearchMsg::date($smsg),
+ "<$smsg->{mid}>",
+ $smsg->{references},
+ $smsg->{bytes},
+ $smsg->{lines},
+ "Xref: " . xref($self, $ng, $num, $smsg->{mid}));
+ utf8::encode($s);
+ $s
+}
+
+sub cmd_over ($;$) {
+ my ($self, $range) = @_;
+ if ($range && $range =~ /\A<(.+)>\z/) {
+ my ($ng, $n) = mid_lookup($self, $1);
+ defined $n or return r430;
+ my $smsg = $ng->search->{over_ro}->get_art($n) or return r430;
+ more($self, '224 Overview information follows (multi-line)');
+
+ # Only set article number column if it's the current group
+ my $self_ng = $self->{ng};
+ $n = 0 if (!$self_ng || $self_ng ne $ng);
+ more($self, over_line($self, $ng, $n, $smsg));
+ '.';
+ } else {
+ cmd_xover($self, $range);
+ }
+}
+
+sub cmd_xover ($;$) {
+ my ($self, $range) = @_;
+ $range = $self->{article} unless defined $range;