File Coverage

blib/lib/Mail/SpamAssassin/BayesStore.pm
Criterion Covered Total %
statement 39 187 20.8
branch 4 56 7.1
condition 3 32 9.3
subroutine 8 43 18.6
pod 38 39 97.4
total 92 357 25.7


line stmt bran cond sub pod time code
1             # <@LICENSE>
2             # Licensed to the Apache Software Foundation (ASF) under one or more
3             # contributor license agreements. See the NOTICE file distributed with
4             # this work for additional information regarding copyright ownership.
5             # The ASF licenses this file to you under the Apache License, Version 2.0
6             # (the "License"); you may not use this file except in compliance with
7             # the License. You may obtain a copy of the License at:
8             #
9             # http://www.apache.org/licenses/LICENSE-2.0
10             #
11             # Unless required by applicable law or agreed to in writing, software
12             # distributed under the License is distributed on an "AS IS" BASIS,
13             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14             # See the License for the specific language governing permissions and
15             # limitations under the License.
16             # </@LICENSE>
17              
18             =head1 NAME
19              
20             Mail::SpamAssassin::BayesStore - Storage Module for default Bayes classifier
21              
22             =head1 DESCRIPTION
23              
24             This is the public API for the Bayesian store methods. Any implementation of
25             the storage module for the default Bayes classifier must implement these methods.
26              
27             =cut
28              
29             package Mail::SpamAssassin::BayesStore;
30              
31 21     21   133 use strict;
  21         43  
  21         618  
32 21     21   107 use warnings;
  21         42  
  21         668  
33             # use bytes;
34 21     21   155 use re 'taint';
  21         48  
  21         659  
35 21     21   122 use Mail::SpamAssassin::Logger;
  21         50  
  21         49516  
