our
@ISA
=
qw(Mail::SpamAssassin::PersistentAddrList)
;
sub
new {
my
$class
=
shift
;
$class
=
ref
(
$class
) ||
$class
;
my
$self
=
$class
->SUPER::new(
@_
);
$self
->{class} =
$class
;
bless
(
$self
,
$class
);
$self
;
}
sub
new_checker {
my
(
$factory
,
$main
) =
@_
;
my
$class
=
$factory
->{class};
my
$self
= {
'main'
=>
$main
,
'accum'
=> { },
'is_locked'
=> 0,
'locked_file'
=>
''
};
my
@order
=
split
(/\s+/,
$main
->{conf}->{auto_welcomelist_db_modules});
untaint_var(\
@order
);
my
$dbm_module
= Mail::SpamAssassin::Util::first_available_module (
@order
);
if
(!
$dbm_module
) {
die
"auto-welcomelist: cannot find a usable DB package from auto_welcomelist_db_modules: "
.
$main
->{conf}->{auto_welcomelist_db_modules}.
"\n"
;
}
my
$umask
=
umask
~ (
oct
(
$main
->{conf}->{auto_welcomelist_file_mode}));
if
(
defined
(
$main
->{conf}->{auto_welcomelist_path})) {
my
$path
=
$main
->sed_path(
$main
->{conf}->{auto_welcomelist_path});
my
(
$mod1
,
$mod2
);
if
(
$main
->{locker}->safe_lock
(
$path
, 30,
$main
->{conf}->{auto_welcomelist_file_mode}))
{
$self
->{locked_file} =
$path
;
$self
->{is_locked} = 1;
(
$mod1
,
$mod2
) = (
'R/W'
, O_RDWR | O_CREAT);
}
else
{
$self
->{is_locked} = 0;
(
$mod1
,
$mod2
) = (
'R/O'
, O_RDONLY);
}
dbg(
"auto-welcomelist: tie-ing to DB file of type $dbm_module $mod1 in $path"
);
(
$self
->{is_locked} &&
$dbm_module
eq
'DB_File'
) and
Mail::SpamAssassin::Util::avoid_db_file_locking_bug(
$path
);
if
(!
tie
%{
$self
->{accum} },
$dbm_module
,
$path
,
$mod2
,
oct
(
$main
->{conf}->{auto_welcomelist_file_mode}) & 0666)
{
my
$err
= $!;
if
(
$self
->{is_locked}) {
$self
->{main}->{locker}->safe_unlock(
$self
->{locked_file});
$self
->{is_locked} = 0;
}
die
"auto-welcomelist: cannot open auto_welcomelist_path $path: $err\n"
;
}
}
umask
$umask
;
bless
(
$self
,
$class
);
return
$self
;
}
sub
finish {
my
$self
=
shift
;
dbg(
"auto-welcomelist: DB addr list: untie-ing and unlocking"
);
untie
%{
$self
->{accum}};
if
(
$self
->{is_locked}) {
dbg(
"auto-welcomelist: DB addr list: file locked, breaking lock"
);
$self
->{main}->{locker}->safe_unlock (
$self
->{locked_file});
$self
->{is_locked} = 0;
}
}
sub
get_addr_entry {
my
(
$self
,
$addr
,
$signedby
) =
@_
;
my
$entry
= {
addr
=>
$addr
,
};
$entry
->{msgcount} =
$self
->{accum}->{
$addr
} || 0;
$entry
->{totscore} =
$self
->{accum}->{
$addr
.
'|totscore'
} || 0;
dbg(
"auto-welcomelist: db-based $addr scores "
.
$entry
->{msgcount}.
'/'
.
$entry
->{totscore});
return
$entry
;
}
sub
add_score {
my
(
$self
,
$entry
,
$score
) =
@_
;
$entry
->{msgcount} ||= 0;
$entry
->{addr} ||=
''
;
$entry
->{msgcount}++;
$entry
->{totscore} +=
$score
;
dbg(
"auto-welcomelist: add_score: new count: "
.
$entry
->{msgcount}.
", new totscore: "
.
$entry
->{totscore});
$self
->{accum}->{
$entry
->{addr}} =
$entry
->{msgcount};
$self
->{accum}->{
$entry
->{addr}.
'|totscore'
} =
$entry
->{totscore};
return
$entry
;
}
sub
remove_entry {
my
(
$self
,
$entry
) =
@_
;
my
$addr
=
$entry
->{addr};
delete
$self
->{accum}->{
$addr
};
delete
$self
->{accum}->{
$addr
.
'|totscore'
};
if
(
$addr
=~ /^(.*)\|ip=none$/) {
my
$mailaddr
= $1;
while
(
my
(
$key
,
$value
) =
each
%{
$self
->{accum}}) {
if
(
$key
=~ /^\Q${mailaddr}\E\|/) {
delete
$self
->{accum}->{
$key
};
}
}
}
}
1;