# Copyright (C) all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
-# represents an POP3D (currently a singleton)
+# represents an POP3D
package PublicInbox::POP3D;
use v5.12;
use parent qw(PublicInbox::Lock);
use File::Temp 0.19 (); # 0.19 for ->newdir
use Fcntl qw(F_SETLK F_UNLCK F_WRLCK SEEK_SET);
my @FLOCK;
-if ($^O eq 'linux' || $^O eq 'freebsd') {
+if ($^O eq 'linux' || $^O =~ /bsd/) {
require Config;
my $off_t;
my $sz = $Config::Config{lseeksize};
if ($^O eq 'linux') {
@FLOCK = ("ss\@8$off_t$off_t\@32",
qw(l_type l_whence l_start l_len));
- } elsif ($^O eq 'freebsd') {
+ } elsif ($^O =~ /bsd/) {
@FLOCK = ("${off_t}${off_t}lss\@256",
qw(l_start l_len l_pid l_type l_whence));
}
die "File::FcntlLock required for POP3 on $^O: $@\n";
sub new {
- my ($cls, $pi_cfg) = @_;
- $pi_cfg //= PublicInbox::Config->new;
- my $d = $pi_cfg->{'publicinbox.pop3state'} //
- die "publicinbox.pop3state undefined\n";
- -d $d or do {
- require File::Path;
- File::Path::make_path($d, { mode => 0700 });
- PublicInbox::Syscall::nodatacow_dir($d);
- };
+ my ($cls) = @_;
bless {
err => \*STDERR,
out => \*STDOUT,
- pi_cfg => $pi_cfg,
- lock_path => "$d/db.lock", # PublicInbox::Lock to protect SQLite
+ # pi_cfg => PublicInbox::Config
+ # lock_path => ...
# interprocess lock is the $pop3state/txn.locks file
# txn_locks => {}, # intraworker locks
- # accept_tls => { SSL_server => 1, ..., SSL_reuse_ctx => ... }
+ # ssl_ctx_opt => { SSL_cert_file => ..., SSL_key_file => ... }
}, $cls;
}
my ($self, $sig) = @_;
# TODO share pi_cfg with nntpd/imapd inside -netd
my $new = PublicInbox::Config->new;
- my $old = $self->{pi_cfg};
- my $s = 'publicinbox.pop3state';
- $new->{$s} //= $old->{$s};
- if ($new->{$s} ne $old->{$s}) {
- warn <<EOM;
+ my $d = $new->{'publicinbox.pop3state'} //
+ die "publicinbox.pop3state undefined ($new->{-f})\n";
+ -d $d or do {
+ require File::Path;
+ File::Path::make_path($d, { mode => 0700 });
+ PublicInbox::Syscall::nodatacow_dir($d);
+ };
+ $self->{lock_path} //= "$d/db.lock";
+ if (my $old = $self->{pi_cfg}) {
+ my $s = 'publicinbox.pop3state';
+ $new->{$s} //= $old->{$s};
+ return warn <<EOM if $new->{$s} ne $old->{$s};
$s changed: `$old->{$s}' => `$new->{$s}', config reload ignored
EOM
- } else {
- $self->{pi_cfg} = $new;
}
+ $self->{pi_cfg} = $new;
}
# persistent tables
sub unlock_mailbox {
my ($self, $pop3) = @_;
my $txn_id = delete($pop3->{txn_id}) // return;
+ if (!$pop3->{did_quit}) { # deal with QUIT-less disconnects
+ my $lk = $self->lock_for_scope;
+ $self->{-state_dbh}->begin_work;
+ $pop3->__cleanup_state($txn_id);
+ $self->{-state_dbh}->commit;
+ }
delete $self->{txn_locks}->{$txn_id}; # same worker
# other workers