36              
37             # TODO: if we ever get tuits, it'd be good to make these POD
38             # method docs more perlish... hardly a biggie.
39              
40             =head1 METHODS
41              
42             =over 4
43              
44             =item new
45              
46             public class (Mail::SpamAssassin::BayesStore) new (Mail::SpamAssassin::Plugin::Bayes $bayes)
47              
48             Description:
49             This method creates a new instance of the Mail::SpamAssassin::BayesStore
50             object. You must pass in an instance of the Mail::SpamAssassin::Plugin::Bayes
51             object, which is stashed for use throughout the module.
52              
53             =cut
54              
55             sub new {
56 63     63 1 225 my ($class, $bayes) = @_;
57              
58 63   33     410 $class = ref($class) || $class;
59              
60 63         428 my $self = {
61             'bayes' => $bayes,
62             'supported_db_version' => 0,
63             'db_version' => undef,
64             };
65              
66 63         196 bless ($self, $class);
67              
68 63         201 $self;
69             }
70              
71             =item DB_VERSION
72              
73             public instance (Integer) DB_VERSION ()
74              
75             Description:
76             This method returns the currently supported database version for the
77             implementation.
78              
79             =cut
80              
81             sub DB_VERSION {
82 40     40 1 93 my ($self) = @_;
83 40         246 return $self->{supported_db_version};
84             }
85              
86             =item read_db_configs
87              
88             public instance () read_db_configs ()
89              
90             Description:
91             This method reads any needed config variables from the configuration object
92             and then calls the Mail::SpamAssassin::Plugin::Bayes read_db_configs method.
93              
94             =cut
95              
96             sub read_db_configs {
97 42     42 1 76 my ($self) = @_;
98              
99             # TODO: at some stage, this may be useful to read config items which
100             # control database bloat, like
101             #
102             # - use of hapaxes
103             # - use of case-sensitivity
104             # - more midrange-hapax-avoidance tactics when parsing headers (future)
105             #
106             # for now, we just set these settings statically.
107 42         80 my $conf = $self->{bayes}->{main}->{conf};
108              
109             # Minimum desired database size? Expiry will not shrink the
110             # database below this number of entries. 100k entries is roughly
111             # equivalent to a 5Mb database file.
112 42         111 $self->{expiry_max_db_size} = $conf->{bayes_expiry_max_db_size};
113 42         100 $self->{expiry_pct} = $conf->{bayes_expiry_pct};
114 42         79 $self->{expiry_period} = $conf->{bayes_expiry_period};
115 42         80 $self->{expiry_max_exponent} = $conf->{bayes_expiry_max_exponent};
116              
117 42         161 $self->{bayes}->read_db_configs();
118             }
119              
120             =item prefork_init
121              
122             public instance (Boolean) prefork_init ()
123              
124             Description:
125             This optional method is called in the parent process shortly before
126             forking off child processes.
127              
128             =cut
129              
130             # sub prefork_init {
131             # my ($self) = @_;
132             # }
133              
134             =item spamd_child_init
135              
136             public instance (Boolean) spamd_child_init ()
137              
138             Description:
139             This optional method is called in a child process shortly after being spawned.
140              
141             =cut
142              
143             # sub spamd_child_init {
144             # my ($self) = @_;
145             # }
146              
147             =item tie_db_readonly
148              
149             public instance (Boolean) tie_db_readonly ()
150              
151             Description:
152             This method opens up the database in readonly mode.
153              
154             =cut
155              
156             sub tie_db_readonly {
157 0     0 1 0 my ($self) = @_;
158 0         0 die "bayes: tie_db_readonly: not implemented\n";
159             }
160              
161             =item tie_db_writable
162              
163             public instance (Boolean) tie_db_writable ()
164              
165             Description:
166             This method opens up the database in writable mode.
167              
168             Any callers of this methods should ensure that they call untie_db()
169             afterwards.
170              
171             =cut
172              
173             sub tie_db_writable {
174 0     0 1 0 my ($self) = @_;
175 0         0 die "bayes: tie_db_writable: not implemented\n";
176             }
177              
178             =item untie_db
179              
180             public instance () untie_db ()
181              
182             Description:
183             This method unties the database.
184              
185             =cut
186              
187             sub untie_db {
188 0     0 1 0 my $self = shift;
189 0         0 die "bayes: untie_db: not implemented\n";
190             }
191              
192             =item calculate_expire_delta
193              
194             public instance (%) calculate_expire_delta (Integer $newest_atime,
195             Integer $start,
196             Integer $max_expire_mult)
197              
198             Description:
199             This method performs a calculation on the data to determine the optimum
200             atime for token expiration.
201              
202             =cut
203              
204             sub calculate_expire_delta {
205 0     0 1 0 my ($self, $newest_atime, $start, $max_expire_mult) = @_;
206 0         0 die "bayes: calculate_expire_delta: not implemented\n";
207             }
208              
209             =item token_expiration
210              
211             public instance (Integer, Integer,
212             Integer, Integer) token_expiration(\% $opts,
213             Integer $newest_atime,
214             Integer $newdelta)
215              
216             Description:
217             This method performs the database specific expiration of tokens based on
218             the passed in C<$newest_atime> and C<$newdelta>.
219              
220             =cut
221              
222             sub token_expiration {
223 0     0 1 0 my ($self, $opts, $newest_atime, $newdelta) = @_;
224 0         0 die "bayes: token_expiration: not implemented\n";
225             }
226              
227             =item expire_old_tokens
228              
229             public instance (Boolean) expire_old_tokens (\% hashref)
230              
231             Description:
232             This method expires old tokens from the database.
233              
234             =cut
235              
236             sub expire_old_tokens {
237 0     0 1 0 my ($self, $opts) = @_;
238 0         0 my $ret;
239              
240             my $eval_stat;
241             eval {
242 0         0 local $SIG{'__DIE__'}; # do not run user die() traps in here
243 0 0       0 if ($self->tie_db_writable()) {
244 0         0 $ret = $self->expire_old_tokens_trapped ($opts);
245             }
246 0         0 1;
247 0 0       0 } or do {
248 0 0       0 $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
  0         0  
249             };
250              
251 0 0       0 if (!$self->{bayes}->{main}->{learn_caller_will_untie}) {
252 0         0 $self->untie_db();
253             }
254              
255 0 0       0 if (defined $eval_stat) { # if we died, untie the dbs.
256 0         0 warn "bayes: expire_old_tokens: $eval_stat\n";
257 0         0 return 0;
258             }
259 0         0 $ret;
260             }
261              
262             =item expire_old_tokens_trapped
263              
264             public instance (Boolean) expire_old_tokens_trapped (\% $opts)
265              
266             Description:
267             This methods does the actual token expiration.
268              
269             XXX More docs here about the methodology and what not
270              
271             =cut
272              
273             sub expire_old_tokens_trapped {
274 0     0 1 0 my ($self, $opts) = @_;
275              
276             # Flag that we're doing work
277 0         0 $self->set_running_expire_tok();
278              
279             # We don't need to do an expire, so why were we called? Oh well.
280 0 0       0 if (!$self->expiry_due()) {
281 0         0 $self->remove_running_expire_tok();
282 0         0 return 0;
283             }
284              
285 0         0 my $started = time();
286 0         0 my @vars = $self->get_storage_variables();
287              
288 0 0       0 if ( $vars[10] > time ) {
289 0         0 dbg("bayes: expiry found newest atime in the future, resetting to current time");
290 0         0 $vars[10] = time;
291             }
292              
293             # How many tokens do we want to keep?
294 0         0 my $goal_reduction = int($self->{expiry_max_db_size} * $self->{expiry_pct});
295 0         0 dbg("bayes: expiry check keep size, ".$self->{expiry_pct}." * max: $goal_reduction");
296             # Make sure we keep at least 100000 tokens in the DB
297 0 0       0 if ( $goal_reduction < 100000 ) {
298 0         0 $goal_reduction = 100000;
299 0         0 dbg("bayes: expiry keep size too small, resetting to 100,000 tokens");
300             }
301             # Now turn goal_reduction into how many to expire.
302 0         0 $goal_reduction = $vars[3] - $goal_reduction;
303 0         0 dbg("bayes: token count: ".$vars[3].", final goal reduction size: $goal_reduction");
304              
305 0 0       0 if ( $goal_reduction < 1000 ) { # too few tokens to expire, abort.
306 0         0 dbg("bayes: reduction goal of $goal_reduction is under 1,000 tokens, skipping expire");
307 0         0 $self->set_last_expire(time());
308 0         0 $self->remove_running_expire_tok(); # this won't be cleaned up, so do it now.
309 0         0 return 1; # we want to indicate things ran as expected
310             }
311              
312             # Estimate new atime delta based on the last atime delta
313 0         0 my $newdelta = 0;
314 0 0       0 if ( $vars[9] > 0 ) {
315             # newdelta = olddelta * old / goal;
316             # this may seem backwards, but since we're talking delta here,
317             # not actual atime, we want smaller atimes to expire more tokens,
318             # and visa versa.
319             #
320 0         0 $newdelta = int($vars[8] * $vars[9] / $goal_reduction);
321             }
322              
323             # Calculate size difference between last expiration token removal
324             # count and the current goal removal count.
325 0 0 0     0 my $ratio = ($vars[9] == 0 || $vars[9] > $goal_reduction) ? $vars[9]/$goal_reduction : $goal_reduction/$vars[9];
326              
327 0         0 dbg("bayes: first pass? current: ".time().", Last: ".$vars[4].", atime: ".$vars[8].", count: ".$vars[9].", newdelta: $newdelta, ratio: $ratio, period: ".$self->{expiry_period});
328              
329             ## ESTIMATION PHASE
330             #
331             # Do this for the first expire or "odd" looking results cause a first pass to determine atime:
332             #
333             # - last expire was more than 30 days ago
334             # assume mail flow stays roughly the same month to month, recompute if it's > 1 month
335             # - last atime delta was under expiry period
336             # if we're expiring often max_db_size should go up, but let's recompute just to check
337             # - last reduction count was < 1000 tokens
338             # ditto
339             # - new estimated atime delta is under expiry period
340             # ditto
341             # - difference of last reduction to current goal reduction is > 50%
342             # if the two values are out of balance, estimating atime is going to be funky, recompute
343             #
344 0 0 0     0 if ( (time() - $vars[4] > 86400*30) || ($vars[8] < $self->{expiry_period}) || ($vars[9] < 1000)
      0        
      0        
      0        
345             || ($newdelta < $self->{expiry_period}) || ($ratio > 1.5) ) {
346 0         0 dbg("bayes: can't use estimation method for expiry, unexpected result, calculating optimal atime delta (first pass)");
347              
348 0         0 my $start = $self->{expiry_period}; # exponential search starting at ...? 1/2 day, 1, 2, 4, 8, 16, ...
349 0         0 my $max_expire_mult = 2**$self->{expiry_max_exponent}; # $max_expire_mult * $start = max expire time (256 days), power of 2.
350              
351 0         0 dbg("bayes: expiry max exponent: ".$self->{expiry_max_exponent});
352              
353 0         0 my %delta = $self->calculate_expire_delta($vars[10], $start, $max_expire_mult);
354              
355 0 0       0 return 0 unless (%delta);
356              
357             # This will skip the for loop if debugging isn't enabled ...
358 0 0       0 if (would_log('dbg', 'bayes')) {
359 0         0 dbg("bayes: atime\ttoken reduction");
360 0         0 dbg("bayes: ========\t===============");
361 0         0 for(my $i = 1; $i<=$max_expire_mult; $i <<= 1) {
362 0 0       0 dbg("bayes: ".$start*$i."\t".(exists $delta{$i} ? $delta{$i} : 0));
363             }
364             }
365            
366             # Now figure out which max_expire_mult value gives the closest results to goal_reduction, without
367             # going over ... Go from the largest delta backwards so the reduction size increases
368             # (tokens that expire at 4 also expire at 3, 2, and 1, so 1 will always be the largest expiry...)
369             #
370 0         0 for( ; $max_expire_mult > 0; $max_expire_mult>>=1 ) {
371 0 0       0 next unless exists $delta{$max_expire_mult};
372 0 0       0 if ($delta{$max_expire_mult} > $goal_reduction) {
373 0         0 $max_expire_mult<<=1; # the max expire is actually the next power of 2 out
374 0         0 last;
375             }
376             }
377              
378             # if max_expire_mult gets to 0, either we can't expire anything, or 1 is <= $goal_reduction
379 0   0     0 $max_expire_mult ||= 1;
380              
381             # $max_expire_mult is now equal to the value we should use ...
382             # Check to see if the atime value we found is really good.
383             # It's not good if:
384             # - $max_expire_mult would not expire any tokens. This means that the majority of
385             # tokens are old or new, and more activity is required before an expiry can occur.
386             # - reduction count < 1000, not enough tokens to be worth doing an expire.
387             #
388 0 0 0     0 if ( !exists $delta{$max_expire_mult} || $delta{$max_expire_mult} < 1000 ) {
389 0         0 dbg("bayes: couldn't find a good delta atime, need more token difference, skipping expire");
390 0         0 $self->set_last_expire(time());
391 0         0 $self->remove_running_expire_tok(); # this won't be cleaned up, so do it now.
392 0         0 return 1; # we want to indicate things ran as expected
393             }
394              
395 0         0 $newdelta = $start * $max_expire_mult;
396 0         0 dbg("bayes: first pass decided on $newdelta for atime delta");
397             }
398             else { # use the estimation method
399 0         0 dbg("bayes: can do estimation method for expiry, skipping first pass");
400             }
401              
402 0         0 my ($kept, $deleted, $num_hapaxes, $num_lowfreq) = $self->token_expiration($opts, $newdelta, @vars);
403              
404 0         0 my $done = time();
405              
406 0         0 my $msg = "expired old bayes database entries in ".($done - $started)." seconds";
407 0         0 my $msg2 = "$kept entries kept, $deleted deleted";
408              
409 0 0       0 if ($opts->{verbose}) {
410 0         0 my $hapax_pc = ($num_hapaxes * 100) / $kept;
411 0         0 my $lowfreq_pc = ($num_lowfreq * 100) / $kept;
412 0 0       0 print "$msg\n$msg2\n" or die "Error writing: $!";
413 0 0       0 printf "token frequency: 1-occurrence tokens: %3.2f%%\n", $hapax_pc
414             or die "Error writing: $!";
415 0 0       0 printf "token frequency: less than 8 occurrences: %3.2f%%\n", $lowfreq_pc
416             or die "Error writing: $!";
417             }
418             else {
419 0         0 dbg("bayes: $msg: $msg2");
420             }
421              
422 0         0 $self->remove_running_expire_tok();
423 0         0 return 1;
424             }
425              
426             =item sync_due
427              
428             public instance (Boolean) sync_due ()
429              
430             Description:
431             This methods determines if a sync is due.
432              
433             =cut
434              
435             sub sync_due {
436 0     0 1 0 my ($self) = @_;
437 0         0 die "bayes: sync_due: not implemented\n";
438             }
439              
440             =item expiry_due
441              
442             public instance (Boolean) expiry_due ()
443              
444             Description:
445             This methods determines if an expire is due.
446              
447             =cut
448              
449             sub expiry_due {
450 4     4 1 17 my ($self) = @_;
451              
452 4         26 $self->read_db_configs(); # make sure this has happened here
453              
454             # If force expire was called, do the expire no matter what.
455 4 50       22 return 1 if ($self->{bayes}->{main}->{learn_force_expire});
456              
457             # if config says not to auto expire then no need to continue
458 4 50       18 return 0 if ($self->{bayes}->{main}->{conf}->{bayes_auto_expire} == 0);
459              
460             # is the database too small for expiry? (Do *not* use "scalar keys",
461             # as this will iterate through the entire db counting them!)
462 4         22 my @vars = $self->get_storage_variables();
463 4         11 my $ntoks = $vars[3];
464              
465 4         11 my $last_expire = time() - $vars[4];
466 4 50       41 if (!$self->{bayes}->{main}->{ignore_safety_expire_timeout}) {
467             # if we're not ignoring the safety timeout, don't run an expire more
468             # than once every 12 hours.
469 4 50       19 return 0 if ($last_expire < 43200);
470             }
471             else {
472             # if we are ignoring the safety timeout (e.g.: mass-check), still
473             # limit the expiry to only one every 5 minutes.
474 0 0       0 return 0 if ($last_expire < 300);
475             }
476              
477 4         67 dbg("bayes: DB expiry: tokens in DB: $ntoks, Expiry max size: ".$self->{expiry_max_db_size}.", Oldest atime: ".$vars[5].", Newest atime: ".$vars[10].", Last expire: ".$vars[4].", Current time: ".time());
478              
479 4         11 my $conf = $self->{bayes}->{main}->{conf};
480 4 0 33     45 if ($ntoks <= 100000 || # keep at least 100k tokens
      33        
      0        
481             $self->{expiry_max_db_size} > $ntoks || # not enough tokens to cause an expire
482             $vars[10]-$vars[5] < 43200 || # delta between oldest and newest < 12h
483             $self->{db_version} < $self->DB_VERSION # ignore old db formats
484             ) {
485 4         42 return 0;
486             }
487              
488 0           return 1;
489             }
490              
491             =item seen_get
492              
493             public instance (Char) seen_get (String $msgid)
494              
495             Description:
496             This method retrieves the stored value, if any, for C<$msgid>. The return
497             value is the stored string ('s' for spam and 'h' for ham) or undef if
498             C<$msgid> is not found.
499              
500             =cut
501              
502             sub seen_get {
503 0     0 1   my ($self, $msgid) = @_;
504 0           die "bayes: seen_get: not implemented\n";
505             }
506              
507             =item seen_put
508              
509             public instance (Boolean) seen_put (String $msgid, Char $flag)
510              
511             Description:
512             This method records C<$msgid> as the type given by C<$flag>. C<$flag> is
513             one of two values 's' for spam and 'h' for ham.
514              
515             =cut
516              
517             sub seen_put {
518 0     0 1   my ($self, $msgid, $flag) = @_;
519 0           die "bayes: seen_put: not implemented\n";
520             }
521              
522             =item seen_delete
523              
524             public instance (Boolean) seen_delete (String $msgid)
525              
526             Description:
527             This method removes C<$msgid> from storage.
528              
529             =cut
530              
531             sub seen_delete {
532 0     0 1   my ($self, $msgid) = @_;
533 0           die "bayes: seen_delete: not implemented\n";
534             }
535              
536             =item get_storage_variables
537              
538             public instance (@) get_storage_variables ()
539              
540             Description:
541             This method retrieves the various administrative variables used by
542             the Bayes storage implementation.
543              
544             The values returned in the array are in the following order:
545              
546             0: scan count base
547              
548             1: number of spam
549              
550             2: number of ham
551              
552             3: number of tokens in db
553              
554             4: last expire atime
555              
556             5: oldest token in db atime
557              
558             6: db version value
559              
560             7: last journal sync
561              
562             8: last atime delta
563              
564             9: last expire reduction count
565              
566             10: newest token in db atime
567              
568             =cut
569              
570             sub get_storage_variables {
571 0     0 1   my ($self) = @_;
572 0           die "bayes: get_storage_variables: not implemented\n";
573             }
574              
575             =item dump_db_toks
576              
577             public instance () dump_db_toks (String $template, String $regex, @ @vars)
578              
579             Description:
580             This method loops over all tokens, computing the probability for the token
581             and then printing it out according to the passed in template.
582              
583             =cut
584              
585             sub dump_db_toks {
586 0     0 1   my ($self, $template, $regex, @vars) = @_;
587 0           die "bayes: dump_db_toks: not implemented\n";
588             }
589              
590             =item set_last_expire
591              
592             public instance (Boolean) _set_last_expire (Integer $time)
593              
594             Description:
595             This method sets the last expire time.
596              
597             =cut
598              
599             sub set_last_expire {
600 0     0 1   my ($self, $time) = @_;
601 0           die "bayes: set_last_expire: not implemented\n";
602             }
603              
604             =item get_running_expire_tok
605              
606             public instance (Time) get_running_expire_tok ()
607              
608             Description:
609             This method determines if an expire is currently running and returns the time
610             the expire started.
611              
612             =cut
613              
614             sub get_running_expire_tok {
615 0     0 1   my ($self) = @_;
616 0           die "bayes: get_running_expire_tok: not implemented\n";
617             }
618              
619             =item set_running_expire_tok
620              
621             public instance (Time) set_running_expire_tok ()
622              
623             Description:
624             This method sets the running expire time to the current time.
625              
626             =cut
627              
628             sub set_running_expire_tok {
629 0     0 1   my ($self) = @_;
630 0           die "bayes: set_running_expire_tok: not implemented\n";
631             }
632              
633             =item remove_running_expire_tok
634              
635             public instance (Boolean) remove_running_expire_tok ()
636              
637             Description:
638             This method removes a currently set running expire time.
639              
640             =cut
641              
642             sub remove_running_expire_tok {
643 0     0 1   my ($self) = @_;
644 0           die "bayes: remove_running_expire_tok: not implemented\n";
645             }
646              
647             =item tok_get
648              
649             public instance (Integer, Integer, Time) tok_get (String $token)
650              
651             Description:
652             This method retrieves the specified token (C<$token>) from storage and returns
653             it's spam count, ham acount and last access time.
654              
655             =cut
656              
657             sub tok_get {
658 0     0 1   my ($self, $token) = @_;
659 0           die "bayes: tok_get: not implemented\n";
660             }
661              
662             =item tok_get_all
663              
664             public instance (\@) tok_get_all (@ @tokens)
665              
666             Description:
667             This method retrieves the specified tokens (C<@tokens>) from storage and
668             returns an array ref of arrays spam count, ham count and last access time.
669              
670             =cut
671              
672             sub tok_get_all {
673 0     0 1   my ($self, $tokens) = @_;
674 0           die "bayes: tok_get_all: not implemented\n";
675             }
676              
677             =item tok_count_change
678              
679             public instance (Boolean) tok_count_change (Integer $spam_count,
680             Integer $ham_count,
681             String $token,
682             Time $atime)
683              
684             Description:
685             This method takes a C<$spam_count> and C<$ham_count> and adds it to
686             C<$token> along with updating C<$token>s atime with C<$atime>.
687              
688             =cut
689              
690             sub tok_count_change {
691 0     0 1   my ($self, $spam_count, $ham_count, $token, $atime) = @_;
692 0           die "bayes: tok_count_change: not implemented\n";
693             }
694              
695             =item multi_tok_count_change
696              
697             public instance (Boolean) multi_tok_count_change (Integer $spam_count,
698             Integer $ham_count,
699             \% $tokens,
700             String $atime)
701              
702             Description:
703             This method takes a C<$spam_count> and C<$ham_count> and adds it to all
704             of the tokens in the C<$tokens> hash ref along with updating each tokens
705             atime with C<$atime>.
706              
707             =cut
708              
709             sub multi_tok_count_change {
710 0     0 1   my ($self, $spam_count, $ham_count, $tokens, $atime) = @_;
711 0           die "bayes: multi_tok_count_change: not implemented\n";
712             }
713              
714             =item nspam_nham_get
715              
716             public instance (Integer, Integer) nspam_nham_get ()
717              
718             Description:
719             This method retrieves the total number of spam and the total number of ham
720             currently under storage.
721              
722             =cut
723              
724             sub nspam_nham_get {
725 0     0 1   my ($self) = @_;
726 0           die "bayes: nspam_nham_get: not implemented\n";
727             }
728              
729             =item nspam_nham_change
730              
731             public instance (Boolean) nspam_nham_change (Integer $num_spam,
732             Integer $num_ham)
733              
734             Description:
735             This method updates the number of spam and the number of ham in the database.
736              
737             =cut
738              
739             sub nspam_nham_change {
740 0     0 1   my ($self, $num_spam, $num_ham) = @_;
741 0           die "bayes: nspam_nham_change: not implemented\n";
742             }
743              
744             =item tok_touch
745              
746             public instance (Boolean) tok_touch (String $token,
747             Time $atime)
748              
749             Description:
750             This method updates the given tokens (C<$token>) access time.
751              
752             =cut
753              
754             sub tok_touch {
755 0     0 1   my ($self, $token, $atime) = @_;
756 0           die "bayes: tok_touch: not implemented\n";
757             }
758              
759             =item tok_touch_all
760              
761             public instance (Boolean) tok_touch_all (\@ $tokens,
762             Time $atime)
763              
764             Description:
765             This method does a mass update of the given list of tokens C<$tokens>, if the existing token
766             atime is < C<$atime>.
767              
768             =cut
769              
770             sub tok_touch_all {
771 0     0 1   my ($self, $tokens, $atime) = @_;
772 0           die "bayes: tok_touch_all: not implemented\n";
773             }
774              
775             =item cleanup
776              
777             public instance (Boolean) cleanup ()
778              
779             Description:
780             This method performs any cleanup necessary before moving onto the next
781             operation.
782              
783             =cut
784              
785             sub cleanup {
786 0     0 1   my ($self) = @_;
787 0           die "bayes: cleanup: not implemented\n";
788             }
789              
790             =item get_magic_re
791              
792             public instance get_magic_re (String)
793              
794             Description:
795             This method returns a regexp which indicates a magic token.
796              
797             =cut
798              
799             sub get_magic_re {
800 0     0 1   my ($self) = @_;
801 0           die "bayes: get_magic_re: not implemented\n";
802             }
803              
804             =item sync
805              
806             public instance (Boolean) sync (\% $opts)
807              
808             Description:
809             This method performs a sync of the database.
810              
811             =cut
812              
813             sub sync {
814 0     0 1   my ($self, $opts) = @_;
815 0           die "bayes: sync: not implemented\n";
816             }
817              
818             =item perform_upgrade
819              
820             public instance (Boolean) perform_upgrade (\% $opts)
821              
822             Description:
823             This method is a utility method that performs any necessary upgrades
824             between versions. It should know how to handle previous versions and
825             what needs to happen to upgrade them.
826              
827             A true return value indicates success.
828              
829             =cut
830              
831             sub perform_upgrade {
832 0     0 1   my ($self, $opts) = @_;
833 0           die "bayes: perform_upgrade: not implemented\n";
834             }
835              
836             =item clear_database
837              
838             public instance (Boolean) clear_database ()
839              
840             Description:
841             This method deletes all records for a particular user.
842              
843             Callers should be aware that any errors returned by this method
844             could causes the database to be inconsistent for the given user.
845              
846             =cut
847              
848             sub clear_database {
849 0     0 1   my ($self) = @_;
850 0           die "bayes: clear_database: not implemented\n";
851             }
852              
853             =item backup_database
854              
855             public instance (Boolean) backup_database ()
856              
857             Description:
858             This method will dump the users database in a machine readable format.
859              
860             =cut
861              
862             sub backup_database {
863 0     0 1   my ($self) = @_;
864 0           die "bayes: backup_database: not implemented\n";
865             }
866              
867             =item restore_database
868              
869             public instance (Boolean) restore_database (String $filename, Boolean $showdots)
870              
871             Description:
872             This method restores a database from the given filename, C<$filename>.
873              
874             Callers should be aware that any errors returned by this method
875             could causes the database to be inconsistent for the given user.
876              
877             =cut
878              
879             sub restore_database {
880 0     0 1   my ($self, $filename, $showdots) = @_;
881 0           die "bayes: restore_database: not implemented\n";
882             }
883              
884             =item db_readable
885              
886             public instance (Boolean) db_readable ()
887              
888             Description:
889             This method returns whether or not the Bayes DB is available in a
890             readable state.
891              
892             =cut
893              
894             sub db_readable {
895 0     0 1   my ($self) = @_;
896 0           die "bayes: db_readable: not implemented\n";
897             }
898              
899             =item db_writable
900              
901             public instance (Boolean) db_writable ()
902              
903             Description:
904             This method returns whether or not the Bayes DB is available in a
905             writable state.
906              
907             =cut
908              
909             sub db_writable {
910 0     0 1   my ($self) = @_;
911 0           die "bayes: db_writable: not implemented\n";
912             }
913              
914              
915 0     0 0   sub sa_die { Mail::SpamAssassin::sa_die(@_); }
916              
917             1;
918              
919             =back
920              
921             =cut