]> git.proxmox.com Git - proxmox-spamassassin.git/blame - upstream/spamassassin.raw
bump version to 4.0.1-1
[proxmox-spamassassin.git] / upstream / spamassassin.raw
CommitLineData
37ef5775
SI
1#!/usr/bin/perl -w
2
3# <@LICENSE>
4# Licensed to the Apache Software Foundation (ASF) under one or more
5# contributor license agreements. See the NOTICE file distributed with
6# this work for additional information regarding copyright ownership.
7# The ASF licenses this file to you under the Apache License, Version 2.0
8# (the "License"); you may not use this file except in compliance with
9# the License. You may obtain a copy of the License at:
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18# </@LICENSE>
19
20use strict;
21use warnings;
22use re 'taint';
23
24use File::Spec;
25
26my $PREFIX = '@@PREFIX@@'; # substituted at 'make' time
27my $DEF_RULES_DIR = '@@DEF_RULES_DIR@@'; # substituted at 'make' time
28my $LOCAL_RULES_DIR = '@@LOCAL_RULES_DIR@@'; # substituted at 'make' time
29my $LOCAL_STATE_DIR = '@@LOCAL_STATE_DIR@@'; # substituted at 'make' time
30
31use lib '@@INSTALLSITELIB@@'; # substituted at 'make' time
32
33BEGIN {
34 # Locate locally installed SA libraries *without* using FindBin, which
35 # generates warnings and causes more trouble than its worth. We don't
36 # need to be too smart about this BTW.
37 my @bin = File::Spec->splitpath($0);
38 my $bin = (
39 $bin[0]
40 ? File::Spec->catpath( @bin[ 0 .. 1 ], '' )
41 : $bin[1]
42 ) # /home/jm/foo -> /home/jm
43 || File::Spec->curdir; # foo -> .
44
45 # check to make sure it wasn't just installed in the normal way.
46 # note that ./lib/Mail/SpamAssassin.pm takes precedence, for
47 # building SpamAssassin on a machine where an old version is installed.
48 if (-e $bin.'/lib/Mail/SpamAssassin.pm'
49 || !-e '@@INSTALLSITELIB@@/Mail/SpamAssassin.pm' )
50 {
51 my $searchrelative;
52 $searchrelative = 1; # disabled during "make install": REMOVEFORINST
53
54 # Firstly, are we running "make test" in the "t" dir? the test files
55 # *need* to use 'blib', so that 'use bytes' is removed for pre-5.6 perls
56 # beforehand by the preproc. However, ./spamassassin does not, as the
57 # preproc will have stripped out the "use rule files from cwd" code from
58 # Mail::SpamAssassin. So we want to use blib just for the t scripts.
59 # This is disabled during the "make install" process.
60 if ($searchrelative && $bin eq '../' && -e '../blib/lib/Mail/SpamAssassin.pm')
61 {
62 unshift ( @INC, '../blib/lib' );
63 } else {
64 # These are common paths where the SA libs might be found.
65 foreach ( qw(lib ../lib/site_perl
66 ../lib/spamassassin ../share/spamassassin/lib))
67 {
68 my $dir = File::Spec->catdir( $bin, split ( '/', $_ ) );
69 if ( -f File::Spec->catfile( $dir, "Mail", "SpamAssassin.pm" ) )
70 { unshift ( @INC, $dir ); last; }
71 }
72 }
73 }
74}
75
76use Getopt::Long;
77use Pod::Usage;
78use POSIX qw(locale_h setsid sigprocmask _exit);
79use Mail::SpamAssassin;
80use Mail::SpamAssassin::ArchiveIterator;
81use Mail::SpamAssassin::Util::Progress;
82use Mail::SpamAssassin::Logger qw(log_message);
83
84BEGIN {
85 # redirect __WARN__, but NOT until after the
86 # Mail::SpamAssassin::Logger class has been parsed.
87 # do not trap warnings here based on eval scope; evals are very
88 # common throughout. die()s can be trapped in future though.
89 $SIG{__WARN__} = sub {
90 log_message("warn", $_[0]);
91 };
92};
93
94POSIX::setlocale(LC_TIME,'C');
95
96my %resphash = (
97 EX_OK => 0, # no problems
98 EX_USAGE => 64, # command line usage error
99 EX_DATAERR => 65, # data format error
100 EX_NOINPUT => 66, # cannot open input
101 EX_NOUSER => 67, # addressee unknown
102 EX_NOHOST => 68, # host name unknown
103 EX_UNAVAILABLE => 69, # service unavailable
104 EX_SOFTWARE => 70, # internal software error
105 EX_OSERR => 71, # system error (e.g., can't fork)
106 EX_OSFILE => 72, # critical OS file missing
107 EX_CANTCREAT => 73, # can't create (user) output file
108 EX_IOERR => 74, # input/output error
109 EX_TEMPFAIL => 75, # temp failure; user is invited to retry
110 EX_PROTOCOL => 76, # remote error in protocol
111 EX_NOPERM => 77, # permission denied
112 EX_CONFIG => 78, # configuration error
113);
114
115
116sub print_version {
117 printf("SpamAssassin version %s\n running on Perl version %s\n",
118 Mail::SpamAssassin::Version(),
119 join(".", map( 0+($_||0), ($] =~ /(\d)\.(\d{3})(\d{3})?/ ))))
120 or die "error writing: $!";
121}
122
123sub print_usage_and_exit {
124 my ( $message, $respnam ) = @_;
125 $respnam ||= 'EX_USAGE';
126
127 if ($respnam eq 'EX_OK' ) {
128 print_version();
129 print("\n") or die "error writing: $!";
130 }
131 pod2usage(
132 -verbose => 0,
133 -message => $message,
134 -exitval => $resphash{$respnam},
135 -input => "spamassassin-run.pod",
136 -pathlist => \@INC,
137 );
138}
139
140
141
142sub usage {
143 my ( $verbose, $message ) = @_;
144 my $ver = Mail::SpamAssassin::Version();
145
146 print "SpamAssassin version $ver\n" or die "error writing: $!";
147 pod2usage( -verbose => $verbose, -message => $message, -exitval => 64, -input => "spamassassin-run.pod", -pathlist => \@INC );
148
149}
150
151# Check to make sure the script version and the module version matches.
152# If not, die here! Also, deal with unchanged VERSION macro.
153if ($Mail::SpamAssassin::VERSION ne '@@VERSION@@' && '@@VERSION@@' ne "\@\@VERSION\@\@") {
154 die 'spamassassin: spamassassin script is v@@VERSION@@, but using modules v'.$Mail::SpamAssassin::VERSION."\n";
155}
156
157# by default:
158# - create user preference files
159# - have ArchiveIterator detect the input message format (file vs dir)
160#
ae52237f 161my %opt = ( 'create-prefs' => 1, 'format' => 'detect', pre => [], cf => [] );
37ef5775 162
ae52237f 163my $doing_welcomelist_operation = 0;
37ef5775
SI
164my $count = 0;
165my @targets = ();
166my $exitvalue;
167
168my $init_results = 0;
169my $progress;
170my $total_messages = 0;
171
172# gnu_getopt is not available in Getopt::Long 2.24, see bug 732
173# gnu_compat neither.
174Getopt::Long::Configure(
175 qw(bundling no_getopt_compat no_auto_abbrev no_ignore_case));
176GetOptions(
ae52237f
SI
177 'add-addr-to-blocklist=s' => \$opt{'add-addr-to-blocklist'},
178 'add-addr-to-welcomelist=s' => \$opt{'add-addr-to-welcomelist'},
179 'add-addr-to-blacklist=s' => \$opt{'add-addr-to-blocklist'}, # removed in 4.1
180 'add-addr-to-whitelist=s' => \$opt{'add-addr-to-welcomelist'}, # removed in 4.1
181 'add-to-blocklist' => \$opt{'add-to-blocklist'},
182 'add-to-welcomelist|W' => \$opt{'add-to-welcomelist'},
183 'add-to-blacklist' => \$opt{'add-to-blocklist'}, # removed in 4.1
184 'add-to-whitelist' => \$opt{'add-to-welcomelist'}, # removed in 4.1
f887dfc0 185 'username|u=s' => \$opt{'username'},
37ef5775
SI
186 'configpath|config-file|config-dir|c|C=s' => \$opt{'configpath'},
187 'create-prefs!' => \$opt{'create-prefs'},
ae52237f 188 'pre=s' => \@{$opt{'pre'}},
37ef5775
SI
189 'cf=s' => \@{$opt{'cf'}},
190 'debug|D:s' => \$opt{'debug'},
191 'error-code|exit-code|e:i' => \$opt{'error-code'},
192 'help|h|?' => \$opt{'help'},
193 '4|ipv4only|ipv4-only|ipv4' => sub { $opt{'force_ipv4'} = 1;
194 $opt{'force_ipv6'} = 0; },
195 '6' => sub { $opt{'force_ipv6'} = 1;
196 $opt{'force_ipv4'} = 0; },
197 'lint' => \$opt{'lint'},
ae52237f 198 'net' => \$opt{'net'},
37ef5775
SI
199 'local-only|local|L' => \$opt{'local'},
200 'mbox' => sub { $opt{'format'} = 'mbox'; },
201 'mbx' => sub { $opt{'format'} = 'mbx'; },
202 'prefspath|prefs-file|p=s' => \$opt{'prefspath'},
ae52237f
SI
203 'remove-addr-from-welcomelist=s' => \$opt{'remove-addr-from-welcomelist'},
204 'remove-from-welcomelist|R' => \$opt{'remove-from-welcomelist'},
205 'remove-addr-from-whitelist=s' => \$opt{'remove-addr-from-welcomelist'}, # removed in 4.1
206 'remove-from-whitelist' => \$opt{'remove-from-welcomelist'}, # removed in 4.1
37ef5775
SI
207 'remove-markup|despamassassinify|d' => \$opt{'remove-markup'},
208 'report|r' => \$opt{'report'},
209 'revoke|k' => \$opt{'revoke'},
210 'siteconfigpath=s' => \$opt{'siteconfigpath'},
211 'test-mode|test|t' => \$opt{'test-mode'},
212 'progress' => \$opt{'progress'},
213 'version|V' => \$opt{'version'},
214 'x' => sub { $opt{'create-prefs'} = 0 },
215
216 #
217 # NOTE: These are old options. We should ignore (but warn about)
218 # the ones that are now defaults. Everything else gets a die (see note2)
219 # so the user doesn't get us doing something they didn't expect.
220 #
221 # NOTE2: 'die' doesn't actually stop the process, GetOptions() catches
222 # it, then passes the error on, so we'll end up doing a Usage statement.
223 # You can avoid that by doing an explicit exit in the sub.
224 #
225
226 # last in 2.3
227 'pipe|P' => sub { warn "The -P option is deprecated as 'pipe mode' is now the default behavior, ignoring.\n" },
228 'F:i' => sub { warn "The -F option has been removed from spamassassin, please remove from your commandline and re-run.\n"; exit 2; },
229 'add-from!' => sub { warn "The --add-from option has been removed from spamassassin, please remove from your commandline and re-run.\n"; exit 2; },
230
231 # last in 2.4
232 'stop-at-threshold|S' => sub { warn "The -S option has been deprecated and is no longer supported, ignoring.\n" },
233
234 # last in 2.6
235 'log-to-mbox|l:s' => sub { warn "The -l option has been deprecated and is no longer supported, ignoring.\n" },
236 'warning-from|w:s' => sub { warn "The -w option has been removed from spamassassin, please remove from your commandline and re-run.\n"; exit 2; },
237 'whitelist-factory|M:s' => sub { warn "The -M option has been removed from spamassassin, please remove from your commandline and re-run.\n"; exit 2; },
238
239) or print_usage_and_exit();
240
241if ( defined $opt{'help'} ) {
242 print_usage_and_exit("For more information read the spamassassin man page.\n", 'EX_OK');
243}
244if ( defined $opt{'version'} ) {
245 print_version();
246 exit($resphash{'EX_OK'});
247}
248
249# set debug areas, if any specified (only useful for command-line tools)
250if (defined $opt{'debug'}) {
251 $opt{'debug'} ||= 'all';
252}
253
254if (Mail::SpamAssassin::Util::am_running_on_windows()) {
255 binmode(STDIN) or die "cannot set binmode on STDIN: $!"; # bug 4363
256 binmode(STDOUT) or die "cannot set binmode on STDOUT: $!";
257}
258
259# bug 5048: --lint should not cause network accesses
ae52237f
SI
260# allow --net to override for testing
261if ($opt{'lint'} && !$opt{'net'}) { $opt{'local'} = 1; }
37ef5775
SI
262
263# create the tester factory
ae52237f 264my $spamtest = Mail::SpamAssassin->new(
37ef5775
SI
265 {
266 rules_filename => $opt{'configpath'},
267 site_rules_filename => $opt{'siteconfigpath'},
268 userprefs_filename => $opt{'prefspath'},
f887dfc0 269 username => $opt{'username'},
37ef5775
SI
270 force_ipv4 => $opt{'force_ipv4'},
271 force_ipv6 => $opt{'force_ipv6'},
272 local_tests_only => $opt{'local'},
273 debug => $opt{'debug'},
274 dont_copy_prefs => ( $opt{'create-prefs'} ? 0 : 1 ),
ae52237f 275 pre_config_text => join("\n", @{$opt{'pre'}})."\n",
37ef5775
SI
276 post_config_text => join("\n", @{$opt{'cf'}})."\n",
277 require_rules => 1,
278 PREFIX => $PREFIX,
279 DEF_RULES_DIR => $DEF_RULES_DIR,
280 LOCAL_RULES_DIR => $LOCAL_RULES_DIR,
281 LOCAL_STATE_DIR => $LOCAL_STATE_DIR,
282 }
283);
284
285if ($opt{'lint'}) {
286 $spamtest->debug_diagnostics();
287 my $res = $spamtest->lint_rules();
ae52237f 288 $spamtest->finish();
37ef5775
SI
289 warn "lint: $res issues detected, please rerun with debug enabled for more information\n" if ($res and !$opt{'debug'});
290 # make sure we notice any write errors while flushing output buffer
291 close STDOUT or die "error closing STDOUT: $!";
292 close STDIN or die "error closing STDIN: $!";
f887dfc0 293 exit($res ? 1 : 0);
37ef5775
SI
294}
295
ae52237f
SI
296if ($opt{'remove-addr-from-welcomelist'} ||
297 $opt{'add-addr-to-welcomelist'} ||
298 $opt{'add-addr-to-blocklist'})
37ef5775
SI
299{
300 $spamtest->init(1);
301
ae52237f
SI
302 if ( $opt{'add-addr-to-welcomelist'} ) {
303 $spamtest->add_address_to_welcomelist($opt{'add-addr-to-welcomelist'}, 1);
37ef5775 304 }
ae52237f
SI
305 elsif ( $opt{'remove-addr-from-welcomelist'} ) {
306 $spamtest->remove_address_from_welcomelist($opt{'remove-addr-from-welcomelist'}, 1);
37ef5775 307 }
ae52237f
SI
308 elsif ( $opt{'add-addr-to-blocklist'} ) {
309 $spamtest->add_address_to_blocklist($opt{'add-addr-to-blocklist'}, 1);
37ef5775
SI
310 }
311 else {
ae52237f 312 die "spamassassin: oops! unhandled welcomelist operation";
37ef5775
SI
313 }
314
315 $spamtest->finish();
316 # make sure we notice any write errors while flushing output buffer
317 close STDOUT or die "error closing STDOUT: $!";
318 close STDIN or die "error closing STDIN: $!";
319 exit(0);
320}
321
ae52237f
SI
322# if we're going to do welcome/block-listing, let's prep now...
323if ( $opt{'remove-from-welcomelist'}
324 or $opt{'add-to-welcomelist'}
325 or $opt{'add-to-blocklist'} )
37ef5775 326{
ae52237f 327 $doing_welcomelist_operation = 1;
37ef5775
SI
328 $spamtest->init(1);
329}
330
331# if we're doing things in test mode, force disable long-term memory
ae52237f 332# functions like autowelcomelist and bayes autolearn.
37ef5775
SI
333# XXX - feels like we need a plugin hook here so plugins can be made
334# aware and take appropriate action.
335if ($opt{'test-mode'}) {
ae52237f 336 $spamtest->{'conf'}->{'use_auto_welcomelist'} = 0;
37ef5775
SI
337 $spamtest->{'conf'}->{'bayes_auto_learn'} = 0;
338}
339
340###########################################################################
341# Deal with the target listing, and STDIN -> tempfile
342
343my $tempfile; # will be defined if stdin -> tempfile
344push(@targets, @ARGV);
345@targets = ('-') unless @targets;
346
347for(my $elem = 0; $elem <= $#targets; $elem++) {
348 # ArchiveIterator doesn't really like STDIN, so if "-" is specified
349 # as a target, make it a temp file instead.
350 if ( $targets[$elem] =~ /(?:^|:)-$/ ) {
351 if (defined $tempfile) {
352 # uh-oh, stdin specified multiple times?
353 warn "skipping extra stdin target (".$targets[$elem].")\n";
354 splice @targets, $elem, 1;
355 $elem--; # go back to this element again
356 next;
357 }
358 else {
359 my $handle;
360 ( $tempfile, $handle ) = Mail::SpamAssassin::Util::secure_tmpfile();
361 binmode $handle or die "cannot set binmode on file $tempfile: $!";
362
363 # avoid slurping the whole file into memory, copy chunk by chunk
364 my($inbuf,$nread,$nwrites);
365 while ( $nread = sysread(STDIN, $inbuf, 32*1024) ) {
366 for (my $ofs = 0; $ofs < length($inbuf); $ofs += $nwrites) {
367 $nwrites = $handle->syswrite($inbuf, length($inbuf)-$ofs, $ofs);
368 defined $nwrites or die "error writing to $tempfile: $!";
369 }
370 }
371 undef $inbuf; # release storage
372 defined $nread or die "error reading from STDIN: $!";
373 close $handle or die "cannot close $tempfile: $!";
374
375 # re-aim the targets at the tempfile instead of STDIN
376 $targets[$elem] =~ s/-$/$tempfile/;
377 }
378 }
379
380 # make sure the target list is in the normal AI format
381 if ($targets[$elem] !~ /^[^:]*:[a-z]+:/) {
382 my $format = $opt{'format'} || 'detect';
383 $targets[$elem] = join ( ":", '', $format, $targets[$elem] );
384 }
385}
386
387###########################################################################
388
389setup_sig_handlers();
390
391# Everything below here needs ArchiveIterator ...
ae52237f 392my $iter = Mail::SpamAssassin::ArchiveIterator->new(
37ef5775
SI
393 {
394 'opt_max_size' => 0, # no limit
395 'opt_want_date' => 0
396 }
397);
398
399$iter->set_functions( \&wanted, \&result );
400
401# Go run the messages!
402# bug 4930: use a temp variable since "||=" decides whether or not to set the
403# value before the RHS is actually run, so if the RHS separately sets the LHS
404# variable, things don't work right. Stupid global variables. ;)
405my $eval_stat;
406eval {
407 my $runreturn = !$iter->run(@targets); $exitvalue ||= $runreturn; 1;
408} or do {
409 $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat;
410};
411
412$progress->final() if ($opt{progress} && $progress);
413
414# If we needed to make a tempfile, go delete it now.
415if (defined $tempfile) {
416 unlink $tempfile or die "cannot unlink temporary file $tempfile: $!";
417 undef $tempfile;
418}
419
420# Let folks know how many messages were handled, as long as the handling
421# didn't produce output (ala: check, test, or remove_markup ...)
ae52237f 422if ( $opt{'report'} || $opt{'revoke'} || $doing_welcomelist_operation ) {
37ef5775
SI
423 print "$count message(s) examined.\n" or die "error writing: $!";
424}
425
426# if the eval died from something, report it here and return an error.
427if (defined $eval_stat) { die $eval_stat; }
428
429$spamtest->finish() if $spamtest;
430
431# make sure we notice any write errors while flushing output buffer
432close STDOUT or die "error closing STDOUT: $!";
433close STDIN or die "error closing STDIN: $!";
434# Ok, exit!
435exit( $exitvalue || 0 );
436
437###########################################################################
438
439sub init_results {
440 $init_results = 1;
441
442 return unless $opt{'progress'};
443
444 $total_messages = $Mail::SpamAssassin::ArchiveIterator::MESSAGES;
445
446 $progress = Mail::SpamAssassin::Util::Progress->new({total => $total_messages,});
447}
448
449###########################################################################
450
451sub result {
452 my ($class, $result, $time) = @_;
453
454 # don't open results files until we get here to avoid overwriting files
455 &init_results if !$init_results;
456
457 $progress->update($count) if ($opt{progress} && $progress);
458}
459
460###########################################################################
461
462my $mail; # global, so signal handler can clean it up; bug 5626
463
464# make sure it only returns false values so that result_sub() isn't called...
465sub wanted {
466 $spamtest->timer_reset; # reset timers for each AI message
467 my $dataref = $_[3];
468 $mail = $spamtest->parse($dataref);
469 $count++;
470
ae52237f
SI
471 # This is a short cut -- doing welcome/block-list? Do it and return quickly.
472 if ($doing_welcomelist_operation) {
473 if ( $opt{'add-to-welcomelist'} ) {
474 $spamtest->add_all_addresses_to_welcomelist($mail, 1);
37ef5775 475 }
ae52237f
SI
476 elsif ( $opt{'remove-from-welcomelist'} ) {
477 $spamtest->remove_all_addresses_from_welcomelist($mail, 1);
37ef5775 478 }
ae52237f
SI
479 elsif ( $opt{'add-to-blocklist'} ) {
480 $spamtest->add_all_addresses_to_blocklist($mail, 1);
37ef5775
SI
481 }
482 else {
ae52237f 483 warn "spamassassin: oops! unhandled welcomelist operation";
37ef5775
SI
484 }
485
486 $mail->finish();
487 $mail = undef;
488 return 1;
489 }
490
491 # handle removing reports
492 if ( $opt{'remove-markup'} ) {
493
494 # If we're not going to retest, just remove the markup and print it out
495 if ( !$opt{'test-mode'} ) {
496 print $spamtest->remove_spamassassin_markup ($mail);
497 $mail->finish();
498 $mail = undef;
499 return 1;
500 }
501 else {
502
503 # remove the markup and retest it... a little more tricky ...
504 # go ahead and remove the markup, then fake that the clean version
505 # was what was sent in
506 #
507 my $new_mail =
508 $spamtest->parse( $spamtest->remove_spamassassin_markup($mail) );
509
510 $mail->finish();
511 $mail = $new_mail;
512 }
513 }
514
515 # handle reporting and revoking
516 if ( $opt{'report'} || $opt{'revoke'} ) {
517
518 # Make sure the message is clean first ...
519 my $new_mail =
520 $spamtest->parse( $spamtest->remove_spamassassin_markup($mail) );
521 $mail->finish();
522 $mail = $new_mail;
523
524 my $failed;
525 if ( $opt{'report'} && !$spamtest->report_as_spam($mail) ) {
526 $failed = 'report';
527 }
528
529 if ( $opt{'revoke'} && !$spamtest->revoke_as_spam($mail) ) {
530 $failed = 'revoke';
531 }
532
533 if ($failed) {
534 warn "spamassassin: warning, unable to $failed message\n";
535 warn "spamassassin: for more information, re-run with -D option to see debug output\n";
536 }
537
538 $mail->finish();
539 $mail = undef;
540 return 1;
541 }
542
543 # OK, do checks and put out the message.
544 my $status = $spamtest->check($mail);
545 print $status->rewrite_mail() or die "error writing: $!";
546
547 if ( $opt{'test-mode'} ) {
548 print $status->get_report() or die "error writing: $!";
549 }
550
551 # if this message was spam, set the exit value appropriately.
552 if ( defined $opt{'error-code'} && $status->is_spam() && !defined $exitvalue )
553 {
554 $exitvalue = $opt{'error-code'} || 5;
555 }
556
557 # clean up after ourselves
558 $mail->finish();
559 $mail = undef;
560
561 $status->finish();
562
563 return 1;
564}
565
566###########################################################################
567
568sub setup_sig_handlers {
569 $SIG{HUP} = \&kill_handler;
570 $SIG{INT} = \&kill_handler;
571 $SIG{TERM} = \&kill_handler;
572# $SIG{PIPE} = \&kill_handler;
573 $SIG{PIPE} = 'IGNORE';
574}
575
576sub kill_handler {
577 my ($sig) = @_;
578 warn "spamassassin: killed by SIG$sig\n";
579 if ($mail) {
580 $mail->finish(); # bug 5626: remove temp files etc.
581 $mail = undef;
582 }
583 if (defined $tempfile) { # bug 5557: additional paranoia about tmpfiles
584 unlink $tempfile or warn "cannot unlink temporary file $tempfile: $!";
585 undef $tempfile;
586 }
587 close STDOUT; close STDIN; # ignoring status
588 exit 15;
589}
590
591__END__
592
593# ---------------------------------------------------------------------------
594
595=head1 NAME
596
597spamassassin - extensible email filter used to identify spam
598
599=head1 DESCRIPTION
600
601SpamAssassin is an intelligent email filter which uses a diverse range of
602tests to identify unsolicited bulk email, more commonly known as "spam".
603These tests are applied to email headers and content to classify email
604using advanced statistical methods. In addition, SpamAssassin has a
605modular architecture that allows other technologies to be quickly wielded
606against spam and is designed for easy integration into virtually any email
607system.
608
609=head1 SYNOPSIS
610
611For ease of access, the SpamAssassin manual has been split up into
612several sections. If you're intending to read these straight through
613for the first time, the suggested order will tend to reduce the number
614of forward references.
615
616Extensive additional documentation for SpamAssassin is available,
617primarily on the SpamAssassin web site and wiki.
618
619You should be able to view SpamAssassin's documentation with your man(1)
620program or perldoc(1).
621
622=head2 OVERVIEW
623
624 spamassassin SpamAssassin overview (this section)
625
626=head2 CONFIGURATION
627
628 Mail::SpamAssassin::Conf SpamAssassin configuration files
629
630=head2 USAGE
631
632 spamassassin-run "spamassassin" front-end filtering script
633 sa-learn train SpamAssassin's Bayesian classifier
634 spamc client for spamd (faster than spamassassin)
635 spamd spamassassin server (needed by spamc)
636
637=head2 DEFAULT PLUGINS
638
639@@PLUGIN_POD@@
640
641=head1 WEB SITES
642
ae52237f
SI
643 SpamAssassin web site: https://spamassassin.apache.org/
644 Wiki-based documentation: https://wiki.apache.org/spamassassin/
37ef5775
SI
645
646=head1 USER MAILING LIST
647
648A users mailing list exists where other experienced users are often able
649to help and provide tips and advice. Subscription instructions are
650located on the SpamAssassin web site.
651
652=head1 CONFIGURATION FILES
653
654The SpamAssassin rule base, text templates, and rule description text
655are loaded from configuration files.
656
657Default configuration data is loaded from the first existing directory
658in:
659
660=over 4
661
662=item @@LOCAL_STATE_DIR@@/@@VERSION@@
663
664=item @@DEF_RULES_DIR@@
665
666=item @@PREFIX@@/share/spamassassin
667
668=item /usr/local/share/spamassassin
669
670=item /usr/share/spamassassin
671
672=back
673
674Site-specific configuration data is used to override any values which had
675already been set. This is loaded from the first existing directory in:
676
677=over 4
678
679=item @@LOCAL_RULES_DIR@@
680
681=item @@PREFIX@@/etc/mail/spamassassin
682
683=item @@PREFIX@@/etc/spamassassin
684
685=item /usr/local/etc/spamassassin
686
687=item /usr/pkg/etc/spamassassin
688
689=item /usr/etc/spamassassin
690
691=item /etc/mail/spamassassin
692
693=item /etc/spamassassin
694
695=back
696
697From those directories, SpamAssassin will first read files ending in
698".pre" in lexical order and then it will read files ending in ".cf" in
699lexical order (most files begin with two numbers to make the sorting
700order obvious).
701
702In other words, it will read F<init.pre> first, then F<10_default_prefs.cf> before
703F<50_scores.cf> and F<20_body_tests.cf> before F<20_head_tests.cf>.
704Options in later files will override earlier files.
705
706Individual user preferences are loaded from the location specified on
707the C<spamassassin>, C<sa-learn>, or C<spamd> command line (see respective
708manual page for details). If the location is not specified,
709F<~/.spamassassin/user_prefs> is used if it exists. SpamAssassin will
710create that file if it does not already exist, using
711F<user_prefs.template> as a template. That file will be looked for in:
712
713=over 4
714
715=item @@LOCAL_RULES_DIR@@
716
717=item @@PREFIX@@/etc/mail/spamassassin
718
719=item @@PREFIX@@/share/spamassassin
720
721=item /etc/spamassassin
722
723=item /etc/mail/spamassassin
724
725=item /usr/local/share/spamassassin
726
727=item /usr/share/spamassassin
728
729=back
730
731=head1 TAGGING
732
733The following two sections detail the default tagging and markup that
734takes place for messages when running C<spamassassin> or C<spamc> with
735C<spamd> in the default configuration.
736
737Note: before header modification and addition, all headers beginning
738with C<X-Spam-> are removed to prevent spammer mischief and also to
739avoid potential problems caused by prior invocations of SpamAssassin.
740
741=head2 TAGGING FOR SPAM MAILS
742
743By default, all messages with a calculated score of 5.0 or higher are
744tagged as spam.
745
746If an incoming message is tagged as spam, instead of modifying the
747original message, SpamAssassin will create a new report message and
748attach the original message as a message/rfc822 MIME part (ensuring the
749original message is completely preserved and easier to recover).
750
751The new report message inherits the following headers (if they are
752present) from the original spam message:
753
754=over 4
755
756=item From: header
757
758=item To: header
759
760=item Cc: header
761
762=item Subject: header
763
764=item Date: header
765
766=item Message-ID: header
767
768=back
769
770The above headers can be modified if the relevant C<rewrite_header>
771option is given (see C<Mail::SpamAssassin::Conf> for more information).
772
773By default these message headers are added to spam:
774
775=over 4
776
777=item X-Spam-Flag: header
778
779Set to C<YES>.
780
781=back
782
783The headers that added are fully configurable via the C<add_header>
784option (see C<Mail::SpamAssassin::Conf> for more information).
785
786=over 4
787
788=item spam mail body text
789
790The SpamAssassin report is added to top of the mail message body,
791if the message is marked as spam.
792
793=back
794
795=head2 DEFAULT TAGGING FOR ALL MAILS
796
797These headers are added to all messages, both spam and ham (non-spam).
798
799=over 4
800
801=item X-Spam-Checker-Version: header
802
803The version and subversion of SpamAssassin and the host where
804SpamAssassin was run.
805
806=item X-Spam-Level: header
807
808A series of "*" characters where each one represents a full score point.
809
810=item X-Spam-Status: header
811
812A string, C<(Yes|No), score=nn required=nn tests=xxx,xxx
813autolearn=(ham|spam|no|unavailable|failed)> is set in this header to
814reflect the filter status. For the first word, "Yes" means spam and
815"No" means ham (non-spam).
816
817=back
818
819The headers that added are fully configurable via the C<add_header>
820option (see C<Mail::SpamAssassin::Conf> for more information).
821
822=head1 INSTALLATION
823
824The B<spamassassin> command is part of the B<Mail::SpamAssassin> Perl module.
825Install this as a normal Perl module, using C<perl -MCPAN -e shell>, or by
826hand.
827
828Note that it is not possible to use the C<PERL5LIB> environment variable
829to affect where SpamAssassin finds its perl modules, due to limitations
830imposed by perl's "taint" security checks.
831
832For further details on how to install, please read the C<INSTALL> file
833from the SpamAssassin distribution.
834
835=head1 DEVELOPER DOCUMENTATION
836
837 Mail::SpamAssassin
838 Spam detector and markup engine
839
840 Mail::SpamAssassin::ArchiveIterator
841 find and process messages one at a time
842
ae52237f
SI
843 Mail::SpamAssassin::AutoWelcomelist
844 auto-welcomelist handler for SpamAssassin
37ef5775
SI
845
846 Mail::SpamAssassin::Bayes
847 determine spammishness using a Bayesian classifier
848
849 Mail::SpamAssassin::BayesStore
850 Bayesian Storage Module
851
852 Mail::SpamAssassin::BayesStore::SQL
853 SQL Bayesian Storage Module Implementation
854
855 Mail::SpamAssassin::Conf::LDAP
856 load SpamAssassin scores from LDAP database
857
858 Mail::SpamAssassin::Conf::Parser
859 parse SpamAssassin configuration
860
861 Mail::SpamAssassin::Conf::SQL
862 load SpamAssassin scores from SQL database
863
864 Mail::SpamAssassin::Message
865 decode, render, and hold an RFC-2822 message
866
867 Mail::SpamAssassin::Message::Metadata
868 extract metadata from a message
869
870 Mail::SpamAssassin::Message::Node
871 decode, render, and make available MIME message parts
872
873 Mail::SpamAssassin::PerMsgLearner
874 per-message status (spam or not-spam)
875
876 Mail::SpamAssassin::PerMsgStatus
877 per-message status (spam or not-spam)
878
879 Mail::SpamAssassin::PersistentAddrList
880 persistent address list base class
881
882 Mail::SpamAssassin::Plugin
883 SpamAssassin plugin base class
884
37ef5775
SI
885 Mail::SpamAssassin::Plugin::RelayCountry
886 add message metadata indicating the country code of each relay
887
888 Mail::SpamAssassin::Plugin::SPF
889 perform SPF verification tests
890
891 Mail::SpamAssassin::Plugin::URIDNSBL
892 look up URLs against DNS blocklists
893
894 Mail::SpamAssassin::SQLBasedAddrList
ae52237f 895 SpamAssassin SQL Based Auto Welcomelist
37ef5775
SI
896
897=head1 BUGS
898
f887dfc0 899See E<lt>https://issues.apache.org/SpamAssassin/E<gt>
37ef5775
SI
900
901=head1 AUTHORS
902
f887dfc0 903The SpamAssassin(tm) Project E<lt>https://spamassassin.apache.org/E<gt>
37ef5775
SI
904
905=head1 COPYRIGHT AND LICENSE
906
907SpamAssassin is distributed under the Apache License, Version 2.0, as
908described in the file C<LICENSE> included with the distribution.
909
910Copyright (C) 2015 The Apache Software Foundation
911