+ if (my $mm = $self->mm) {
+ # favor the Message-ID we used for the NNTP article number:
+ defined(my $num = $mm->num_for($mid)) or return;
+ $smsg = $over->get_art($num);
+ } else {
+ my ($id, $prev);
+ $smsg = $over->next_by_mid($mid, \$id, \$prev);
+ }
+ $smsg ? PublicInbox::Smsg::psgi_cull($smsg) : undef;
+}
+
+sub msg_by_mid ($$) {
+ my ($self, $mid) = @_;
+ my $smsg = smsg_by_mid($self, $mid);
+ $smsg ? msg_by_smsg($self, $smsg) : msg_by_path($self, mid2path($mid));
+}
+
+sub recent {
+ my ($self, $opts, $after, $before) = @_;
+ $self->over->recent($opts, $after, $before);
+}
+
+sub modified {
+ my ($self) = @_;
+ if (my $over = $self->over) {
+ my $msgs = $over->recent({limit => 1});
+ if (my $smsg = $msgs->[0]) {
+ return $smsg->{ts};
+ }
+ return time;
+ }
+ git($self)->modified; # v1
+}
+
+# returns prefix => pathname mapping
+# (pathname is NOT public, but prefix is used for Xapian queries)
+sub altid_map ($) {
+ my ($self) = @_;
+ $self->{-altid_map} //= eval {
+ require PublicInbox::AltId;
+ my $altid = $self->{altid} or return {};
+ my %h = map {;
+ my $x = PublicInbox::AltId->new($self, $_);
+ "$x->{prefix}" => $x->{filename}
+ } @$altid;
+ \%h;
+ } // {};
+}
+
+# $obj must respond to ->on_inbox_unlock, which takes Inbox ($self) as an arg
+sub subscribe_unlock {
+ my ($self, $ident, $obj) = @_;
+ $self->{unlock_subs}->{$ident} = $obj;
+}
+
+sub unsubscribe_unlock {
+ my ($self, $ident) = @_;
+ delete $self->{unlock_subs}->{$ident};