Filename | /usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm |
Statements | Executed 116592 statements in 810ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
5382 | 1 | 1 | 244ms | 244ms | is_rule_active | Mail::SpamAssassin::Conf::
811 | 1 | 1 | 171ms | 189ms | __ANON__[:280] | Mail::SpamAssassin::Conf::
190 | 1 | 1 | 80.1ms | 80.1ms | set_ports_range | Mail::SpamAssassin::Conf::
781 | 1 | 1 | 58.6ms | 324ms | __ANON__[:2981] | Mail::SpamAssassin::Conf::
7701 | 27 | 1 | 31.7ms | 31.7ms | CORE:match (opcode) | Mail::SpamAssassin::Conf::
655 | 1 | 1 | 30.6ms | 233ms | __ANON__[:3020] | Mail::SpamAssassin::Conf::
459 | 1 | 1 | 23.4ms | 28.2ms | __ANON__[:3750] | Mail::SpamAssassin::Conf::
465 | 1 | 1 | 21.5ms | 322ms | __ANON__[:3174] | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 20.4ms | 20.4ms | set_default_commands | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 18.2ms | 112ms | BEGIN@85 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 15.1ms | 16.5ms | BEGIN@88 | Mail::SpamAssassin::Conf::
128 | 1 | 1 | 13.5ms | 15.9ms | __ANON__[:3557] | Mail::SpamAssassin::Conf::
30 | 1 | 1 | 6.44ms | 87.4ms | __ANON__[:1685] | Mail::SpamAssassin::Conf::
270 | 1 | 1 | 5.85ms | 5.85ms | __ANON__[:2044] | Mail::SpamAssassin::Conf::
2338 | 4 | 1 | 5.10ms | 5.10ms | CORE:subst (opcode) | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 4.32ms | 26.3ms | BEGIN@86 | Mail::SpamAssassin::Conf::
71 | 1 | 1 | 2.43ms | 24.1ms | __ANON__[:3052] | Mail::SpamAssassin::Conf::
77 | 1 | 1 | 2.22ms | 2.70ms | __ANON__[:3206] | Mail::SpamAssassin::Conf::
27 | 1 | 1 | 2.13ms | 510ms | __ANON__[:4145] | Mail::SpamAssassin::Conf::
40 | 1 | 1 | 2.08ms | 13.9ms | __ANON__[:3088] | Mail::SpamAssassin::Conf::
192 | 1 | 1 | 1.78ms | 1.78ms | register_eval_rule | Mail::SpamAssassin::Conf::
48 | 1 | 1 | 1.52ms | 1.91ms | __ANON__[:3781] | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 1.33ms | 1.63ms | BEGIN@90 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 1.19ms | 1.20ms | __ANON__[:3804] | Mail::SpamAssassin::Conf::
15 | 1 | 1 | 1.13ms | 5.28ms | __ANON__[:2701] | Mail::SpamAssassin::Conf::
19 | 1 | 1 | 1.01ms | 3.75ms | __ANON__[:433] | Mail::SpamAssassin::Conf::
5 | 1 | 1 | 743µs | 865µs | __ANON__[:935] | Mail::SpamAssassin::Conf::
27 | 1 | 1 | 701µs | 507ms | load_plugin | Mail::SpamAssassin::Conf::
13 | 1 | 1 | 640µs | 2.33ms | __ANON__[:3122] | Mail::SpamAssassin::Conf::
15 | 1 | 1 | 584µs | 584µs | CORE:regcomp (opcode) | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 350µs | 29.8ms | new | Mail::SpamAssassin::Conf::
27 | 1 | 1 | 304µs | 304µs | load_plugin_succeeded | Mail::SpamAssassin::Conf::
24 | 1 | 1 | 301µs | 301µs | feature_bug6558_free | Mail::SpamAssassin::Conf::
36 | 1 | 1 | 215µs | 215µs | __ANON__[:3402] | Mail::SpamAssassin::Conf::
2 | 1 | 1 | 126µs | 132µs | __ANON__[:1419] | Mail::SpamAssassin::Conf::
15 | 1 | 1 | 103µs | 103µs | CORE:qr (opcode) | Mail::SpamAssassin::Conf::
3 | 3 | 1 | 103µs | 6.73ms | new_netset | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 92µs | 132µs | __ANON__[:3835] | Mail::SpamAssassin::Conf::
7 | 1 | 1 | 70µs | 70µs | perl_min_version_5010000 | Mail::SpamAssassin::Conf::
2 | 2 | 2 | 67µs | 86µs | set_score_set | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 51µs | 51µs | __ANON__[:1007] | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 44µs | 88µs | __ANON__[:3858] | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 39µs | 48µs | BEGIN@80 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 35µs | 35µs | CORE:ftdir (opcode) | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 34µs | 41µs | __ANON__[:1054] | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 31µs | 921µs | BEGIN@87 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 31µs | 7.67s | finish_parsing | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 29µs | 189µs | BEGIN@89 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 28µs | 28µs | found_any_rules | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 24µs | 5.03s | parse_rules | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 22µs | 111µs | BEGIN@91 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 22µs | 22µs | wipe_ports_range | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 21µs | 1.00ms | BEGIN@94 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 20µs | 27µs | BEGIN@82 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 20µs | 20µs | BEGIN@92 | Mail::SpamAssassin::Conf::
2 | 1 | 1 | 19µs | 19µs | feature_registryboundaries | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 19µs | 44µs | BEGIN@81 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 18µs | 68µs | BEGIN@83 | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 17µs | 17µs | __ANON__[:1437] | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 10µs | 10µs | feature_originating_ip_headers | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 9µs | 9µs | feature_yesno_takes_args | Mail::SpamAssassin::Conf::
1 | 1 | 1 | 8µs | 8µs | feature_dns_local_ports_permit_avoid | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1165] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1277] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1331] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1388] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1519] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1573] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1592] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1649] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1717] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1810] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1862] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:1881] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:2017] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:2364] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:2406] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:2663] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:3379] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:3470] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:3882] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:4175] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:417] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:4328] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:501] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:715] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:754] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:775] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:796] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:858] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | __ANON__[:974] | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | add_meta_depends | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | add_to_addrlist | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | add_to_addrlist_rcvd | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | clone | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | delete_rule | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | feature_bayes_auto_learn_on_error | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | feature_dns_query_restriction | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | feature_edns | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | feature_uri_host_listed | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | finish | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | free_uncompiled_rule_source | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | get_description_for_rule | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | get_rule_keys | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | get_rule_types | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | get_rule_value | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | get_score_set | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | maybe_body_only | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | maybe_header_only | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | mtime | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | parse_scores_only | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | regression_tests | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | remove_from_addrlist | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | remove_from_addrlist_rcvd | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | sa_die | Mail::SpamAssassin::Conf::
0 | 0 | 0 | 0s | 0s | trim_rules | Mail::SpamAssassin::Conf::
Line | State ments |
Time on line |
Calls | Time in subs |
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::Conf - SpamAssassin configuration file | ||||
21 | |||||
22 | =head1 SYNOPSIS | ||||
23 | |||||
24 | # a comment | ||||
25 | |||||
26 | rewrite_header Subject *****SPAM***** | ||||
27 | |||||
28 | full PARA_A_2_C_OF_1618 /Paragraph .a.{0,10}2.{0,10}C. of S. 1618/i | ||||
29 | describe PARA_A_2_C_OF_1618 Claims compliance with senate bill 1618 | ||||
30 | |||||
31 | header FROM_HAS_MIXED_NUMS From =~ /\d+[a-z]+\d+\S*@/i | ||||
32 | describe FROM_HAS_MIXED_NUMS From: contains numbers mixed in with letters | ||||
33 | |||||
34 | score A_HREF_TO_REMOVE 2.0 | ||||
35 | |||||
36 | lang es describe FROM_FORGED_HOTMAIL Forzado From: simula ser de hotmail.com | ||||
37 | |||||
38 | lang pt_BR report O programa detetor de Spam ZOE [...] | ||||
39 | |||||
40 | =head1 DESCRIPTION | ||||
41 | |||||
42 | SpamAssassin is configured using traditional UNIX-style configuration files, | ||||
43 | loaded from the C</usr/share/spamassassin> and C</etc/mail/spamassassin> | ||||
44 | directories. | ||||
45 | |||||
46 | The following web page lists the most important configuration settings | ||||
47 | used to configure SpamAssassin; novices are encouraged to read it first: | ||||
48 | |||||
49 | http://wiki.apache.org/spamassassin/ImportantInitialConfigItems | ||||
50 | |||||
51 | =head1 FILE FORMAT | ||||
52 | |||||
53 | The C<#> character starts a comment, which continues until end of line. | ||||
54 | B<NOTE:> if the C<#> character is to be used as part of a rule or | ||||
55 | configuration option, it must be escaped with a backslash. i.e.: C<\#> | ||||
56 | |||||
57 | Whitespace in the files is not significant, but please note that starting a | ||||
58 | line with whitespace is deprecated, as we reserve its use for multi-line rule | ||||
59 | definitions, at some point in the future. | ||||
60 | |||||
61 | Currently, each rule or configuration setting must fit on one-line; multi-line | ||||
62 | settings are not supported yet. | ||||
63 | |||||
64 | File and directory paths can use C<~> to refer to the user's home | ||||
65 | directory, but no other shell-style path extensions such as globing or | ||||
66 | C<~user/> are supported. | ||||
67 | |||||
68 | Where appropriate below, default values are listed in parentheses. | ||||
69 | |||||
70 | =head1 USER PREFERENCES | ||||
71 | |||||
72 | The following options can be used in both site-wide (C<local.cf>) and | ||||
73 | user-specific (C<user_prefs>) configuration files to customize how | ||||
74 | SpamAssassin handles incoming email messages. | ||||
75 | |||||
76 | =cut | ||||
77 | |||||
78 | package Mail::SpamAssassin::Conf; | ||||
79 | |||||
80 | 2 | 53µs | 2 | 57µs | # spent 48µs (39+9) within Mail::SpamAssassin::Conf::BEGIN@80 which was called:
# once (39µs+9µs) by Mail::SpamAssassin::BEGIN@71 at line 80 # spent 48µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@80
# spent 9µs making 1 call to strict::import |
81 | 2 | 50µs | 2 | 69µs | # spent 44µs (19+25) within Mail::SpamAssassin::Conf::BEGIN@81 which was called:
# once (19µs+25µs) by Mail::SpamAssassin::BEGIN@71 at line 81 # spent 44µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@81
# spent 25µs making 1 call to warnings::import |
82 | 2 | 53µs | 2 | 34µs | # spent 27µs (20+7) within Mail::SpamAssassin::Conf::BEGIN@82 which was called:
# once (20µs+7µs) by Mail::SpamAssassin::BEGIN@71 at line 82 # spent 27µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@82
# spent 7µs making 1 call to bytes::import |
83 | 2 | 53µs | 2 | 118µs | # spent 68µs (18+50) within Mail::SpamAssassin::Conf::BEGIN@83 which was called:
# once (18µs+50µs) by Mail::SpamAssassin::BEGIN@71 at line 83 # spent 68µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@83
# spent 50µs making 1 call to re::import |
84 | |||||
85 | 2 | 308µs | 2 | 112ms | # spent 112ms (18.2+93.4) within Mail::SpamAssassin::Conf::BEGIN@85 which was called:
# once (18.2ms+93.4ms) by Mail::SpamAssassin::BEGIN@71 at line 85 # spent 112ms making 1 call to Mail::SpamAssassin::Conf::BEGIN@85
# spent 91µs making 1 call to Exporter::import |
86 | 2 | 332µs | 1 | 26.3ms | # spent 26.3ms (4.32+22.0) within Mail::SpamAssassin::Conf::BEGIN@86 which was called:
# once (4.32ms+22.0ms) by Mail::SpamAssassin::BEGIN@71 at line 86 # spent 26.3ms making 1 call to Mail::SpamAssassin::Conf::BEGIN@86 |
87 | 2 | 72µs | 2 | 1.81ms | # spent 921µs (31+890) within Mail::SpamAssassin::Conf::BEGIN@87 which was called:
# once (31µs+890µs) by Mail::SpamAssassin::BEGIN@71 at line 87 # spent 921µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@87
# spent 890µs making 1 call to Exporter::import |
88 | 2 | 566µs | 1 | 16.5ms | # spent 16.5ms (15.1+1.35) within Mail::SpamAssassin::Conf::BEGIN@88 which was called:
# once (15.1ms+1.35ms) by Mail::SpamAssassin::BEGIN@71 at line 88 # spent 16.5ms making 1 call to Mail::SpamAssassin::Conf::BEGIN@88 |
89 | 2 | 63µs | 2 | 348µs | # spent 189µs (29+159) within Mail::SpamAssassin::Conf::BEGIN@89 which was called:
# once (29µs+159µs) by Mail::SpamAssassin::BEGIN@71 at line 89 # spent 189µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@89
# spent 159µs making 1 call to Exporter::import |
90 | 2 | 360µs | 1 | 1.63ms | # spent 1.63ms (1.33+306µs) within Mail::SpamAssassin::Conf::BEGIN@90 which was called:
# once (1.33ms+306µs) by Mail::SpamAssassin::BEGIN@71 at line 90 # spent 1.63ms making 1 call to Mail::SpamAssassin::Conf::BEGIN@90 |
91 | 2 | 57µs | 2 | 200µs | # spent 111µs (22+89) within Mail::SpamAssassin::Conf::BEGIN@91 which was called:
# once (22µs+89µs) by Mail::SpamAssassin::BEGIN@71 at line 91 # spent 111µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@91
# spent 89µs making 1 call to Exporter::import |
92 | 2 | 118µs | 1 | 20µs | # spent 20µs within Mail::SpamAssassin::Conf::BEGIN@92 which was called:
# once (20µs+0s) by Mail::SpamAssassin::BEGIN@71 at line 92 # spent 20µs making 1 call to Mail::SpamAssassin::Conf::BEGIN@92 |
93 | |||||
94 | 1 | 2µs | # spent 1.00ms (21µs+983µs) within Mail::SpamAssassin::Conf::BEGIN@94 which was called:
# once (21µs+983µs) by Mail::SpamAssassin::BEGIN@71 at line 109 | ||
95 | @ISA | ||||
96 | $CONF_TYPE_STRING $CONF_TYPE_BOOL | ||||
97 | $CONF_TYPE_NUMERIC $CONF_TYPE_HASH_KEY_VALUE | ||||
98 | $CONF_TYPE_ADDRLIST $CONF_TYPE_TEMPLATE | ||||
99 | $CONF_TYPE_STRINGLIST $CONF_TYPE_IPADDRLIST | ||||
100 | $CONF_TYPE_DURATION $CONF_TYPE_NOARGS | ||||
101 | $MISSING_REQUIRED_VALUE $INVALID_VALUE $INVALID_HEADER_FIELD_NAME | ||||
102 | @MIGRATED_SETTINGS | ||||
103 | $COLLECT_REGRESSION_TESTS | ||||
104 | |||||
105 | $TYPE_HEAD_TESTS $TYPE_HEAD_EVALS | ||||
106 | $TYPE_BODY_TESTS $TYPE_BODY_EVALS $TYPE_FULL_TESTS $TYPE_FULL_EVALS | ||||
107 | $TYPE_RAWBODY_TESTS $TYPE_RAWBODY_EVALS $TYPE_URI_TESTS $TYPE_URI_EVALS | ||||
108 | $TYPE_META_TESTS $TYPE_RBL_EVALS $TYPE_EMPTY_TESTS | ||||
109 | 1 | 28.2ms | 2 | 1.99ms | }; # spent 1.00ms making 1 call to Mail::SpamAssassin::Conf::BEGIN@94
# spent 983µs making 1 call to vars::import |
110 | |||||
111 | 1 | 25µs | @ISA = qw(); | ||
112 | |||||
113 | # odd => eval test. Not constants so they can be shared with Parser | ||||
114 | # TODO: move to Constants.pm? | ||||
115 | 1 | 2µs | $TYPE_HEAD_TESTS = 0x0008; | ||
116 | 1 | 2µs | $TYPE_HEAD_EVALS = 0x0009; | ||
117 | 1 | 2µs | $TYPE_BODY_TESTS = 0x000a; | ||
118 | 1 | 2µs | $TYPE_BODY_EVALS = 0x000b; | ||
119 | 1 | 2µs | $TYPE_FULL_TESTS = 0x000c; | ||
120 | 1 | 1µs | $TYPE_FULL_EVALS = 0x000d; | ||
121 | 1 | 2µs | $TYPE_RAWBODY_TESTS = 0x000e; | ||
122 | 1 | 2µs | $TYPE_RAWBODY_EVALS = 0x000f; | ||
123 | 1 | 2µs | $TYPE_URI_TESTS = 0x0010; | ||
124 | 1 | 2µs | $TYPE_URI_EVALS = 0x0011; | ||
125 | 1 | 1µs | $TYPE_META_TESTS = 0x0012; | ||
126 | 1 | 2µs | $TYPE_RBL_EVALS = 0x0013; | ||
127 | 1 | 1µs | $TYPE_EMPTY_TESTS = 0x0014; | ||
128 | |||||
129 | 1 | 7µs | my @rule_types = ("body_tests", "uri_tests", "uri_evals", | ||
130 | "head_tests", "head_evals", "body_evals", "full_tests", | ||||
131 | "full_evals", "rawbody_tests", "rawbody_evals", | ||||
132 | "rbl_evals", "meta_tests"); | ||||
133 | |||||
134 | #Removed $VERSION per BUG 6422 | ||||
135 | #$VERSION = 'bogus'; # avoid CPAN.pm picking up version strings later | ||||
136 | |||||
137 | # these are variables instead of constants so that other classes can | ||||
138 | # access them; if they're constants, they'd have to go in Constants.pm | ||||
139 | # TODO: move to Constants.pm? | ||||
140 | 1 | 2µs | $CONF_TYPE_STRING = 1; | ||
141 | 1 | 2µs | $CONF_TYPE_BOOL = 2; | ||
142 | 1 | 2µs | $CONF_TYPE_NUMERIC = 3; | ||
143 | 1 | 1µs | $CONF_TYPE_HASH_KEY_VALUE = 4; | ||
144 | 1 | 2µs | $CONF_TYPE_ADDRLIST = 5; | ||
145 | 1 | 2µs | $CONF_TYPE_TEMPLATE = 6; | ||
146 | 1 | 2µs | $CONF_TYPE_NOARGS = 7; | ||
147 | 1 | 2µs | $CONF_TYPE_STRINGLIST = 8; | ||
148 | 1 | 2µs | $CONF_TYPE_IPADDRLIST = 9; | ||
149 | 1 | 2µs | $CONF_TYPE_DURATION = 10; | ||
150 | 1 | 2µs | $MISSING_REQUIRED_VALUE = '-99999999999999'; # string expected by parser | ||
151 | 1 | 2µs | $INVALID_VALUE = '-99999999999998'; | ||
152 | 1 | 3µs | $INVALID_HEADER_FIELD_NAME = '-99999999999997'; | ||
153 | |||||
154 | # set to "1" by the test suite code, to record regression tests | ||||
155 | # $Mail::SpamAssassin::Conf::COLLECT_REGRESSION_TESTS = 1; | ||||
156 | |||||
157 | # search for "sub new {" to find the start of the code | ||||
158 | ########################################################################### | ||||
159 | |||||
160 | # spent 20.4ms within Mail::SpamAssassin::Conf::set_default_commands which was called:
# once (20.4ms+0s) by Mail::SpamAssassin::Conf::new at line 4516 | ||||
161 | 1 | 2µs | my($self) = @_; | ||
162 | |||||
163 | # see "perldoc Mail::SpamAssassin::Conf::Parser" for details on this fmt. | ||||
164 | # push each config item like this, to avoid a POD bug; it can't just accept | ||||
165 | # ( { ... }, { ... }, { ...} ) otherwise POD parsing dies. | ||||
166 | 1 | 2µs | my @cmds; | ||
167 | |||||
168 | =head2 SCORING OPTIONS | ||||
169 | |||||
170 | =over 4 | ||||
171 | |||||
172 | =item required_score n.nn (default: 5) | ||||
173 | |||||
174 | Set the score required before a mail is considered spam. C<n.nn> can | ||||
175 | be an integer or a real number. 5.0 is the default setting, and is | ||||
176 | quite aggressive; it would be suitable for a single-user setup, but if | ||||
177 | you're an ISP installing SpamAssassin, you should probably set the | ||||
178 | default to be more conservative, like 8.0 or 10.0. It is not | ||||
179 | recommended to automatically delete or discard messages marked as | ||||
180 | spam, as your users B<will> complain, but if you choose to do so, only | ||||
181 | delete messages with an exceptionally high score such as 15.0 or | ||||
182 | higher. This option was previously known as C<required_hits> and that | ||||
183 | name is still accepted, but is deprecated. | ||||
184 | |||||
185 | =cut | ||||
186 | |||||
187 | 1 | 11µs | push (@cmds, { | ||
188 | setting => 'required_score', | ||||
189 | aliases => ['required_hits'], # backward compatible | ||||
190 | default => 5, | ||||
191 | type => $CONF_TYPE_NUMERIC, | ||||
192 | }); | ||||
193 | |||||
194 | =item score SYMBOLIC_TEST_NAME n.nn [ n.nn n.nn n.nn ] | ||||
195 | |||||
196 | Assign scores (the number of points for a hit) to a given test. | ||||
197 | Scores can be positive or negative real numbers or integers. | ||||
198 | C<SYMBOLIC_TEST_NAME> is the symbolic name used by SpamAssassin for | ||||
199 | that test; for example, 'FROM_ENDS_IN_NUMS'. | ||||
200 | |||||
201 | If only one valid score is listed, then that score is always used | ||||
202 | for a test. | ||||
203 | |||||
204 | If four valid scores are listed, then the score that is used depends | ||||
205 | on how SpamAssassin is being used. The first score is used when | ||||
206 | both Bayes and network tests are disabled (score set 0). The second | ||||
207 | score is used when Bayes is disabled, but network tests are enabled | ||||
208 | (score set 1). The third score is used when Bayes is enabled and | ||||
209 | network tests are disabled (score set 2). The fourth score is used | ||||
210 | when Bayes is enabled and network tests are enabled (score set 3). | ||||
211 | |||||
212 | Setting a rule's score to 0 will disable that rule from running. | ||||
213 | |||||
214 | If any of the score values are surrounded by parenthesis '()', then | ||||
215 | all of the scores in the line are considered to be relative to the | ||||
216 | already set score. ie: '(3)' means increase the score for this | ||||
217 | rule by 3 points in all score sets. '(3) (0) (3) (0)' means increase | ||||
218 | the score for this rule by 3 in score sets 0 and 2 only. | ||||
219 | |||||
220 | If no score is given for a test by the end of the configuration, | ||||
221 | a default score is assigned: a score of 1.0 is used for all tests, | ||||
222 | except those whose names begin with 'T_' (this is used to indicate a | ||||
223 | rule in testing) which receive 0.01. | ||||
224 | |||||
225 | Note that test names which begin with '__' are indirect rules used | ||||
226 | to compose meta-match rules and can also act as prerequisites to | ||||
227 | other rules. They are not scored or listed in the 'tests hit' | ||||
228 | reports, but assigning a score of 0 to an indirect rule will disable | ||||
229 | it from running. | ||||
230 | |||||
231 | =cut | ||||
232 | |||||
233 | push (@cmds, { | ||||
234 | setting => 'score', | ||||
235 | is_frequent => 1, | ||||
236 | # spent 189ms (171+17.8) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:280] which was called 811 times, avg 233µs/call:
# 811 times (171ms+17.8ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 233µs/call | ||||
237 | 811 | 5.91ms | my ($self, $key, $value, $line) = @_; | ||
238 | 811 | 12.7ms | my($rule, @scores) = split(/\s+/, $value); | ||
239 | 811 | 10.3ms | 811 | 2.10ms | unless (defined $value && $value !~ /^$/ && # spent 2.10ms making 811 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
240 | (scalar @scores == 1 || scalar @scores == 4)) { | ||||
241 | info("config: score: requires a symbolic rule name and 1 or 4 scores"); | ||||
242 | return $MISSING_REQUIRED_VALUE; | ||||
243 | } | ||||
244 | |||||
245 | # Figure out if we're doing relative scores, remove the parens if we are | ||||
246 | 811 | 1.39ms | my $relative = 0; | ||
247 | 811 | 3.17ms | foreach (@scores) { | ||
248 | 2323 | 8.92ms | local ($1); | ||
249 | 2323 | 38.4ms | 2323 | 5.07ms | if (s/^\((-?\d+(?:\.\d+)?)\)$/$1/) { # spent 5.07ms making 2323 calls to Mail::SpamAssassin::Conf::CORE:subst, avg 2µs/call |
250 | $relative = 1; | ||||
251 | } | ||||
252 | 2323 | 45.2ms | 2323 | 10.6ms | unless (/^-?\d+(?:\.\d+)?$/) { # spent 10.6ms making 2323 calls to Mail::SpamAssassin::Conf::CORE:match, avg 5µs/call |
253 | info("config: score: the non-numeric score ($_) is not valid, " . | ||||
254 | "a numeric score is required"); | ||||
255 | return $INVALID_VALUE; | ||||
256 | } | ||||
257 | } | ||||
258 | |||||
259 | 811 | 1.31ms | if ($relative && !exists $self->{scoreset}->[0]->{$rule}) { | ||
260 | info("config: score: relative score without previous setting in " . | ||||
261 | "configuration"); | ||||
262 | return $INVALID_VALUE; | ||||
263 | } | ||||
264 | |||||
265 | # If we're only passed 1 score, copy it to the other scoresets | ||||
266 | 811 | 19.9ms | if (@scores) { | ||
267 | 811 | 2.00ms | if (@scores != 4) { | ||
268 | 307 | 2.42ms | @scores = ( $scores[0], $scores[0], $scores[0], $scores[0] ); | ||
269 | } | ||||
270 | |||||
271 | # Set the actual scoreset values appropriately | ||||
272 | 811 | 3.15ms | for my $index (0..3) { | ||
273 | my $score = $relative ? | ||||
274 | 3244 | 7.71ms | $self->{scoreset}->[$index]->{$rule} + $scores[$index] : | ||
275 | $scores[$index]; | ||||
276 | |||||
277 | 3244 | 38.7ms | $self->{scoreset}->[$index]->{$rule} = $score + 0.0; | ||
278 | } | ||||
279 | } | ||||
280 | } | ||||
281 | 1 | 19µs | }); | ||
282 | |||||
283 | =back | ||||
284 | |||||
285 | =head2 WHITELIST AND BLACKLIST OPTIONS | ||||
286 | |||||
287 | =over 4 | ||||
288 | |||||
289 | =item whitelist_from user@example.com | ||||
290 | |||||
291 | Used to whitelist sender addresses which send mail that is often tagged | ||||
292 | (incorrectly) as spam. | ||||
293 | |||||
294 | Use of this setting is not recommended, since it blindly trusts the message, | ||||
295 | which is routinely and easily forged by spammers and phish senders. The | ||||
296 | recommended solution is to instead use C<whitelist_auth> or other authenticated | ||||
297 | whitelisting methods, or C<whitelist_from_rcvd>. | ||||
298 | |||||
299 | Whitelist and blacklist addresses are now file-glob-style patterns, so | ||||
300 | C<friend@somewhere.com>, C<*@isp.com>, or C<*.domain.net> will all work. | ||||
301 | Specifically, C<*> and C<?> are allowed, but all other metacharacters | ||||
302 | are not. Regular expressions are not used for security reasons. | ||||
303 | Matching is case-insensitive. | ||||
304 | |||||
305 | Multiple addresses per line, separated by spaces, is OK. Multiple | ||||
306 | C<whitelist_from> lines are also OK. | ||||
307 | |||||
308 | The headers checked for whitelist addresses are as follows: if C<Resent-From> | ||||
309 | is set, use that; otherwise check all addresses taken from the following | ||||
310 | set of headers: | ||||
311 | |||||
312 | Envelope-Sender | ||||
313 | Resent-Sender | ||||
314 | X-Envelope-From | ||||
315 | From | ||||
316 | |||||
317 | In addition, the "envelope sender" data, taken from the SMTP envelope data | ||||
318 | where this is available, is looked up. See C<envelope_sender_header>. | ||||
319 | |||||
320 | e.g. | ||||
321 | |||||
322 | whitelist_from joe@example.com fred@example.com | ||||
323 | whitelist_from *@example.com | ||||
324 | |||||
325 | =cut | ||||
326 | |||||
327 | 1 | 5µs | push (@cmds, { | ||
328 | setting => 'whitelist_from', | ||||
329 | type => $CONF_TYPE_ADDRLIST, | ||||
330 | }); | ||||
331 | |||||
332 | =item unwhitelist_from user@example.com | ||||
333 | |||||
334 | Used to override a default whitelist_from entry, so for example a distribution | ||||
335 | whitelist_from can be overridden in a local.cf file, or an individual user can | ||||
336 | override a whitelist_from entry in their own C<user_prefs> file. | ||||
337 | The specified email address has to match exactly (although case-insensitively) | ||||
338 | the address previously used in a whitelist_from line, which implies that a | ||||
339 | wildcard only matches literally the same wildcard (not 'any' address). | ||||
340 | |||||
341 | e.g. | ||||
342 | |||||
343 | unwhitelist_from joe@example.com fred@example.com | ||||
344 | unwhitelist_from *@example.com | ||||
345 | |||||
346 | =cut | ||||
347 | |||||
348 | 1 | 7µs | push (@cmds, { | ||
349 | command => 'unwhitelist_from', | ||||
350 | setting => 'whitelist_from', | ||||
351 | type => $CONF_TYPE_ADDRLIST, | ||||
352 | code => \&Mail::SpamAssassin::Conf::Parser::remove_addrlist_value | ||||
353 | }); | ||||
354 | |||||
355 | =item whitelist_from_rcvd addr@lists.sourceforge.net sourceforge.net | ||||
356 | |||||
357 | Works similarly to whitelist_from, except that in addition to matching | ||||
358 | a sender address, a relay's rDNS name or its IP address must match too | ||||
359 | for the whitelisting rule to fire. The first parameter is a sender's e-mail | ||||
360 | address to whitelist, and the second is a string to match the relay's rDNS, | ||||
361 | or its IP address. Matching is case-insensitive. | ||||
362 | |||||
363 | This second parameter is matched against the TCP-info information field as | ||||
364 | provided in a FROM clause of a trace information (i.e. the Received header | ||||
365 | field, see RFC 5321). Only the Received header fields inserted by trusted | ||||
366 | hosts are considered. This parameter can either be a full hostname, or the | ||||
367 | domain component of that hostname, or an IP address in square brackets. | ||||
368 | The reverse DNS lookup is done by a MTA, not by SpamAssassin. | ||||
369 | |||||
370 | In case of an IPv4 address in brackets, it may be truncated on classful | ||||
371 | boundaries to cover whole subnets, e.g. C<[10.1.2.3]>, C<[10.1.2]>, | ||||
372 | C<[10.1]>, C<[10]>. CIDR notation is currently not supported, nor is | ||||
373 | IPv6. The matching on IP address is mainly provided to cover rare cases | ||||
374 | where whitelisting of a sending MTA is desired which does not have a | ||||
375 | correct reverse DNS configured. | ||||
376 | |||||
377 | In other words, if the host that connected to your MX had an IP address | ||||
378 | 192.0.2.123 that mapped to 'sendinghost.example.org', you should specify | ||||
379 | C<sendinghost.example.org>, or C<example.org>, or C<[192.0.2.123]> or | ||||
380 | C<[192.0.2]> here. | ||||
381 | |||||
382 | Note that this requires that C<internal_networks> be correct. For simple | ||||
383 | cases, it will be, but for a complex network you may get better results | ||||
384 | by setting that parameter. | ||||
385 | |||||
386 | It also requires that your mail exchangers be configured to perform DNS | ||||
387 | reverse lookups on the connecting host's IP address, and to record the | ||||
388 | result in the generated Received header field according to RFC 5321. | ||||
389 | |||||
390 | e.g. | ||||
391 | |||||
392 | whitelist_from_rcvd joe@example.com example.com | ||||
393 | whitelist_from_rcvd *@axkit.org sergeant.org | ||||
394 | whitelist_from_rcvd *@axkit.org [192.0.2.123] | ||||
395 | |||||
396 | =item def_whitelist_from_rcvd addr@lists.sourceforge.net sourceforge.net | ||||
397 | |||||
398 | Same as C<whitelist_from_rcvd>, but used for the default whitelist entries | ||||
399 | in the SpamAssassin distribution. The whitelist score is lower, because | ||||
400 | these are often targets for spammer spoofing. | ||||
401 | |||||
402 | =cut | ||||
403 | |||||
404 | push (@cmds, { | ||||
405 | setting => 'whitelist_from_rcvd', | ||||
406 | type => $CONF_TYPE_ADDRLIST, | ||||
407 | code => sub { | ||||
408 | my ($self, $key, $value, $line) = @_; | ||||
409 | unless (defined $value && $value !~ /^$/) { | ||||
410 | return $MISSING_REQUIRED_VALUE; | ||||
411 | } | ||||
412 | unless ($value =~ /^\S+\s+\S+$/) { | ||||
413 | return $INVALID_VALUE; | ||||
414 | } | ||||
415 | $self->{parser}->add_to_addrlist_rcvd ('whitelist_from_rcvd', | ||||
416 | split(/\s+/, $value)); | ||||
417 | } | ||||
418 | 1 | 12µs | }); | ||
419 | |||||
420 | push (@cmds, { | ||||
421 | setting => 'def_whitelist_from_rcvd', | ||||
422 | type => $CONF_TYPE_ADDRLIST, | ||||
423 | # spent 3.75ms (1.01+2.75) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:433] which was called 19 times, avg 198µs/call:
# 19 times (1.01ms+2.75ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 198µs/call | ||||
424 | 19 | 230µs | my ($self, $key, $value, $line) = @_; | ||
425 | 19 | 198µs | 19 | 48µs | unless (defined $value && $value !~ /^$/) { # spent 48µs making 19 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
426 | return $MISSING_REQUIRED_VALUE; | ||||
427 | } | ||||
428 | 19 | 196µs | 19 | 67µs | unless ($value =~ /^\S+\s+\S+$/) { # spent 67µs making 19 calls to Mail::SpamAssassin::Conf::CORE:match, avg 4µs/call |
429 | return $INVALID_VALUE; | ||||
430 | } | ||||
431 | 19 | 511µs | 19 | 2.63ms | $self->{parser}->add_to_addrlist_rcvd ('def_whitelist_from_rcvd', # spent 2.63ms making 19 calls to Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd, avg 138µs/call |
432 | split(/\s+/, $value)); | ||||
433 | } | ||||
434 | 1 | 10µs | }); | ||
435 | |||||
436 | =item whitelist_allows_relays user@example.com | ||||
437 | |||||
438 | Specify addresses which are in C<whitelist_from_rcvd> that sometimes | ||||
439 | send through a mail relay other than the listed ones. By default mail | ||||
440 | with a From address that is in C<whitelist_from_rcvd> that does not match | ||||
441 | the relay will trigger a forgery rule. Including the address in | ||||
442 | C<whitelist_allows_relay> prevents that. | ||||
443 | |||||
444 | Whitelist and blacklist addresses are now file-glob-style patterns, so | ||||
445 | C<friend@somewhere.com>, C<*@isp.com>, or C<*.domain.net> will all work. | ||||
446 | Specifically, C<*> and C<?> are allowed, but all other metacharacters | ||||
447 | are not. Regular expressions are not used for security reasons. | ||||
448 | Matching is case-insensitive. | ||||
449 | |||||
450 | Multiple addresses per line, separated by spaces, is OK. Multiple | ||||
451 | C<whitelist_allows_relays> lines are also OK. | ||||
452 | |||||
453 | The specified email address does not have to match exactly the address | ||||
454 | previously used in a whitelist_from_rcvd line as it is compared to the | ||||
455 | address in the header. | ||||
456 | |||||
457 | e.g. | ||||
458 | |||||
459 | whitelist_allows_relays joe@example.com fred@example.com | ||||
460 | whitelist_allows_relays *@example.com | ||||
461 | |||||
462 | =cut | ||||
463 | |||||
464 | 1 | 5µs | push (@cmds, { | ||
465 | setting => 'whitelist_allows_relays', | ||||
466 | type => $CONF_TYPE_ADDRLIST, | ||||
467 | }); | ||||
468 | |||||
469 | =item unwhitelist_from_rcvd user@example.com | ||||
470 | |||||
471 | Used to override a default whitelist_from_rcvd entry, so for example a | ||||
472 | distribution whitelist_from_rcvd can be overridden in a local.cf file, | ||||
473 | or an individual user can override a whitelist_from_rcvd entry in | ||||
474 | their own C<user_prefs> file. | ||||
475 | |||||
476 | The specified email address has to match exactly the address previously | ||||
477 | used in a whitelist_from_rcvd line. | ||||
478 | |||||
479 | e.g. | ||||
480 | |||||
481 | unwhitelist_from_rcvd joe@example.com fred@example.com | ||||
482 | unwhitelist_from_rcvd *@axkit.org | ||||
483 | |||||
484 | =cut | ||||
485 | |||||
486 | push (@cmds, { | ||||
487 | setting => 'unwhitelist_from_rcvd', | ||||
488 | type => $CONF_TYPE_ADDRLIST, | ||||
489 | code => sub { | ||||
490 | my ($self, $key, $value, $line) = @_; | ||||
491 | unless (defined $value && $value !~ /^$/) { | ||||
492 | return $MISSING_REQUIRED_VALUE; | ||||
493 | } | ||||
494 | unless ($value =~ /^(?:\S+(?:\s+\S+)*)$/) { | ||||
495 | return $INVALID_VALUE; | ||||
496 | } | ||||
497 | $self->{parser}->remove_from_addrlist_rcvd('whitelist_from_rcvd', | ||||
498 | split (/\s+/, $value)); | ||||
499 | $self->{parser}->remove_from_addrlist_rcvd('def_whitelist_from_rcvd', | ||||
500 | split (/\s+/, $value)); | ||||
501 | } | ||||
502 | 1 | 12µs | }); | ||
503 | |||||
504 | =item blacklist_from user@example.com | ||||
505 | |||||
506 | Used to specify addresses which send mail that is often tagged (incorrectly) as | ||||
507 | non-spam, but which the user doesn't want. Same format as C<whitelist_from>. | ||||
508 | |||||
509 | =cut | ||||
510 | |||||
511 | 1 | 5µs | push (@cmds, { | ||
512 | setting => 'blacklist_from', | ||||
513 | type => $CONF_TYPE_ADDRLIST, | ||||
514 | }); | ||||
515 | |||||
516 | =item unblacklist_from user@example.com | ||||
517 | |||||
518 | Used to override a default blacklist_from entry, so for example a | ||||
519 | distribution blacklist_from can be overridden in a local.cf file, or | ||||
520 | an individual user can override a blacklist_from entry in their own | ||||
521 | C<user_prefs> file. The specified email address has to match exactly | ||||
522 | the address previously used in a blacklist_from line. | ||||
523 | |||||
524 | |||||
525 | e.g. | ||||
526 | |||||
527 | unblacklist_from joe@example.com fred@example.com | ||||
528 | unblacklist_from *@spammer.com | ||||
529 | |||||
530 | =cut | ||||
531 | |||||
532 | |||||
533 | 1 | 7µs | push (@cmds, { | ||
534 | command => 'unblacklist_from', | ||||
535 | setting => 'blacklist_from', | ||||
536 | type => $CONF_TYPE_ADDRLIST, | ||||
537 | code => \&Mail::SpamAssassin::Conf::Parser::remove_addrlist_value | ||||
538 | }); | ||||
539 | |||||
540 | |||||
541 | =item whitelist_to user@example.com | ||||
542 | |||||
543 | If the given address appears as a recipient in the message headers | ||||
544 | (Resent-To, To, Cc, obvious envelope recipient, etc.) the mail will | ||||
545 | be whitelisted. Useful if you're deploying SpamAssassin system-wide, | ||||
546 | and don't want some users to have their mail filtered. Same format | ||||
547 | as C<whitelist_from>. | ||||
548 | |||||
549 | There are three levels of To-whitelisting, C<whitelist_to>, C<more_spam_to> | ||||
550 | and C<all_spam_to>. Users in the first level may still get some spammish | ||||
551 | mails blocked, but users in C<all_spam_to> should never get mail blocked. | ||||
552 | |||||
553 | The headers checked for whitelist addresses are as follows: if C<Resent-To> or | ||||
554 | C<Resent-Cc> are set, use those; otherwise check all addresses taken from the | ||||
555 | following set of headers: | ||||
556 | |||||
557 | To | ||||
558 | Cc | ||||
559 | Apparently-To | ||||
560 | Delivered-To | ||||
561 | Envelope-Recipients | ||||
562 | Apparently-Resent-To | ||||
563 | X-Envelope-To | ||||
564 | Envelope-To | ||||
565 | X-Delivered-To | ||||
566 | X-Original-To | ||||
567 | X-Rcpt-To | ||||
568 | X-Real-To | ||||
569 | |||||
570 | =item more_spam_to user@example.com | ||||
571 | |||||
572 | See above. | ||||
573 | |||||
574 | =item all_spam_to user@example.com | ||||
575 | |||||
576 | See above. | ||||
577 | |||||
578 | =cut | ||||
579 | |||||
580 | 1 | 5µs | push (@cmds, { | ||
581 | setting => 'whitelist_to', | ||||
582 | type => $CONF_TYPE_ADDRLIST, | ||||
583 | }); | ||||
584 | 1 | 4µs | push (@cmds, { | ||
585 | setting => 'more_spam_to', | ||||
586 | type => $CONF_TYPE_ADDRLIST, | ||||
587 | }); | ||||
588 | 1 | 4µs | push (@cmds, { | ||
589 | setting => 'all_spam_to', | ||||
590 | type => $CONF_TYPE_ADDRLIST, | ||||
591 | }); | ||||
592 | |||||
593 | =item blacklist_to user@example.com | ||||
594 | |||||
595 | If the given address appears as a recipient in the message headers | ||||
596 | (Resent-To, To, Cc, obvious envelope recipient, etc.) the mail will | ||||
597 | be blacklisted. Same format as C<blacklist_from>. | ||||
598 | |||||
599 | =cut | ||||
600 | |||||
601 | 1 | 4µs | push (@cmds, { | ||
602 | setting => 'blacklist_to', | ||||
603 | type => $CONF_TYPE_ADDRLIST, | ||||
604 | }); | ||||
605 | |||||
606 | =item whitelist_auth user@example.com | ||||
607 | |||||
608 | Used to specify addresses which send mail that is often tagged (incorrectly) as | ||||
609 | spam. This is different from C<whitelist_from> and C<whitelist_from_rcvd> in | ||||
610 | that it first verifies that the message was sent by an authorized sender for | ||||
611 | the address, before whitelisting. | ||||
612 | |||||
613 | Authorization is performed using one of the installed sender-authorization | ||||
614 | schemes: SPF (using C<Mail::SpamAssassin::Plugin::SPF>), or DKIM (using | ||||
615 | C<Mail::SpamAssassin::Plugin::DKIM>). Note that those plugins must be active, | ||||
616 | and working, for this to operate. | ||||
617 | |||||
618 | Using C<whitelist_auth> is roughly equivalent to specifying duplicate | ||||
619 | C<whitelist_from_spf>, C<whitelist_from_dk>, and C<whitelist_from_dkim> lines | ||||
620 | for each of the addresses specified. | ||||
621 | |||||
622 | e.g. | ||||
623 | |||||
624 | whitelist_auth joe@example.com fred@example.com | ||||
625 | whitelist_auth *@example.com | ||||
626 | |||||
627 | =item def_whitelist_auth user@example.com | ||||
628 | |||||
629 | Same as C<whitelist_auth>, but used for the default whitelist entries | ||||
630 | in the SpamAssassin distribution. The whitelist score is lower, because | ||||
631 | these are often targets for spammer spoofing. | ||||
632 | |||||
633 | =cut | ||||
634 | |||||
635 | 1 | 4µs | push (@cmds, { | ||
636 | setting => 'whitelist_auth', | ||||
637 | type => $CONF_TYPE_ADDRLIST, | ||||
638 | }); | ||||
639 | |||||
640 | 1 | 4µs | push (@cmds, { | ||
641 | setting => 'def_whitelist_auth', | ||||
642 | type => $CONF_TYPE_ADDRLIST, | ||||
643 | }); | ||||
644 | |||||
645 | =item unwhitelist_auth user@example.com | ||||
646 | |||||
647 | Used to override a C<whitelist_auth> entry. The specified email address has to | ||||
648 | match exactly the address previously used in a C<whitelist_auth> line. | ||||
649 | |||||
650 | e.g. | ||||
651 | |||||
652 | unwhitelist_auth joe@example.com fred@example.com | ||||
653 | unwhitelist_auth *@example.com | ||||
654 | |||||
655 | =cut | ||||
656 | |||||
657 | 1 | 6µs | push (@cmds, { | ||
658 | command => 'unwhitelist_auth', | ||||
659 | setting => 'whitelist_auth', | ||||
660 | type => $CONF_TYPE_ADDRLIST, | ||||
661 | code => \&Mail::SpamAssassin::Conf::Parser::remove_addrlist_value | ||||
662 | }); | ||||
663 | |||||
664 | |||||
665 | =item enlist_uri_host (listname) host ... | ||||
666 | |||||
667 | Adds one or more host names or domain names to a named list of URI domains. | ||||
668 | The named list can then be consulted through a check_uri_host_listed() | ||||
669 | eval rule implemented by the WLBLEval plugin, which takes the list name as | ||||
670 | an argument. Parenthesis around a list name are literal - a required syntax. | ||||
671 | |||||
672 | Host names may optionally be prefixed by an exclamantion mark '!', which | ||||
673 | produces false as a result if this entry matches. This makes it easier | ||||
674 | to exclude some subdomains when their superdomain is listed, for example: | ||||
675 | |||||
676 | enlist_uri_host (MYLIST) !sub1.example.com !sub2.example.com example.com | ||||
677 | |||||
678 | No wildcards are supported, but subdomains do match implicitly. Lists | ||||
679 | are independent. Search for each named list starts by looking up the | ||||
680 | full hostname first, then leading fields are progressively stripped off | ||||
681 | (e.g.: sub.example.com, example.com, com) until a match is found or we run | ||||
682 | out of fields. The first matching entry (the most specific) determines if a | ||||
683 | lookup yielded a true (no '!' prefix) or a false (with a '!' prefix) result. | ||||
684 | |||||
685 | If an URL found in a message contains an IP address in place of a host name, | ||||
686 | the given list must specify the exact same IP address (instead of a host name) | ||||
687 | in order to match. | ||||
688 | |||||
689 | Use the delist_uri_host directive to neutralize previous enlist_uri_host | ||||
690 | settings. | ||||
691 | |||||
692 | Enlisting to lists named 'BLACK' and 'WHITE' have their shorthand directives | ||||
693 | blacklist_uri_host and whitelist_uri_host and corresponding default rules, | ||||
694 | but the names 'BLACK' and 'WHITE' are otherwise not special or reserved. | ||||
695 | |||||
696 | =cut | ||||
697 | |||||
698 | push (@cmds, { | ||||
699 | command => 'enlist_uri_host', | ||||
700 | setting => 'uri_host_lists', | ||||
701 | type => $CONF_TYPE_ADDRLIST, | ||||
702 | code => sub { | ||||
703 | my($conf, $key, $value, $line) = @_; | ||||
704 | local($1,$2); | ||||
705 | if ($value !~ /^ \( (.*?) \) \s+ (.*) \z/sx) { | ||||
706 | return $MISSING_REQUIRED_VALUE; | ||||
707 | } | ||||
708 | my $listname = $1; # corresponds to arg in check_uri_host_in_wblist() | ||||
709 | # note: must not factor out dereferencing, as otherwise | ||||
710 | # subhashes would spring up in a copy and be lost | ||||
711 | foreach my $host ( split(' ', lc $2) ) { | ||||
712 | my $v = $host =~ s/^!// ? 0 : 1; | ||||
713 | $conf->{uri_host_lists}{$listname}{$host} = $v; | ||||
714 | } | ||||
715 | } | ||||
716 | 1 | 12µs | }); | ||
717 | |||||
718 | =item delist_uri_host [ (listname) ] host ... | ||||
719 | |||||
720 | Removes one or more specified host names from a named list of URI domains. | ||||
721 | Removing an unlisted name is ignored (is not an error). Listname is optional, | ||||
722 | if specified then just the named list is affected, otherwise hosts are | ||||
723 | removed from all URI host lists created so far. Parenthesis around a list | ||||
724 | name are a required syntax. | ||||
725 | |||||
726 | Note that directives in configuration files are processed in sequence, | ||||
727 | the delist_uri_host only applies to previously listed entries and has | ||||
728 | no effect on enlisted entries in yet-to-be-processed directives. | ||||
729 | |||||
730 | For convenience (similarity to the enlist_uri_host directive) hostnames | ||||
731 | may be prefixed by a an exclamation mark, which is stripped off from each | ||||
732 | name and has no meaning here. | ||||
733 | |||||
734 | =cut | ||||
735 | |||||
736 | push (@cmds, { | ||||
737 | command => 'delist_uri_host', | ||||
738 | setting => 'uri_host_lists', | ||||
739 | type => $CONF_TYPE_ADDRLIST, | ||||
740 | code => sub { | ||||
741 | my($conf, $key, $value, $line) = @_; | ||||
742 | local($1,$2); | ||||
743 | if ($value !~ /^ (?: \( (.*?) \) \s+ )? (.*) \z/sx) { | ||||
744 | return $MISSING_REQUIRED_VALUE; | ||||
745 | } | ||||
746 | my @listnames = defined $1 ? $1 : keys %{$conf->{uri_host_lists}}; | ||||
747 | my @args = split(' ', lc $2); | ||||
748 | foreach my $listname (@listnames) { | ||||
749 | foreach my $host (@args) { | ||||
750 | my $v = $host =~ s/^!// ? 0 : 1; | ||||
751 | delete $conf->{uri_host_lists}{$listname}{$host}; | ||||
752 | } | ||||
753 | } | ||||
754 | } | ||||
755 | 1 | 13µs | }); | ||
756 | |||||
757 | =item blacklist_uri_host host-or-domain ... | ||||
758 | |||||
759 | Is a shorthand for a directive: enlist_uri_host (BLACK) host ... | ||||
760 | |||||
761 | Please see directives enlist_uri_host and delist_uri_host for details. | ||||
762 | |||||
763 | =cut | ||||
764 | |||||
765 | push (@cmds, { | ||||
766 | command => 'blacklist_uri_host', | ||||
767 | setting => 'uri_host_lists', | ||||
768 | type => $CONF_TYPE_ADDRLIST, | ||||
769 | code => sub { | ||||
770 | my($conf, $key, $value, $line) = @_; | ||||
771 | foreach my $host ( split(' ', lc $value) ) { | ||||
772 | my $v = $host =~ s/^!// ? 0 : 1; | ||||
773 | $conf->{uri_host_lists}{'BLACK'}{$host} = $v; | ||||
774 | } | ||||
775 | } | ||||
776 | 1 | 11µs | }); | ||
777 | |||||
778 | =item whitelist_uri_host host-or-domain ... | ||||
779 | |||||
780 | Is a shorthand for a directive: enlist_uri_host (BLACK) host ... | ||||
781 | |||||
782 | Please see directives enlist_uri_host and delist_uri_host for details. | ||||
783 | |||||
784 | =cut | ||||
785 | |||||
786 | push (@cmds, { | ||||
787 | command => 'whitelist_uri_host', | ||||
788 | setting => 'uri_host_lists', | ||||
789 | type => $CONF_TYPE_ADDRLIST, | ||||
790 | code => sub { | ||||
791 | my($conf, $key, $value, $line) = @_; | ||||
792 | foreach my $host ( split(' ', lc $value) ) { | ||||
793 | my $v = $host =~ s/^!// ? 0 : 1; | ||||
794 | $conf->{uri_host_lists}{'WHITE'}{$host} = $v; | ||||
795 | } | ||||
796 | } | ||||
797 | 1 | 10µs | }); | ||
798 | |||||
799 | =back | ||||
800 | |||||
801 | =head2 BASIC MESSAGE TAGGING OPTIONS | ||||
802 | |||||
803 | =over 4 | ||||
804 | |||||
805 | =item rewrite_header { subject | from | to } STRING | ||||
806 | |||||
807 | By default, suspected spam messages will not have the C<Subject>, | ||||
808 | C<From> or C<To> lines tagged to indicate spam. By setting this option, | ||||
809 | the header will be tagged with C<STRING> to indicate that a message is | ||||
810 | spam. For the From or To headers, this will take the form of an RFC 2822 | ||||
811 | comment following the address in parantheses. For the Subject header, | ||||
812 | this will be prepended to the original subject. Note that you should | ||||
813 | only use the _REQD_ and _SCORE_ tags when rewriting the Subject header | ||||
814 | if C<report_safe> is 0. Otherwise, you may not be able to remove | ||||
815 | the SpamAssassin markup via the normal methods. More information | ||||
816 | about tags is explained below in the B<TEMPLATE TAGS> section. | ||||
817 | |||||
818 | Parentheses are not permitted in STRING if rewriting the From or To headers. | ||||
819 | (They will be converted to square brackets.) | ||||
820 | |||||
821 | If C<rewrite_header subject> is used, but the message being rewritten | ||||
822 | does not already contain a C<Subject> header, one will be created. | ||||
823 | |||||
824 | A null value for C<STRING> will remove any existing rewrite for the specified | ||||
825 | header. | ||||
826 | |||||
827 | =cut | ||||
828 | |||||
829 | push (@cmds, { | ||||
830 | setting => 'rewrite_header', | ||||
831 | type => $CONF_TYPE_HASH_KEY_VALUE, | ||||
832 | code => sub { | ||||
833 | my ($self, $key, $value, $line) = @_; | ||||
834 | my($hdr, $string) = split(/\s+/, $value, 2); | ||||
835 | $hdr = ucfirst(lc($hdr)); | ||||
836 | |||||
837 | if ($hdr =~ /^$/) { | ||||
838 | return $MISSING_REQUIRED_VALUE; | ||||
839 | } | ||||
840 | # We only deal with From, Subject, and To ... | ||||
841 | elsif ($hdr =~ /^(?:From|Subject|To)$/) { | ||||
842 | unless (defined $string && $string =~ /\S/) { | ||||
843 | delete $self->{rewrite_header}->{$hdr}; | ||||
844 | return; | ||||
845 | } | ||||
846 | |||||
847 | if ($hdr ne 'Subject') { | ||||
848 | $string =~ tr/()/[]/; | ||||
849 | } | ||||
850 | $self->{rewrite_header}->{$hdr} = $string; | ||||
851 | return; | ||||
852 | } | ||||
853 | else { | ||||
854 | # if we get here, note the issue, then we'll fail through for an error. | ||||
855 | info("config: rewrite_header: ignoring $hdr, not From, Subject, or To"); | ||||
856 | return $INVALID_VALUE; | ||||
857 | } | ||||
858 | } | ||||
859 | 1 | 10µs | }); | ||
860 | |||||
861 | =item add_header { spam | ham | all } header_name string | ||||
862 | |||||
863 | Customized headers can be added to the specified type of messages (spam, | ||||
864 | ham, or "all" to add to either). All headers begin with C<X-Spam-> | ||||
865 | (so a C<header_name> Foo will generate a header called X-Spam-Foo). | ||||
866 | header_name is restricted to the character set [A-Za-z0-9_-]. | ||||
867 | |||||
868 | The order of C<add_header> configuration options is preserved, inserted | ||||
869 | headers will follow this order of declarations. When combining C<add_header> | ||||
870 | with C<clear_headers> and C<remove_header>, keep in mind that C<add_header> | ||||
871 | appends a new header to the current list, after first removing any existing | ||||
872 | header fields of the same name. Note also that C<add_header>, C<clear_headers> | ||||
873 | and C<remove_header> may appear in multiple .cf files, which are interpreted | ||||
874 | in alphabetic order. | ||||
875 | |||||
876 | C<string> can contain tags as explained below in the B<TEMPLATE TAGS> section. | ||||
877 | You can also use C<\n> and C<\t> in the header to add newlines and tabulators | ||||
878 | as desired. A backslash has to be written as \\, any other escaped chars will | ||||
879 | be silently removed. | ||||
880 | |||||
881 | All headers will be folded if fold_headers is set to C<1>. Note: Manually | ||||
882 | adding newlines via C<\n> disables any further automatic wrapping (ie: | ||||
883 | long header lines are possible). The lines will still be properly folded | ||||
884 | (marked as continuing) though. | ||||
885 | |||||
886 | You can customize existing headers with B<add_header> (only the specified | ||||
887 | subset of messages will be changed). | ||||
888 | |||||
889 | See also C<clear_headers> and C<remove_header> for removing headers. | ||||
890 | |||||
891 | Here are some examples (these are the defaults, note that Checker-Version can | ||||
892 | not be changed or removed): | ||||
893 | |||||
894 | add_header spam Flag _YESNOCAPS_ | ||||
895 | add_header all Status _YESNO_, score=_SCORE_ required=_REQD_ tests=_TESTS_ autolearn=_AUTOLEARN_ version=_VERSION_ | ||||
896 | add_header all Level _STARS(*)_ | ||||
897 | add_header all Checker-Version SpamAssassin _VERSION_ (_SUBVERSION_) on _HOSTNAME_ | ||||
898 | |||||
899 | =cut | ||||
900 | |||||
901 | push (@cmds, { | ||||
902 | setting => 'add_header', | ||||
903 | # spent 865µs (743+122) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:935] which was called 5 times, avg 173µs/call:
# 5 times (743µs+122µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 173µs/call | ||||
904 | 5 | 25µs | my ($self, $key, $value, $line) = @_; | ||
905 | 5 | 27µs | local ($1,$2,$3); | ||
906 | 5 | 112µs | 5 | 72µs | if ($value !~ /^(ham|spam|all)\s+([A-Za-z0-9_-]+)\s+(.*?)\s*$/) { # spent 72µs making 5 calls to Mail::SpamAssassin::Conf::CORE:match, avg 14µs/call |
907 | return $INVALID_VALUE; | ||||
908 | } | ||||
909 | |||||
910 | 5 | 28µs | my ($type, $name, $hline) = ($1, $2, $3); | ||
911 | 5 | 51µs | 5 | 15µs | if ($hline =~ /^"(.*)"$/) { # spent 15µs making 5 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
912 | 1 | 4µs | $hline = $1; | ||
913 | } | ||||
914 | 5 | 33µs | my @line = split( | ||
915 | /\\\\/, # split at double backslashes, | ||||
916 | $hline."\n" # newline needed to make trailing backslashes work | ||||
917 | ); | ||||
918 | 5 | 21µs | foreach (@line) { | ||
919 | 5 | 49µs | 5 | 13µs | s/\\t/\t/g; # expand tabs # spent 13µs making 5 calls to Mail::SpamAssassin::Conf::CORE:subst, avg 3µs/call |
920 | 5 | 40µs | 5 | 11µs | s/\\n/\n/g; # expand newlines # spent 11µs making 5 calls to Mail::SpamAssassin::Conf::CORE:subst, avg 2µs/call |
921 | 5 | 51µs | 5 | 12µs | s/\\.//g; # purge all other escapes # spent 12µs making 5 calls to Mail::SpamAssassin::Conf::CORE:subst, avg 2µs/call |
922 | }; | ||||
923 | 5 | 25µs | $hline = join("\\", @line); | ||
924 | 5 | 16µs | chop($hline); # remove dummy newline again | ||
925 | 5 | 21µs | if (($type eq "ham") || ($type eq "all")) { | ||
926 | $self->{headers_ham} = | ||||
927 | 15 | 96µs | [ grep { lc($_->[0]) ne lc($name) } @{$self->{headers_ham}} ]; | ||
928 | 8 | 32µs | push(@{$self->{headers_ham}}, [$name, $hline]); | ||
929 | } | ||||
930 | 5 | 74µs | if (($type eq "spam") || ($type eq "all")) { | ||
931 | $self->{headers_spam} = | ||||
932 | 21 | 115µs | [ grep { lc($_->[0]) ne lc($name) } @{$self->{headers_spam}} ]; | ||
933 | 10 | 45µs | push(@{$self->{headers_spam}}, [$name, $hline]); | ||
934 | } | ||||
935 | } | ||||
936 | 1 | 11µs | }); | ||
937 | |||||
938 | =item remove_header { spam | ham | all } header_name | ||||
939 | |||||
940 | Headers can be removed from the specified type of messages (spam, ham, | ||||
941 | or "all" to remove from either). All headers begin with C<X-Spam-> | ||||
942 | (so C<header_name> will be appended to C<X-Spam->). | ||||
943 | |||||
944 | See also C<clear_headers> for removing all the headers at once. | ||||
945 | |||||
946 | Note that B<X-Spam-Checker-Version> is not removable because the version | ||||
947 | information is needed by mail administrators and developers to debug | ||||
948 | problems. Without at least one header, it might not even be possible to | ||||
949 | determine that SpamAssassin is running. | ||||
950 | |||||
951 | =cut | ||||
952 | |||||
953 | push (@cmds, { | ||||
954 | setting => 'remove_header', | ||||
955 | code => sub { | ||||
956 | my ($self, $key, $value, $line) = @_; | ||||
957 | local ($1,$2); | ||||
958 | if ($value !~ /^(ham|spam|all)\s+([A-Za-z0-9_-]+)\s*$/) { | ||||
959 | return $INVALID_VALUE; | ||||
960 | } | ||||
961 | |||||
962 | my ($type, $name) = ($1, $2); | ||||
963 | return if ( $name eq "Checker-Version" ); | ||||
964 | |||||
965 | $name = lc($name); | ||||
966 | if (($type eq "ham") || ($type eq "all")) { | ||||
967 | $self->{headers_ham} = | ||||
968 | [ grep { lc($_->[0]) ne $name } @{$self->{headers_ham}} ]; | ||||
969 | } | ||||
970 | if (($type eq "spam") || ($type eq "all")) { | ||||
971 | $self->{headers_spam} = | ||||
972 | [ grep { lc($_->[0]) ne $name } @{$self->{headers_spam}} ]; | ||||
973 | } | ||||
974 | } | ||||
975 | 1 | 10µs | }); | ||
976 | |||||
977 | =item clear_headers | ||||
978 | |||||
979 | Clear the list of headers to be added to messages. You may use this | ||||
980 | before any B<add_header> options to prevent the default headers from being | ||||
981 | added to the message. | ||||
982 | |||||
983 | C<add_header>, C<clear_headers> and C<remove_header> may appear in multiple | ||||
984 | .cf files, which are interpreted in alphabetic order, so C<clear_headers> | ||||
985 | in a later file will remove all added headers from previously interpreted | ||||
986 | configuration files, which may or may not be desired. | ||||
987 | |||||
988 | Note that B<X-Spam-Checker-Version> is not removable because the version | ||||
989 | information is needed by mail administrators and developers to debug | ||||
990 | problems. Without at least one header, it might not even be possible to | ||||
991 | determine that SpamAssassin is running. | ||||
992 | |||||
993 | =cut | ||||
994 | |||||
995 | push (@cmds, { | ||||
996 | setting => 'clear_headers', | ||||
997 | type => $CONF_TYPE_NOARGS, | ||||
998 | # spent 51µs within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1007] which was called:
# once (51µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm | ||||
999 | 1 | 5µs | my ($self, $key, $value, $line) = @_; | ||
1000 | 1 | 4µs | unless (!defined $value || $value eq '') { | ||
1001 | return $INVALID_VALUE; | ||||
1002 | } | ||||
1003 | 1 | 7µs | my @h = grep { lc($_->[0]) eq "checker-version" } | ||
1004 | 2 | 17µs | @{$self->{headers_ham}}; | ||
1005 | 1 | 6µs | $self->{headers_ham} = !@h ? [] : [ $h[0] ]; | ||
1006 | 1 | 15µs | $self->{headers_spam} = !@h ? [] : [ $h[0] ]; | ||
1007 | } | ||||
1008 | 1 | 10µs | }); | ||
1009 | |||||
1010 | =item report_safe ( 0 | 1 | 2 ) (default: 1) | ||||
1011 | |||||
1012 | if this option is set to 1, if an incoming message is tagged as spam, | ||||
1013 | instead of modifying the original message, SpamAssassin will create a | ||||
1014 | new report message and attach the original message as a message/rfc822 | ||||
1015 | MIME part (ensuring the original message is completely preserved, not | ||||
1016 | easily opened, and easier to recover). | ||||
1017 | |||||
1018 | If this option is set to 2, then original messages will be attached with | ||||
1019 | a content type of text/plain instead of message/rfc822. This setting | ||||
1020 | may be required for safety reasons on certain broken mail clients that | ||||
1021 | automatically load attachments without any action by the user. This | ||||
1022 | setting may also make it somewhat more difficult to extract or view the | ||||
1023 | original message. | ||||
1024 | |||||
1025 | If this option is set to 0, incoming spam is only modified by adding | ||||
1026 | some C<X-Spam-> headers and no changes will be made to the body. In | ||||
1027 | addition, a header named B<X-Spam-Report> will be added to spam. You | ||||
1028 | can use the B<remove_header> option to remove that header after setting | ||||
1029 | B<report_safe> to 0. | ||||
1030 | |||||
1031 | See B<report_safe_copy_headers> if you want to copy headers from | ||||
1032 | the original mail into tagged messages. | ||||
1033 | |||||
1034 | =cut | ||||
1035 | |||||
1036 | push (@cmds, { | ||||
1037 | setting => 'report_safe', | ||||
1038 | default => 1, | ||||
1039 | type => $CONF_TYPE_NUMERIC, | ||||
1040 | # spent 41µs (34+7) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1054] which was called:
# once (34µs+7µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm | ||||
1041 | 1 | 6µs | my ($self, $key, $value, $line) = @_; | ||
1042 | 1 | 20µs | 1 | 8µs | if ($value eq '') { # spent 8µs making 1 call to Mail::SpamAssassin::Conf::CORE:match |
1043 | return $MISSING_REQUIRED_VALUE; | ||||
1044 | } | ||||
1045 | elsif ($value !~ /^[012]$/) { | ||||
1046 | return $INVALID_VALUE; | ||||
1047 | } | ||||
1048 | |||||
1049 | 1 | 6µs | $self->{report_safe} = $value+0; | ||
1050 | 1 | 12µs | if (! $self->{report_safe} && | ||
1051 | ! (grep { lc($_->[0]) eq "report" } @{$self->{headers_spam}}) ) { | ||||
1052 | push(@{$self->{headers_spam}}, ["Report", "_REPORT_"]); | ||||
1053 | } | ||||
1054 | } | ||||
1055 | 1 | 23µs | }); | ||
1056 | |||||
1057 | =back | ||||
1058 | |||||
1059 | =head2 LANGUAGE OPTIONS | ||||
1060 | |||||
1061 | =over 4 | ||||
1062 | |||||
1063 | =item ok_locales xx [ yy zz ... ] (default: all) | ||||
1064 | |||||
1065 | This option is used to specify which locales are considered OK for | ||||
1066 | incoming mail. Mail using the B<character sets> that are allowed by | ||||
1067 | this option will not be marked as possibly being spam in a foreign | ||||
1068 | language. | ||||
1069 | |||||
1070 | If you receive lots of spam in foreign languages, and never get any non-spam in | ||||
1071 | these languages, this may help. Note that all ISO-8859-* character sets, and | ||||
1072 | Windows code page character sets, are always permitted by default. | ||||
1073 | |||||
1074 | Set this to C<all> to allow all character sets. This is the default. | ||||
1075 | |||||
1076 | The rules C<CHARSET_FARAWAY>, C<CHARSET_FARAWAY_BODY>, and | ||||
1077 | C<CHARSET_FARAWAY_HEADERS> are triggered based on how this is set. | ||||
1078 | |||||
1079 | Examples: | ||||
1080 | |||||
1081 | ok_locales all (allow all locales) | ||||
1082 | ok_locales en (only allow English) | ||||
1083 | ok_locales en ja zh (allow English, Japanese, and Chinese) | ||||
1084 | |||||
1085 | Note: if there are multiple ok_locales lines, only the last one is used. | ||||
1086 | |||||
1087 | Select the locales to allow from the list below: | ||||
1088 | |||||
1089 | =over 4 | ||||
1090 | |||||
1091 | =item en - Western character sets in general | ||||
1092 | |||||
1093 | =item ja - Japanese character sets | ||||
1094 | |||||
1095 | =item ko - Korean character sets | ||||
1096 | |||||
1097 | =item ru - Cyrillic character sets | ||||
1098 | |||||
1099 | =item th - Thai character sets | ||||
1100 | |||||
1101 | =item zh - Chinese (both simplified and traditional) character sets | ||||
1102 | |||||
1103 | =back | ||||
1104 | |||||
1105 | =cut | ||||
1106 | |||||
1107 | 1 | 5µs | push (@cmds, { | ||
1108 | setting => 'ok_locales', | ||||
1109 | default => 'all', | ||||
1110 | type => $CONF_TYPE_STRING, | ||||
1111 | }); | ||||
1112 | |||||
1113 | =item normalize_charset ( 0 | 1) (default: 0) | ||||
1114 | |||||
1115 | Whether to decode non- UTF-8 and non-ASCII textual parts and recode them | ||||
1116 | to UTF-8 before the text is given over to rules processing. The character | ||||
1117 | set used for attempted decoding is primarily based on a declared character | ||||
1118 | set in a Content-Type header, but if the decoding attempt fails a module | ||||
1119 | Encode::Detect::Detector is consulted (if available) to provide a guess | ||||
1120 | based on the actual text, and decoding is re-attempted. Even if the option | ||||
1121 | is enabled no unnecessary decoding and re-encoding work is done when | ||||
1122 | possible (like with an all-ASCII text with a US-ASCII or extended ASCII | ||||
1123 | character set declaration, e.g. UTF-8 or ISO-8859-nn or Windows-nnnn). | ||||
1124 | |||||
1125 | Unicode support in old versions of perl or in a core module Encode is likely | ||||
1126 | to be buggy in places, so if the normalize_charset function is enabled | ||||
1127 | it is advised to stick to more recent versions of perl (preferably 5.12 | ||||
1128 | or later). The module Encode::Detect::Detector is optional, when necessary | ||||
1129 | it will be used if it is available. | ||||
1130 | |||||
1131 | =cut | ||||
1132 | |||||
1133 | push (@cmds, { | ||||
1134 | setting => 'normalize_charset', | ||||
1135 | default => 0, | ||||
1136 | type => $CONF_TYPE_BOOL, | ||||
1137 | code => sub { | ||||
1138 | my ($self, $key, $value, $line) = @_; | ||||
1139 | unless (defined $value && $value !~ /^$/) { | ||||
1140 | return $MISSING_REQUIRED_VALUE; | ||||
1141 | } | ||||
1142 | if (lc $value eq 'yes' || $value eq '1') { $value = 1 } | ||||
1143 | elsif (lc $value eq 'no' || $value eq '0') { $value = 0 } | ||||
1144 | else { return $INVALID_VALUE } | ||||
1145 | |||||
1146 | $self->{normalize_charset} = $value; | ||||
1147 | |||||
1148 | unless ($] > 5.008004) { | ||||
1149 | $self->{parser}->lint_warn("config: normalize_charset requires Perl 5.8.5 or later"); | ||||
1150 | $self->{normalize_charset} = 0; | ||||
1151 | return $INVALID_VALUE; | ||||
1152 | } | ||||
1153 | require HTML::Parser; | ||||
1154 | #changed to eval to use VERSION so that this version was not incorrectly parsed for CPAN | ||||
1155 | unless ( eval { HTML::Parser->VERSION(3.46) } ) { | ||||
1156 | $self->{parser}->lint_warn("config: normalize_charset requires HTML::Parser 3.46 or later"); | ||||
1157 | $self->{normalize_charset} = 0; | ||||
1158 | return $INVALID_VALUE; | ||||
1159 | } | ||||
1160 | unless (eval 'require Encode') { | ||||
1161 | $self->{parser}->lint_warn("config: normalize_charset requires Encode"); | ||||
1162 | $self->{normalize_charset} = 0; | ||||
1163 | return $INVALID_VALUE; | ||||
1164 | } | ||||
1165 | } | ||||
1166 | 1 | 13µs | }); | ||
1167 | |||||
1168 | |||||
1169 | =back | ||||
1170 | |||||
1171 | =head2 NETWORK TEST OPTIONS | ||||
1172 | |||||
1173 | =over 4 | ||||
1174 | |||||
1175 | =item trusted_networks IPaddress[/masklen] ... (default: none) | ||||
1176 | |||||
1177 | What networks or hosts are 'trusted' in your setup. B<Trusted> in this case | ||||
1178 | means that relay hosts on these networks are considered to not be potentially | ||||
1179 | operated by spammers, open relays, or open proxies. A trusted host could | ||||
1180 | conceivably relay spam, but will not originate it, and will not forge header | ||||
1181 | data. DNS blacklist checks will never query for hosts on these networks. | ||||
1182 | |||||
1183 | See C<http://wiki.apache.org/spamassassin/TrustPath> for more information. | ||||
1184 | |||||
1185 | MXes for your domain(s) and internal relays should B<also> be specified using | ||||
1186 | the C<internal_networks> setting. When there are 'trusted' hosts that | ||||
1187 | are not MXes or internal relays for your domain(s) they should B<only> be | ||||
1188 | specified in C<trusted_networks>. | ||||
1189 | |||||
1190 | The C<IPaddress> can be an IPv4 address (in a dot-quad form), or an IPv6 | ||||
1191 | address optionally enclosed in square brackets. Scoped link-local IPv6 | ||||
1192 | addresses are syntactically recognized but the interface scope is currently | ||||
1193 | ignored (e.g. [fe80::1234%eth0] ) and should be avoided. | ||||
1194 | |||||
1195 | If a C</masklen> is specified, it is considered a CIDR-style 'netmask' length, | ||||
1196 | specified in bits. If it is not specified, but less than 4 octets of an IPv4 | ||||
1197 | address are specified with a trailing dot, an implied netmask length covers | ||||
1198 | all addresses in remaining octets (i.e. implied masklen is /8 or /16 or /24). | ||||
1199 | If masklen is not specified, and there is not trailing dot, then just a single | ||||
1200 | IP address specified is used, as if the masklen were C</32> with an IPv4 | ||||
1201 | address, or C</128> in case of an IPv6 address. | ||||
1202 | |||||
1203 | If a network or host address is prefaced by a C<!> the matching network or | ||||
1204 | host will be excluded from the list even if a less specific (shorter netmask | ||||
1205 | length) subnet is later specified in the list. This allows a subset of | ||||
1206 | a wider network to be exempt. In case of specifying overlapping subnets, | ||||
1207 | specify more specific subnets first (tighter matching, i.e. with a longer | ||||
1208 | netmask length), followed by less specific (shorter netmask length) subnets | ||||
1209 | to get predictable results regarless of the search algorithm used - when | ||||
1210 | Net::Patricia module is installed the search finds the tightest matching | ||||
1211 | entry in the list, while a sequential search as used in absence of the | ||||
1212 | module Net::Patricia will find the first matching entry in the list. | ||||
1213 | |||||
1214 | Note: 127.0.0.0/8 and ::1 are always included in trusted_networks, regardless | ||||
1215 | of your config. | ||||
1216 | |||||
1217 | Examples: | ||||
1218 | |||||
1219 | trusted_networks 192.168.0.0/16 # all in 192.168.*.* | ||||
1220 | trusted_networks 192.168. # all in 192.168.*.* | ||||
1221 | trusted_networks 212.17.35.15 # just that host | ||||
1222 | trusted_networks !10.0.1.5 10.0.1/24 # all in 10.0.1.* but not 10.0.1.5 | ||||
1223 | trusted_networks 2001:db8:1::1 !2001:db8:1::/64 2001:db8::/32 | ||||
1224 | # 2001:db8::/32 and 2001:db8:1::1/128, except the rest of 2001:db8:1::/64 | ||||
1225 | |||||
1226 | This operates additively, so a C<trusted_networks> line after another one | ||||
1227 | will append new entries to the list of trusted networks. To clear out the | ||||
1228 | existing entries, use C<clear_trusted_networks>. | ||||
1229 | |||||
1230 | If C<trusted_networks> is not set and C<internal_networks> is, the value | ||||
1231 | of C<internal_networks> will be used for this parameter. | ||||
1232 | |||||
1233 | If neither C<trusted_networks> or C<internal_networks> is set, a basic | ||||
1234 | inference algorithm is applied. This works as follows: | ||||
1235 | |||||
1236 | =over 4 | ||||
1237 | |||||
1238 | =item * | ||||
1239 | |||||
1240 | If the 'from' host has an IP address in a private (RFC 1918) network range, | ||||
1241 | then it's trusted | ||||
1242 | |||||
1243 | =item * | ||||
1244 | |||||
1245 | If there are authentication tokens in the received header, and | ||||
1246 | the previous host was trusted, then this host is also trusted | ||||
1247 | |||||
1248 | =item * | ||||
1249 | |||||
1250 | Otherwise this host, and all further hosts, are consider untrusted. | ||||
1251 | |||||
1252 | =back | ||||
1253 | |||||
1254 | =cut | ||||
1255 | |||||
1256 | 1 | 4µs | push (@cmds, { | ||
1257 | setting => 'trusted_networks', | ||||
1258 | type => $CONF_TYPE_IPADDRLIST, | ||||
1259 | }); | ||||
1260 | |||||
1261 | =item clear_trusted_networks | ||||
1262 | |||||
1263 | Empty the list of trusted networks. | ||||
1264 | |||||
1265 | =cut | ||||
1266 | |||||
1267 | push (@cmds, { | ||||
1268 | setting => 'clear_trusted_networks', | ||||
1269 | type => $CONF_TYPE_NOARGS, | ||||
1270 | code => sub { | ||||
1271 | my ($self, $key, $value, $line) = @_; | ||||
1272 | unless (!defined $value || $value eq '') { | ||||
1273 | return $INVALID_VALUE; | ||||
1274 | } | ||||
1275 | $self->{trusted_networks} = $self->new_netset('trusted_networks',1); | ||||
1276 | $self->{trusted_networks_configured} = 0; | ||||
1277 | } | ||||
1278 | 1 | 10µs | }); | ||
1279 | |||||
1280 | =item internal_networks IPaddress[/masklen] ... (default: none) | ||||
1281 | |||||
1282 | What networks or hosts are 'internal' in your setup. B<Internal> means | ||||
1283 | that relay hosts on these networks are considered to be MXes for your | ||||
1284 | domain(s), or internal relays. This uses the same syntax as | ||||
1285 | C<trusted_networks>, above - see there for details. | ||||
1286 | |||||
1287 | This value is used when checking 'dial-up' or dynamic IP address | ||||
1288 | blocklists, in order to detect direct-to-MX spamming. | ||||
1289 | |||||
1290 | Trusted relays that accept mail directly from dial-up connections | ||||
1291 | (i.e. are also performing a role of mail submission agents - MSA) | ||||
1292 | should not be listed in C<internal_networks>. List them only in | ||||
1293 | C<trusted_networks>. | ||||
1294 | |||||
1295 | If C<trusted_networks> is set and C<internal_networks> is not, the value | ||||
1296 | of C<trusted_networks> will be used for this parameter. | ||||
1297 | |||||
1298 | If neither C<trusted_networks> nor C<internal_networks> is set, no addresses | ||||
1299 | will be considered local; in other words, any relays past the machine where | ||||
1300 | SpamAssassin is running will be considered external. | ||||
1301 | |||||
1302 | Every entry in C<internal_networks> must appear in C<trusted_networks>; in | ||||
1303 | other words, C<internal_networks> is always a subset of the trusted set. | ||||
1304 | |||||
1305 | Note: 127/8 and ::1 are always included in internal_networks, regardless of | ||||
1306 | your config. | ||||
1307 | |||||
1308 | =cut | ||||
1309 | |||||
1310 | 1 | 4µs | push (@cmds, { | ||
1311 | setting => 'internal_networks', | ||||
1312 | type => $CONF_TYPE_IPADDRLIST, | ||||
1313 | }); | ||||
1314 | |||||
1315 | =item clear_internal_networks | ||||
1316 | |||||
1317 | Empty the list of internal networks. | ||||
1318 | |||||
1319 | =cut | ||||
1320 | |||||
1321 | push (@cmds, { | ||||
1322 | setting => 'clear_internal_networks', | ||||
1323 | type => $CONF_TYPE_NOARGS, | ||||
1324 | code => sub { | ||||
1325 | my ($self, $key, $value, $line) = @_; | ||||
1326 | unless (!defined $value || $value eq '') { | ||||
1327 | return $INVALID_VALUE; | ||||
1328 | } | ||||
1329 | $self->{internal_networks} = $self->new_netset('internal_networks',1); | ||||
1330 | $self->{internal_networks_configured} = 0; | ||||
1331 | } | ||||
1332 | 1 | 10µs | }); | ||
1333 | |||||
1334 | =item msa_networks IPaddress[/masklen] ... (default: none) | ||||
1335 | |||||
1336 | The networks or hosts which are acting as MSAs in your setup (but not also | ||||
1337 | as MX relays). This uses the same syntax as C<trusted_networks>, above - see | ||||
1338 | there for details. | ||||
1339 | |||||
1340 | B<MSA> means that the relay hosts on these networks accept mail from your | ||||
1341 | own users and authenticates them appropriately. These relays will never | ||||
1342 | accept mail from hosts that aren't authenticated in some way. Examples of | ||||
1343 | authentication include, IP lists, SMTP AUTH, POP-before-SMTP, etc. | ||||
1344 | |||||
1345 | All relays found in the message headers after the MSA relay will take | ||||
1346 | on the same trusted and internal classifications as the MSA relay itself, | ||||
1347 | as defined by your I<trusted_networks> and I<internal_networks> configuration. | ||||
1348 | |||||
1349 | For example, if the MSA relay is trusted and internal so will all of the | ||||
1350 | relays that precede it. | ||||
1351 | |||||
1352 | When using msa_networks to identify an MSA it is recommended that you treat | ||||
1353 | that MSA as both trusted and internal. When an MSA is not included in | ||||
1354 | msa_networks you should treat the MSA as trusted but not internal, however | ||||
1355 | if the MSA is also acting as an MX or intermediate relay you must always | ||||
1356 | treat it as both trusted and internal and ensure that the MSA includes | ||||
1357 | visible auth tokens in its Received header to identify submission clients. | ||||
1358 | |||||
1359 | B<Warning:> Never include an MSA that also acts as an MX (or is also an | ||||
1360 | intermediate relay for an MX) or otherwise accepts mail from | ||||
1361 | non-authenticated users in msa_networks. Doing so will result in unknown | ||||
1362 | external relays being trusted. | ||||
1363 | |||||
1364 | =cut | ||||
1365 | |||||
1366 | 1 | 5µs | push (@cmds, { | ||
1367 | setting => 'msa_networks', | ||||
1368 | type => $CONF_TYPE_IPADDRLIST, | ||||
1369 | }); | ||||
1370 | |||||
1371 | =item clear_msa_networks | ||||
1372 | |||||
1373 | Empty the list of msa networks. | ||||
1374 | |||||
1375 | =cut | ||||
1376 | |||||
1377 | push (@cmds, { | ||||
1378 | setting => 'clear_msa_networks', | ||||
1379 | type => $CONF_TYPE_NOARGS, | ||||
1380 | code => sub { | ||||
1381 | my ($self, $key, $value, $line) = @_; | ||||
1382 | unless (!defined $value || $value eq '') { | ||||
1383 | return $INVALID_VALUE; | ||||
1384 | } | ||||
1385 | $self->{msa_networks} = | ||||
1386 | $self->new_netset('msa_networks',0); # no loopback IP | ||||
1387 | $self->{msa_networks_configured} = 0; | ||||
1388 | } | ||||
1389 | 1 | 10µs | }); | ||
1390 | |||||
1391 | =item originating_ip_headers header ... (default: X-Yahoo-Post-IP X-Originating-IP X-Apparently-From X-SenderIP) | ||||
1392 | |||||
1393 | A list of header field names from which an originating IP address can | ||||
1394 | be obtained. For example, webmail servers may record a client IP address | ||||
1395 | in X-Originating-IP. | ||||
1396 | |||||
1397 | These IP addresses are virtually appended into the Received: chain, so they | ||||
1398 | are used in RBL checks where appropriate. | ||||
1399 | |||||
1400 | Currently the IP addresses are not added into X-Spam-Relays-* header fields, | ||||
1401 | but they may be in the future. | ||||
1402 | |||||
1403 | =cut | ||||
1404 | |||||
1405 | push (@cmds, { | ||||
1406 | setting => 'originating_ip_headers', | ||||
1407 | default => [], | ||||
1408 | type => $CONF_TYPE_STRINGLIST, | ||||
1409 | # spent 132µs (126+6) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1419] which was called 2 times, avg 66µs/call:
# 2 times (126µs+6µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 66µs/call | ||||
1410 | 2 | 10µs | my ($self, $key, $value, $line) = @_; | ||
1411 | 2 | 21µs | 2 | 6µs | unless (defined $value && $value !~ /^$/) { # spent 6µs making 2 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
1412 | return $MISSING_REQUIRED_VALUE; | ||||
1413 | } | ||||
1414 | 2 | 34µs | foreach my $hfname (split(/\s+/, $value)) { | ||
1415 | # avoid duplicates, consider header field names case-insensitive | ||||
1416 | 5 | 9µs | push(@{$self->{originating_ip_headers}}, $hfname) | ||
1417 | 10 | 67µs | if !grep(lc($_) eq lc($hfname), @{$self->{originating_ip_headers}}); | ||
1418 | } | ||||
1419 | } | ||||
1420 | 1 | 11µs | }); | ||
1421 | |||||
1422 | =item clear_originating_ip_headers | ||||
1423 | |||||
1424 | Empty the list of 'originating IP address' header field names. | ||||
1425 | |||||
1426 | =cut | ||||
1427 | |||||
1428 | push (@cmds, { | ||||
1429 | setting => 'clear_originating_ip_headers', | ||||
1430 | type => $CONF_TYPE_NOARGS, | ||||
1431 | # spent 17µs within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1437] which was called:
# once (17µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm | ||||
1432 | 1 | 5µs | my ($self, $key, $value, $line) = @_; | ||
1433 | 1 | 3µs | unless (!defined $value || $value eq '') { | ||
1434 | return $INVALID_VALUE; | ||||
1435 | } | ||||
1436 | 1 | 12µs | $self->{originating_ip_headers} = []; | ||
1437 | } | ||||
1438 | 1 | 9µs | }); | ||
1439 | |||||
1440 | =item always_trust_envelope_sender ( 0 | 1 ) (default: 0) | ||||
1441 | |||||
1442 | Trust the envelope sender even if the message has been passed through one or | ||||
1443 | more trusted relays. See also C<envelope_sender_header>. | ||||
1444 | |||||
1445 | =cut | ||||
1446 | |||||
1447 | 1 | 5µs | push (@cmds, { | ||
1448 | setting => 'always_trust_envelope_sender', | ||||
1449 | default => 0, | ||||
1450 | type => $CONF_TYPE_BOOL, | ||||
1451 | }); | ||||
1452 | |||||
1453 | =item skip_rbl_checks ( 0 | 1 ) (default: 0) | ||||
1454 | |||||
1455 | Turning on the skip_rbl_checks setting will disable the DNSEval plugin, | ||||
1456 | which implements Real-time Block List (or: Blackhole List) (RBL) lookups. | ||||
1457 | |||||
1458 | By default, SpamAssassin will run RBL checks. Individual blocklists may | ||||
1459 | be disabled selectively by setting a score of a corresponding rule to 0. | ||||
1460 | |||||
1461 | See also a related configuration parameter skip_uribl_checks, | ||||
1462 | which controls the URIDNSBL plugin (documented in the URIDNSBL man page). | ||||
1463 | |||||
1464 | =cut | ||||
1465 | |||||
1466 | 1 | 5µs | push (@cmds, { | ||
1467 | setting => 'skip_rbl_checks', | ||||
1468 | default => 0, | ||||
1469 | type => $CONF_TYPE_BOOL, | ||||
1470 | }); | ||||
1471 | |||||
1472 | =item dns_available { yes | no | test[: domain1 domain2...] } (default: yes) | ||||
1473 | |||||
1474 | Tells SpamAssassin whether DNS resolving is available or not. A value I<yes> | ||||
1475 | indicates DNS resolving is available, a value I<no> indicates DNS resolving | ||||
1476 | is not available - both of these values apply unconditionally and skip initial | ||||
1477 | DNS tests, which can be slow or unreliable. | ||||
1478 | |||||
1479 | When the option value is a I<test> (with or without arguments), SpamAssassin | ||||
1480 | will query some domain names on the internet during initialization, attempting | ||||
1481 | to determine if DNS resolving is working or not. A space-separated list | ||||
1482 | of domain names may be specified explicitly, or left to a built-in default | ||||
1483 | of a dozen or so domain names. From an explicit or a default list a subset | ||||
1484 | of three domain names is picked randomly for checking. The test queries for | ||||
1485 | NS records of these domain: if at least one query returns a success then | ||||
1486 | SpamAssassin considers DNS resolving as available, otherwise not. | ||||
1487 | |||||
1488 | The problem is that the test can introduce some startup delay if a network | ||||
1489 | connection is down, and in some cases it can wrongly guess that DNS is | ||||
1490 | unavailable because a test connection failed, what causes disabling several | ||||
1491 | DNS-dependent tests. | ||||
1492 | |||||
1493 | Please note, the DNS test queries for NS records, so specify domain names, | ||||
1494 | not host names. | ||||
1495 | |||||
1496 | Since version 3.4.0 of SpamAssassin a default setting for option | ||||
1497 | I<dns_available> is I<yes>. A default in older versions was I<test>. | ||||
1498 | |||||
1499 | =cut | ||||
1500 | |||||
1501 | push (@cmds, { | ||||
1502 | setting => 'dns_available', | ||||
1503 | default => 'yes', | ||||
1504 | type => $CONF_TYPE_STRING, | ||||
1505 | code => sub { | ||||
1506 | my ($self, $key, $value, $line) = @_; | ||||
1507 | if ($value =~ /^test(?::\s*\S.*)?$/) { | ||||
1508 | $self->{dns_available} = $value; | ||||
1509 | } | ||||
1510 | elsif ($value =~ /^(?:yes|1)$/) { | ||||
1511 | $self->{dns_available} = 'yes'; | ||||
1512 | } | ||||
1513 | elsif ($value =~ /^(?:no|0)$/) { | ||||
1514 | $self->{dns_available} = 'no'; | ||||
1515 | } | ||||
1516 | else { | ||||
1517 | return $INVALID_VALUE; | ||||
1518 | } | ||||
1519 | } | ||||
1520 | 1 | 11µs | }); | ||
1521 | |||||
1522 | =item dns_server ip-addr-port (default: entries provided by Net::DNS) | ||||
1523 | |||||
1524 | Specifies an IP address of a DNS server, and optionally its port number. | ||||
1525 | The I<dns_server> directive may be specified multiple times, each entry | ||||
1526 | adding to a list of available resolving name servers. The I<ip-addr-port> | ||||
1527 | argument can either be an IPv4 or IPv6 address, optionally enclosed in | ||||
1528 | brackets, and optionally followed by a colon and a port number. In absence | ||||
1529 | of a port number a standard port number 53 is assumed. When an IPv6 address | ||||
1530 | is specified along with a port number, the address B<must> be enclosed in | ||||
1531 | brackets to avoid parsing ambiguity regarding a colon separator. A scoped | ||||
1532 | link-local IP address is allowed (assuming underlying modules allow it). | ||||
1533 | |||||
1534 | Examples : | ||||
1535 | dns_server 127.0.0.1 | ||||
1536 | dns_server 127.0.0.1:53 | ||||
1537 | dns_server [127.0.0.1]:53 | ||||
1538 | dns_server [::1]:53 | ||||
1539 | dns_server fe80::1%lo0 | ||||
1540 | dns_server [fe80::1%lo0]:53 | ||||
1541 | |||||
1542 | In absence of I<dns_server> directives, the list of name servers is provided | ||||
1543 | by Net::DNS module, which typically obtains the list from /etc/resolv.conf, | ||||
1544 | but this may be platform dependent. Please consult the Net::DNS::Resolver | ||||
1545 | documentation for details. | ||||
1546 | |||||
1547 | =cut | ||||
1548 | |||||
1549 | push (@cmds, { | ||||
1550 | setting => 'dns_server', | ||||
1551 | type => $CONF_TYPE_STRING, | ||||
1552 | code => sub { | ||||
1553 | my ($self, $key, $value, $line) = @_; | ||||
1554 | my($address,$port); local($1,$2,$3); | ||||
1555 | if ($value =~ /^(?: \[ ([^\]]*) \] | ([^:]*) ) : (\d+) \z/sx) { | ||||
1556 | $address = defined $1 ? $1 : $2; $port = $3; | ||||
1557 | } elsif ($value =~ /^(?: \[ ([^\]]*) \] | | ||||
1558 | ([0-9A-F.:]+ (?: %[A-Z0-9._~-]* )? ) ) \z/six) { | ||||
1559 | $address = defined $1 ? $1 : $2; $port = '53'; | ||||
1560 | } else { | ||||
1561 | return $INVALID_VALUE; | ||||
1562 | } | ||||
1563 | my $scope = ''; # scoped IP address? | ||||
1564 | $scope = $1 if $address =~ s/ ( % [A-Z0-9._~-]* ) \z//xsi; | ||||
1565 | my $IP_ADDRESS = IP_ADDRESS; # IP_ADDRESS regexp does not handle scope | ||||
1566 | if ($address =~ /$IP_ADDRESS/ && $port >= 1 && $port <= 65535) { | ||||
1567 | $self->{dns_servers} = [] if !$self->{dns_servers}; | ||||
1568 | # checked, untainted, stored in a normalized form | ||||
1569 | push(@{$self->{dns_servers}}, untaint_var("[$address$scope]:$port")); | ||||
1570 | } else { | ||||
1571 | return $INVALID_VALUE; | ||||
1572 | } | ||||
1573 | } | ||||
1574 | 1 | 20µs | }); | ||
1575 | |||||
1576 | =item clear_dns_servers | ||||
1577 | |||||
1578 | Empty the list of explicitly configured DNS servers through a I<dns_server> | ||||
1579 | directive, falling back to Net::DNS -supplied defaults. | ||||
1580 | |||||
1581 | =cut | ||||
1582 | |||||
1583 | push (@cmds, { | ||||
1584 | setting => 'clear_dns_servers', | ||||
1585 | type => $CONF_TYPE_NOARGS, | ||||
1586 | code => sub { | ||||
1587 | my ($self, $key, $value, $line) = @_; | ||||
1588 | unless (!defined $value || $value eq '') { | ||||
1589 | return $INVALID_VALUE; | ||||
1590 | } | ||||
1591 | undef $self->{dns_servers}; | ||||
1592 | } | ||||
1593 | 1 | 10µs | }); | ||
1594 | |||||
1595 | =item dns_local_ports_permit ranges... | ||||
1596 | |||||
1597 | Add the specified ports or ports ranges to the set of allowed port numbers | ||||
1598 | that can be used as local port numbers when sending DNS queries to a resolver. | ||||
1599 | |||||
1600 | The argument is a whitespace-separated or a comma-separated list of | ||||
1601 | single port numbers n, or port number pairs (i.e. m-n) delimited by a '-', | ||||
1602 | representing a range. Allowed port numbers are between 1 and 65535. | ||||
1603 | |||||
1604 | Directives I<dns_local_ports_permit> and I<dns_local_ports_avoid> are processed | ||||
1605 | in order in which they appear in configuration files. Each directive adds | ||||
1606 | (or subtracts) its subsets of ports to a current set of available ports. | ||||
1607 | Whatever is left in the set by the end of configuration processing | ||||
1608 | is made available to a DNS resolving client code. | ||||
1609 | |||||
1610 | If the resulting set of port numbers is empty (see also the directive | ||||
1611 | I<dns_local_ports_none>), then SpamAssassin does not apply its ports | ||||
1612 | randomization logic, but instead leaves the operating system to choose | ||||
1613 | a suitable free local port number. | ||||
1614 | |||||
1615 | The initial set consists of all port numbers in the range 1024-65535. | ||||
1616 | Note that system config files already modify the set and remove all the | ||||
1617 | IANA registered port numbers and some other ranges, so there is rarely | ||||
1618 | a need to adjust the ranges by site-specific directives. | ||||
1619 | |||||
1620 | See also directives I<dns_local_ports_permit> and I<dns_local_ports_none>. | ||||
1621 | |||||
1622 | =cut | ||||
1623 | |||||
1624 | push (@cmds, { | ||||
1625 | setting => 'dns_local_ports_permit', | ||||
1626 | type => $CONF_TYPE_STRING, | ||||
1627 | is_admin => 1, | ||||
1628 | code => sub { | ||||
1629 | my($self, $key, $value, $line) = @_; | ||||
1630 | my(@port_ranges); local($1,$2); | ||||
1631 | foreach my $range (split(/[ \t,]+/, $value)) { | ||||
1632 | if ($range =~ /^(\d{1,5})\z/) { | ||||
1633 | # don't allow adding a port number 0 | ||||
1634 | if ($1 < 1 || $1 > 65535) { return $INVALID_VALUE } | ||||
1635 | push(@port_ranges, [$1,$1]); | ||||
1636 | } elsif ($range =~ /^(\d{1,5})-(\d{1,5})\z/) { | ||||
1637 | if ($1 < 1 || $1 > 65535) { return $INVALID_VALUE } | ||||
1638 | if ($2 < 1 || $2 > 65535) { return $INVALID_VALUE } | ||||
1639 | push(@port_ranges, [$1,$2]); | ||||
1640 | } else { | ||||
1641 | return $INVALID_VALUE; | ||||
1642 | } | ||||
1643 | } | ||||
1644 | foreach my $p (@port_ranges) { | ||||
1645 | undef $self->{dns_available_portscount}; # invalidate derived data | ||||
1646 | set_ports_range(\$self->{dns_available_ports_bitset}, | ||||
1647 | $p->[0], $p->[1], 1); | ||||
1648 | } | ||||
1649 | } | ||||
1650 | 1 | 21µs | }); | ||
1651 | |||||
1652 | =item dns_local_ports_avoid ranges... | ||||
1653 | |||||
1654 | Remove specified ports or ports ranges from the set of allowed port numbers | ||||
1655 | that can be used as local port numbers when sending DNS queries to a resolver. | ||||
1656 | |||||
1657 | Please see directive I<dns_local_ports_permit> for details. | ||||
1658 | |||||
1659 | =cut | ||||
1660 | |||||
1661 | push (@cmds, { | ||||
1662 | setting => 'dns_local_ports_avoid', | ||||
1663 | type => $CONF_TYPE_STRING, | ||||
1664 | is_admin => 1, | ||||
1665 | # spent 87.4ms (6.44+81.0) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1685] which was called 30 times, avg 2.91ms/call:
# 30 times (6.44ms+81.0ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 2.91ms/call | ||||
1666 | 30 | 137µs | my($self, $key, $value, $line) = @_; | ||
1667 | 60 | 140µs | my(@port_ranges); local($1,$2); | ||
1668 | 30 | 378µs | foreach my $range (split(/[ \t,]+/, $value)) { | ||
1669 | 190 | 2.82ms | 247 | 847µs | if ($range =~ /^(\d{1,5})\z/) { # spent 847µs making 247 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
1670 | 133 | 291µs | if ($1 > 65535) { return $INVALID_VALUE } | ||
1671 | # don't mind clearing also the port number 0 | ||||
1672 | 133 | 511µs | push(@port_ranges, [$1,$1]); | ||
1673 | } elsif ($range =~ /^(\d{1,5})-(\d{1,5})\z/) { | ||||
1674 | 57 | 170µs | if ($1 > 65535 || $2 > 65535) { return $INVALID_VALUE } | ||
1675 | 57 | 221µs | push(@port_ranges, [$1,$2]); | ||
1676 | } else { | ||||
1677 | return $INVALID_VALUE; | ||||
1678 | } | ||||
1679 | } | ||||
1680 | 30 | 424µs | foreach my $p (@port_ranges) { | ||
1681 | 190 | 394µs | undef $self->{dns_available_portscount}; # invalidate derived data | ||
1682 | set_ports_range(\$self->{dns_available_ports_bitset}, | ||||
1683 | 190 | 1.50ms | 190 | 80.1ms | $p->[0], $p->[1], 0); # spent 80.1ms making 190 calls to Mail::SpamAssassin::Conf::set_ports_range, avg 422µs/call |
1684 | } | ||||
1685 | } | ||||
1686 | 1 | 11µs | }); | ||
1687 | |||||
1688 | =item dns_local_ports_none | ||||
1689 | |||||
1690 | Is a fast shorthand for: | ||||
1691 | |||||
1692 | dns_local_ports_avoid 1-65535 | ||||
1693 | |||||
1694 | leaving the set of available DNS query local port numbers empty. In all | ||||
1695 | respects (apart from speed) it is equivalent to the shown directive, and can | ||||
1696 | be freely mixed with I<dns_local_ports_permit> and I<dns_local_ports_avoid>. | ||||
1697 | |||||
1698 | If the resulting set of port numbers is empty, then SpamAssassin does not | ||||
1699 | apply its ports randomization logic, but instead leaves the operating system | ||||
1700 | to choose a suitable free local port number. | ||||
1701 | |||||
1702 | See also directives I<dns_local_ports_permit> and I<dns_local_ports_avoid>. | ||||
1703 | |||||
1704 | =cut | ||||
1705 | |||||
1706 | push (@cmds, { | ||||
1707 | setting => 'dns_local_ports_none', | ||||
1708 | type => $CONF_TYPE_NOARGS, | ||||
1709 | is_admin => 1, | ||||
1710 | code => sub { | ||||
1711 | my ($self, $key, $value, $line) = @_; | ||||
1712 | unless (!defined $value || $value eq '') { | ||||
1713 | return $INVALID_VALUE; | ||||
1714 | } | ||||
1715 | undef $self->{dns_available_portscount}; # invalidate derived data | ||||
1716 | wipe_ports_range(\$self->{dns_available_ports_bitset}, 0); | ||||
1717 | } | ||||
1718 | 1 | 10µs | }); | ||
1719 | |||||
1720 | =item dns_test_interval n (default: 600 seconds) | ||||
1721 | |||||
1722 | If dns_available is set to I<test>, the dns_test_interval time in number | ||||
1723 | of seconds will tell SpamAssassin how often to retest for working DNS. | ||||
1724 | A numeric value is optionally suffixed by a time unit (s, m, h, d, w, | ||||
1725 | indicating seconds (default), minutes, hours, days, weeks). | ||||
1726 | |||||
1727 | =cut | ||||
1728 | |||||
1729 | 1 | 5µs | push (@cmds, { | ||
1730 | setting => 'dns_test_interval', | ||||
1731 | default => 600, | ||||
1732 | type => $CONF_TYPE_DURATION, | ||||
1733 | }); | ||||
1734 | |||||
1735 | =item dns_options opts (default: norotate, nodns0x20, edns=4096) | ||||
1736 | |||||
1737 | Provides a (whitespace or comma -separated) list of options applying | ||||
1738 | to DNS resolving. Available options are: I<rotate>, I<dns0x20> and | ||||
1739 | I<edns> (or I<edns0>). Option name may be negated by prepending a I<no> | ||||
1740 | (e.g. I<norotate>, I<NoEDNS>) to counteract a previously enabled option. | ||||
1741 | Option names are not case-sensitive. The I<dns_options> directive may | ||||
1742 | appear in configuration files multiple times, the last setting prevails. | ||||
1743 | |||||
1744 | Option I<edns> (or I<edsn0>) may take a value which specifies a requestor's | ||||
1745 | acceptable UDP payload size according to EDNS0 specifications (RFC 6891, | ||||
1746 | ex RFC 2671) e.g. I<edns=4096>. When EDNS0 is off (I<noedns> or I<edns=512>) | ||||
1747 | a traditional implied UDP payload size is 512 bytes, which is also a minimum | ||||
1748 | allowed value for this option. When the option is specified but a value | ||||
1749 | is not provided, a conservative default of 1220 bytes is implied. It is | ||||
1750 | recommended to keep I<edns> enabled when using a local recursive DNS server | ||||
1751 | which supports EDNS0 (like most modern DNS servers do), a suitable setting | ||||
1752 | in this case is I<edns=4096>, which is also a default. Allowing UDP payload | ||||
1753 | size larger than 512 bytes can avoid truncation of resource records in large | ||||
1754 | DNS responses (like in TXT records of some SPF and DKIM responses, or when | ||||
1755 | an unreasonable number of A records is published by some domain). The option | ||||
1756 | should be disabled when a recursive DNS server is only reachable through | ||||
1757 | non- RFC 6891 compliant middleboxes (such as some old-fashioned firewall) | ||||
1758 | which bans DNS UDP payload sizes larger than 512 bytes. A suitable value | ||||
1759 | when a non-local recursive DNS server is used and a middlebox B<does> allow | ||||
1760 | EDNS0 but blocks fragmented IP packets is perhaps 1220 bytes, allowing a | ||||
1761 | DNS UDP packet to fit within a single IP packet in most cases (a slightly | ||||
1762 | less conservative range would be 1280-1410 bytes). | ||||
1763 | |||||
1764 | Option I<rotate> causes SpamAssassin to choose a DNS server at random | ||||
1765 | from all servers listed in C</etc/resolv.conf> every I<dns_test_interval> | ||||
1766 | seconds, effectively spreading the load over all currently available DNS | ||||
1767 | servers when there are many spamd workers. | ||||
1768 | |||||
1769 | Option I<dns0x20> enables randomization of letters in a DNS query label | ||||
1770 | according to draft-vixie-dnsext-dns0x20, decreasing a chance of collisions | ||||
1771 | of responses (by chance or by a malicious intent) by increasing spread | ||||
1772 | as provided by a 16-bit query ID and up to 16 bits of a port number, | ||||
1773 | with additional bits as encoded by flipping case (upper/lower) of letters | ||||
1774 | in a query. The number of additional random bits corresponds to the number | ||||
1775 | of letters in a query label. Should work reliably with all mainstream | ||||
1776 | DNS servers - do not turn on if you see frequent info messages | ||||
1777 | "dns: no callback for id:" in the log, or if RBL or URIDNS lookups | ||||
1778 | do not work for no apparent reason. | ||||
1779 | |||||
1780 | =cut | ||||
1781 | |||||
1782 | push (@cmds, { | ||||
1783 | setting => 'dns_options', | ||||
1784 | type => $CONF_TYPE_HASH_KEY_VALUE, | ||||
1785 | code => sub { | ||||
1786 | my ($self, $key, $value, $line) = @_; | ||||
1787 | foreach my $option (split (/[\s,]+/, lc $value)) { | ||||
1788 | local($1,$2); | ||||
1789 | if ($option =~ /^no(rotate|dns0x20)\z/) { | ||||
1790 | $self->{dns_options}->{$1} = 0; | ||||
1791 | } elsif ($option =~ /^no(edns)0?\z/) { | ||||
1792 | $self->{dns_options}->{$1} = 0; | ||||
1793 | } elsif ($option =~ /^(rotate|dns0x20)\z/) { | ||||
1794 | $self->{dns_options}->{$1} = 1; | ||||
1795 | } elsif ($option =~ /^(edns)0? (?: = (\d+) )? \z/x) { | ||||
1796 | # RFC 6891 (ex RFC 2671) - EDNS0, value is a requestor's UDP payload | ||||
1797 | # size, defaults to some UDP packet size likely to fit into a single | ||||
1798 | # IP packet which is more likely to pass firewalls which choke on IP | ||||
1799 | # fragments. RFC 2460: min MTU is 1280 for IPv6, minus 40 bytes for | ||||
1800 | # basic header, yielding 1240. RFC 3226 prescribes a min of 1220 for | ||||
1801 | # RFC 2535 compliant servers. RFC 6891: choosing between 1280 and | ||||
1802 | # 1410 bytes for IP (v4 or v6) over Ethernet would be reasonable. | ||||
1803 | # | ||||
1804 | $self->{dns_options}->{$1} = $2 || 1220; | ||||
1805 | return $INVALID_VALUE if $self->{dns_options}->{$1} < 512; | ||||
1806 | } else { | ||||
1807 | return $INVALID_VALUE; | ||||
1808 | } | ||||
1809 | } | ||||
1810 | } | ||||
1811 | 1 | 10µs | }); | ||
1812 | |||||
1813 | =item dns_query_restriction (allow|deny) domain1 domain2 ... | ||||
1814 | |||||
1815 | Option allows disabling of rules which would result in a DNS query to one of | ||||
1816 | the listed domains. The first argument must be a literal C<allow> or C<deny>, | ||||
1817 | remaining arguments are domains names. | ||||
1818 | |||||
1819 | Most DNS queries (with some exceptions) are subject to dns_query_restriction. | ||||
1820 | A domain to be queried is successively stripped-off of its leading labels | ||||
1821 | (thus yielding a series of its parent domains), and on each iteration a | ||||
1822 | check is made against an associative array generated by dns_query_restriction | ||||
1823 | options. Search stops at the first match (i.e. the tightest match), and the | ||||
1824 | matching entry with its C<allow> or C<deny> value then controls whether a | ||||
1825 | DNS query is allowed to be launched. | ||||
1826 | |||||
1827 | If no match is found an implicit default is to allow a query. The purpose of | ||||
1828 | an explicit C<allow> entry is to be able to override a previously configured | ||||
1829 | C<deny> on the same domain or to override an entry (possibly yet to be | ||||
1830 | configured in subsequent config directives) on one of its parent domains. | ||||
1831 | Thus an 'allow zen.spamhaus.org' with a 'deny spamhaus.org' would permit | ||||
1832 | DNS queries on a specific DNS BL zone but deny queries to other zones under | ||||
1833 | the same parent domain. | ||||
1834 | |||||
1835 | Domains are matched case-insensitively, no wildcards are recognized, | ||||
1836 | there should be no leading or trailing dot. | ||||
1837 | |||||
1838 | Specifying a block on querying a domain name has a similar effect as setting | ||||
1839 | a score of corresponding DNSBL and URIBL rules to zero, and can be a handy | ||||
1840 | alternative to hunting for such rules when a site policy does not allow | ||||
1841 | certain DNS block lists to be queried. | ||||
1842 | |||||
1843 | Example: | ||||
1844 | dns_query_restriction deny dnswl.org surbl.org | ||||
1845 | dns_query_restriction allow zen.spamhaus.org | ||||
1846 | dns_query_restriction deny spamhaus.org mailspike.net spamcop.net | ||||
1847 | |||||
1848 | =cut | ||||
1849 | |||||
1850 | push (@cmds, { | ||||
1851 | setting => 'dns_query_restriction', | ||||
1852 | type => $CONF_TYPE_STRING, | ||||
1853 | code => sub { | ||||
1854 | my ($self, $key, $value, $line) = @_; | ||||
1855 | defined $value && $value =~ s/^(allow|deny)\s+//i | ||||
1856 | or return $INVALID_VALUE; | ||||
1857 | my $blocked = lc($1) eq 'deny' ? 1 : 0; | ||||
1858 | foreach my $domain (split(' ', $value)) { | ||||
1859 | $domain =~ s/^\.//; $domain =~ s/\.\z//; # strip dots | ||||
1860 | $self->{dns_query_blocked}{lc $domain} = $blocked; | ||||
1861 | } | ||||
1862 | } | ||||
1863 | 1 | 15µs | }); | ||
1864 | |||||
1865 | =item clear_dns_query_restriction | ||||
1866 | |||||
1867 | The option removes any entries entered by previous 'dns_query_restriction' | ||||
1868 | options, leaving the list empty, i.e. allowing DNS queries for any domain | ||||
1869 | (including any DNS BL zone). | ||||
1870 | |||||
1871 | =cut | ||||
1872 | |||||
1873 | push (@cmds, { | ||||
1874 | setting => 'clear_dns_query_restriction', | ||||
1875 | aliases => ['clear_dns_query_restrictions'], | ||||
1876 | type => $CONF_TYPE_NOARGS, | ||||
1877 | code => sub { | ||||
1878 | my ($self, $key, $value, $line) = @_; | ||||
1879 | return $INVALID_VALUE if defined $value && $value ne ''; | ||||
1880 | delete $self->{dns_query_blocked}; | ||||
1881 | } | ||||
1882 | 1 | 11µs | }); | ||
1883 | |||||
1884 | =back | ||||
1885 | |||||
1886 | =head2 LEARNING OPTIONS | ||||
1887 | |||||
1888 | =over 4 | ||||
1889 | |||||
1890 | =item use_learner ( 0 | 1 ) (default: 1) | ||||
1891 | |||||
1892 | Whether to use any machine-learning classifiers with SpamAssassin, such as the | ||||
1893 | default 'BAYES_*' rules. Setting this to 0 will disable use of any and all | ||||
1894 | human-trained classifiers. | ||||
1895 | |||||
1896 | =cut | ||||
1897 | |||||
1898 | 1 | 6µs | push (@cmds, { | ||
1899 | setting => 'use_learner', | ||||
1900 | default => 1, | ||||
1901 | type => $CONF_TYPE_BOOL, | ||||
1902 | }); | ||||
1903 | |||||
1904 | =item use_bayes ( 0 | 1 ) (default: 1) | ||||
1905 | |||||
1906 | Whether to use the naive-Bayesian-style classifier built into | ||||
1907 | SpamAssassin. This is a master on/off switch for all Bayes-related | ||||
1908 | operations. | ||||
1909 | |||||
1910 | =cut | ||||
1911 | |||||
1912 | 1 | 5µs | push (@cmds, { | ||
1913 | setting => 'use_bayes', | ||||
1914 | default => 1, | ||||
1915 | type => $CONF_TYPE_BOOL, | ||||
1916 | }); | ||||
1917 | |||||
1918 | =item use_bayes_rules ( 0 | 1 ) (default: 1) | ||||
1919 | |||||
1920 | Whether to use rules using the naive-Bayesian-style classifier built | ||||
1921 | into SpamAssassin. This allows you to disable the rules while leaving | ||||
1922 | auto and manual learning enabled. | ||||
1923 | |||||
1924 | =cut | ||||
1925 | |||||
1926 | 1 | 10µs | push (@cmds, { | ||
1927 | setting => 'use_bayes_rules', | ||||
1928 | default => 1, | ||||
1929 | type => $CONF_TYPE_BOOL, | ||||
1930 | }); | ||||
1931 | |||||
1932 | =item bayes_auto_learn ( 0 | 1 ) (default: 1) | ||||
1933 | |||||
1934 | Whether SpamAssassin should automatically feed high-scoring mails (or | ||||
1935 | low-scoring mails, for non-spam) into its learning systems. The only | ||||
1936 | learning system supported currently is a naive-Bayesian-style classifier. | ||||
1937 | |||||
1938 | See the documentation for the | ||||
1939 | C<Mail::SpamAssassin::Plugin::AutoLearnThreshold> plugin module | ||||
1940 | for details on how Bayes auto-learning is implemented by default. | ||||
1941 | |||||
1942 | =cut | ||||
1943 | |||||
1944 | 1 | 5µs | push (@cmds, { | ||
1945 | setting => 'bayes_auto_learn', | ||||
1946 | default => 1, | ||||
1947 | type => $CONF_TYPE_BOOL, | ||||
1948 | }); | ||||
1949 | |||||
1950 | =item bayes_token_sources (default: header visible invisible uri) | ||||
1951 | |||||
1952 | Controls which sources in a mail message can contribute tokens (e.g. words, | ||||
1953 | phrases, etc.) to a Bayes classifier. The argument is a space-separated list | ||||
1954 | of keywords: I<header>, I<visible>, I<invisible>, I<uri>, I<mimepart>), each | ||||
1955 | of which may be prefixed by a I<no> to indicate its exclusion. Additionally | ||||
1956 | two reserved keywords are allowed: I<all> and I<none> (or: I<noall>). The list | ||||
1957 | of keywords is processed sequentially: a keyword I<all> adds all available | ||||
1958 | keywords to a set being built, a I<none> or I<noall> clears the set, other | ||||
1959 | non-negated keywords are added to the set, and negated keywords are removed | ||||
1960 | from the set. Keywords are case-insensitive. | ||||
1961 | |||||
1962 | The default set is: I<header> I<visible> I<invisible> I<uri>, which is | ||||
1963 | equivalent for example to: I<All> I<NoMIMEpart>. The reason why I<mimepart> | ||||
1964 | is not currently in a default set is that it is a newer source (introduced | ||||
1965 | with SpamAssassin version 3.4.1) and not much experience has yet been gathered | ||||
1966 | regarding its usefulness. | ||||
1967 | |||||
1968 | See also option C<bayes_ignore_header> for a fine-grained control on individual | ||||
1969 | header fields under the umbrella of a more general keyword I<header> here. | ||||
1970 | |||||
1971 | Keywords imply the following data sources: | ||||
1972 | |||||
1973 | =over 4 | ||||
1974 | |||||
1975 | =item I<header> - tokens collected from a message header section | ||||
1976 | |||||
1977 | =item I<visible> - words from visible text (plain or HTML) in a message body | ||||
1978 | |||||
1979 | =item I<invisible> - hidden/invisible text in HTML parts of a message body | ||||
1980 | |||||
1981 | =item I<uri> - URIs collected from a message body | ||||
1982 | |||||
1983 | =item I<mimepart> - digests (hashes) of all MIME parts (textual or non-textual) of a message, computed after Base64 and quoted-printable decoding, suffixed by their Content-Type | ||||
1984 | |||||
1985 | =item I<all> - adds all the above keywords to the set being assembled | ||||
1986 | |||||
1987 | =item I<none> or I<noall> - removes all keywords from the set | ||||
1988 | |||||
1989 | =back | ||||
1990 | |||||
1991 | The C<bayes_token_sources> directive may appear multiple times, its keywords | ||||
1992 | are interpreted sequentially, adding or removing items from the final set | ||||
1993 | as they appear in their order in C<bayes_token_sources> directive(s). | ||||
1994 | |||||
1995 | =cut | ||||
1996 | |||||
1997 | push (@cmds, { | ||||
1998 | setting => 'bayes_token_sources', | ||||
1999 | default => { map(($_,1), qw(header visible invisible uri)) }, # mimepart | ||||
2000 | type => $CONF_TYPE_HASH_KEY_VALUE, | ||||
2001 | code => sub { | ||||
2002 | my ($self, $key, $value, $line) = @_; | ||||
2003 | return $MISSING_REQUIRED_VALUE if $value eq ''; | ||||
2004 | my $h = ($self->{bayes_token_sources} ||= {}); | ||||
2005 | my %all_kw = map(($_,1), qw(header visible invisible uri mimepart)); | ||||
2006 | foreach (split(' ', lc $value)) { | ||||
2007 | if (/^(none|noall)\z/) { | ||||
2008 | %$h = (); | ||||
2009 | } elsif ($_ eq 'all') { | ||||
2010 | %$h = %all_kw; | ||||
2011 | } elsif (/^(no)?(.+)\z/s && exists $all_kw{$2}) { | ||||
2012 | $h->{$2} = defined $1 ? 0 : 1; | ||||
2013 | } else { | ||||
2014 | return $INVALID_VALUE; | ||||
2015 | } | ||||
2016 | } | ||||
2017 | } | ||||
2018 | 1 | 24µs | }); | ||
2019 | |||||
2020 | =item bayes_ignore_header header_name | ||||
2021 | |||||
2022 | If you receive mail filtered by upstream mail systems, like | ||||
2023 | a spam-filtering ISP or mailing list, and that service adds | ||||
2024 | new headers (as most of them do), these headers may provide | ||||
2025 | inappropriate cues to the Bayesian classifier, allowing it | ||||
2026 | to take a "short cut". To avoid this, list the headers using this | ||||
2027 | setting. Example: | ||||
2028 | |||||
2029 | bayes_ignore_header X-Upstream-Spamfilter | ||||
2030 | bayes_ignore_header X-Upstream-SomethingElse | ||||
2031 | |||||
2032 | =cut | ||||
2033 | |||||
2034 | push (@cmds, { | ||||
2035 | setting => 'bayes_ignore_header', | ||||
2036 | default => [], | ||||
2037 | type => $CONF_TYPE_STRINGLIST, | ||||
2038 | # spent 5.85ms within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2044] which was called 270 times, avg 22µs/call:
# 270 times (5.85ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 22µs/call | ||||
2039 | 270 | 1.36ms | my ($self, $key, $value, $line) = @_; | ||
2040 | 270 | 479µs | if ($value eq '') { | ||
2041 | return $MISSING_REQUIRED_VALUE; | ||||
2042 | } | ||||
2043 | 540 | 5.36ms | push (@{$self->{bayes_ignore_headers}}, split(/\s+/, $value)); | ||
2044 | } | ||||
2045 | 1 | 10µs | }); | ||
2046 | |||||
2047 | =item bayes_ignore_from user@example.com | ||||
2048 | |||||
2049 | Bayesian classification and autolearning will not be performed on mail | ||||
2050 | from the listed addresses. Program C<sa-learn> will also ignore the | ||||
2051 | listed addresses if it is invoked using the C<--use-ignores> option. | ||||
2052 | One or more addresses can be listed, see C<whitelist_from>. | ||||
2053 | |||||
2054 | Spam messages from certain senders may contain many words that | ||||
2055 | frequently occur in ham. For example, one might read messages from a | ||||
2056 | preferred bookstore but also get unwanted spam messages from other | ||||
2057 | bookstores. If the unwanted messages are learned as spam then any | ||||
2058 | messages discussing books, including the preferred bookstore and | ||||
2059 | antiquarian messages would be in danger of being marked as spam. The | ||||
2060 | addresses of the annoying bookstores would be listed. (Assuming they | ||||
2061 | were halfway legitimate and didn't send you mail through myriad | ||||
2062 | affiliates.) | ||||
2063 | |||||
2064 | Those who have pieces of spam in legitimate messages or otherwise | ||||
2065 | receive ham messages containing potentially spammy words might fear | ||||
2066 | that some spam messages might be in danger of being marked as ham. | ||||
2067 | The addresses of the spam mailing lists, correspondents, etc. would | ||||
2068 | be listed. | ||||
2069 | |||||
2070 | =cut | ||||
2071 | |||||
2072 | 1 | 4µs | push (@cmds, { | ||
2073 | setting => 'bayes_ignore_from', | ||||
2074 | type => $CONF_TYPE_ADDRLIST, | ||||
2075 | }); | ||||
2076 | |||||
2077 | =item bayes_ignore_to user@example.com | ||||
2078 | |||||
2079 | Bayesian classification and autolearning will not be performed on mail | ||||
2080 | to the listed addresses. See C<bayes_ignore_from> for details. | ||||
2081 | |||||
2082 | =cut | ||||
2083 | |||||
2084 | 1 | 4µs | push (@cmds, { | ||
2085 | setting => 'bayes_ignore_to', | ||||
2086 | type => $CONF_TYPE_ADDRLIST, | ||||
2087 | }); | ||||
2088 | |||||
2089 | =item bayes_min_ham_num (Default: 200) | ||||
2090 | |||||
2091 | =item bayes_min_spam_num (Default: 200) | ||||
2092 | |||||
2093 | To be accurate, the Bayes system does not activate until a certain number of | ||||
2094 | ham (non-spam) and spam have been learned. The default is 200 of each ham and | ||||
2095 | spam, but you can tune these up or down with these two settings. | ||||
2096 | |||||
2097 | =cut | ||||
2098 | |||||
2099 | 1 | 4µs | push (@cmds, { | ||
2100 | setting => 'bayes_min_ham_num', | ||||
2101 | default => 200, | ||||
2102 | type => $CONF_TYPE_NUMERIC, | ||||
2103 | }); | ||||
2104 | 1 | 4µs | push (@cmds, { | ||
2105 | setting => 'bayes_min_spam_num', | ||||
2106 | default => 200, | ||||
2107 | type => $CONF_TYPE_NUMERIC, | ||||
2108 | }); | ||||
2109 | |||||
2110 | =item bayes_learn_during_report (Default: 1) | ||||
2111 | |||||
2112 | The Bayes system will, by default, learn any reported messages | ||||
2113 | (C<spamassassin -r>) as spam. If you do not want this to happen, set | ||||
2114 | this option to 0. | ||||
2115 | |||||
2116 | =cut | ||||
2117 | |||||
2118 | 1 | 6µs | push (@cmds, { | ||
2119 | setting => 'bayes_learn_during_report', | ||||
2120 | default => 1, | ||||
2121 | type => $CONF_TYPE_BOOL, | ||||
2122 | }); | ||||
2123 | |||||
2124 | =item bayes_sql_override_username | ||||
2125 | |||||
2126 | Used by BayesStore::SQL storage implementation. | ||||
2127 | |||||
2128 | If this options is set the BayesStore::SQL module will override the set | ||||
2129 | username with the value given. This could be useful for implementing global or | ||||
2130 | group bayes databases. | ||||
2131 | |||||
2132 | =cut | ||||
2133 | |||||
2134 | 1 | 5µs | push (@cmds, { | ||
2135 | setting => 'bayes_sql_override_username', | ||||
2136 | default => '', | ||||
2137 | type => $CONF_TYPE_STRING, | ||||
2138 | }); | ||||
2139 | |||||
2140 | =item bayes_use_hapaxes (default: 1) | ||||
2141 | |||||
2142 | Should the Bayesian classifier use hapaxes (words/tokens that occur only | ||||
2143 | once) when classifying? This produces significantly better hit-rates. | ||||
2144 | |||||
2145 | =cut | ||||
2146 | |||||
2147 | 1 | 5µs | push (@cmds, { | ||
2148 | setting => 'bayes_use_hapaxes', | ||||
2149 | default => 1, | ||||
2150 | type => $CONF_TYPE_BOOL, | ||||
2151 | }); | ||||
2152 | |||||
2153 | =item bayes_journal_max_size (default: 102400) | ||||
2154 | |||||
2155 | SpamAssassin will opportunistically sync the journal and the database. | ||||
2156 | It will do so once a day, but will sync more often if the journal file | ||||
2157 | size goes above this setting, in bytes. If set to 0, opportunistic | ||||
2158 | syncing will not occur. | ||||
2159 | |||||
2160 | =cut | ||||
2161 | |||||
2162 | 1 | 4µs | push (@cmds, { | ||
2163 | setting => 'bayes_journal_max_size', | ||||
2164 | default => 102400, | ||||
2165 | type => $CONF_TYPE_NUMERIC, | ||||
2166 | }); | ||||
2167 | |||||
2168 | =item bayes_expiry_max_db_size (default: 150000) | ||||
2169 | |||||
2170 | What should be the maximum size of the Bayes tokens database? When expiry | ||||
2171 | occurs, the Bayes system will keep either 75% of the maximum value, or | ||||
2172 | 100,000 tokens, whichever has a larger value. 150,000 tokens is roughly | ||||
2173 | equivalent to a 8Mb database file. | ||||
2174 | |||||
2175 | =cut | ||||
2176 | |||||
2177 | 1 | 4µs | push (@cmds, { | ||
2178 | setting => 'bayes_expiry_max_db_size', | ||||
2179 | default => 150000, | ||||
2180 | type => $CONF_TYPE_NUMERIC, | ||||
2181 | }); | ||||
2182 | |||||
2183 | =item bayes_auto_expire (default: 1) | ||||
2184 | |||||
2185 | If enabled, the Bayes system will try to automatically expire old tokens | ||||
2186 | from the database. Auto-expiry occurs when the number of tokens in the | ||||
2187 | database surpasses the bayes_expiry_max_db_size value. If a bayes datastore | ||||
2188 | backend does not implement individual key/value expirations, the setting | ||||
2189 | is silently ignored. | ||||
2190 | |||||
2191 | =cut | ||||
2192 | |||||
2193 | 1 | 4µs | push (@cmds, { | ||
2194 | setting => 'bayes_auto_expire', | ||||
2195 | default => 1, | ||||
2196 | type => $CONF_TYPE_BOOL, | ||||
2197 | }); | ||||
2198 | |||||
2199 | =item bayes_token_ttl (default: 3w, i.e. 3 weeks) | ||||
2200 | |||||
2201 | Time-to-live / expiration time in seconds for tokens kept in a Bayes database. | ||||
2202 | A numeric value is optionally suffixed by a time unit (s, m, h, d, w, | ||||
2203 | indicating seconds (default), minutes, hours, days, weeks). | ||||
2204 | |||||
2205 | If bayes_auto_expire is true and a Bayes datastore backend supports it | ||||
2206 | (currently only Redis), this setting controls deletion of expired tokens | ||||
2207 | from a bayes database. The value is observed on a best-effort basis, exact | ||||
2208 | timing promises are not necessarily kept. If a bayes datastore backend | ||||
2209 | does not implement individual key/value expirations, the setting is silently | ||||
2210 | ignored. | ||||
2211 | |||||
2212 | =cut | ||||
2213 | |||||
2214 | 1 | 4µs | push (@cmds, { | ||
2215 | setting => 'bayes_token_ttl', | ||||
2216 | default => 3*7*24*60*60, # seconds (3 weeks) | ||||
2217 | type => $CONF_TYPE_DURATION, | ||||
2218 | }); | ||||
2219 | |||||
2220 | =item bayes_seen_ttl (default: 8d, i.e. 8 days) | ||||
2221 | |||||
2222 | Time-to-live / expiration time in seconds for 'seen' entries | ||||
2223 | (i.e. mail message digests with their status) kept in a Bayes database. | ||||
2224 | A numeric value is optionally suffixed by a time unit (s, m, h, d, w, | ||||
2225 | indicating seconds (default), minutes, hours, days, weeks). | ||||
2226 | |||||
2227 | If bayes_auto_expire is true and a Bayes datastore backend supports it | ||||
2228 | (currently only Redis), this setting controls deletion of expired 'seen' | ||||
2229 | entries from a bayes database. The value is observed on a best-effort basis, | ||||
2230 | exact timing promises are not necessarily kept. If a bayes datastore backend | ||||
2231 | does not implement individual key/value expirations, the setting is silently | ||||
2232 | ignored. | ||||
2233 | |||||
2234 | =cut | ||||
2235 | |||||
2236 | 1 | 4µs | push (@cmds, { | ||
2237 | setting => 'bayes_seen_ttl', | ||||
2238 | default => 8*24*60*60, # seconds (8 days) | ||||
2239 | type => $CONF_TYPE_DURATION, | ||||
2240 | }); | ||||
2241 | |||||
2242 | =item bayes_learn_to_journal (default: 0) | ||||
2243 | |||||
2244 | If this option is set, whenever SpamAssassin does Bayes learning, it | ||||
2245 | will put the information into the journal instead of directly into the | ||||
2246 | database. This lowers contention for locking the database to execute | ||||
2247 | an update, but will also cause more access to the journal and cause a | ||||
2248 | delay before the updates are actually committed to the Bayes database. | ||||
2249 | |||||
2250 | =cut | ||||
2251 | |||||
2252 | 1 | 11µs | push (@cmds, { | ||
2253 | setting => 'bayes_learn_to_journal', | ||||
2254 | default => 0, | ||||
2255 | type => $CONF_TYPE_BOOL, | ||||
2256 | }); | ||||
2257 | |||||
2258 | =back | ||||
2259 | |||||
2260 | =head2 MISCELLANEOUS OPTIONS | ||||
2261 | |||||
2262 | =over 4 | ||||
2263 | |||||
2264 | =item time_limit n (default: 300) | ||||
2265 | |||||
2266 | Specifies a limit on elapsed time in seconds that SpamAssassin is allowed | ||||
2267 | to spend before providing a result. The value may be fractional and must | ||||
2268 | not be negative, zero is interpreted as unlimited. The default is 300 | ||||
2269 | seconds for consistency with the spamd default setting of --timeout-child . | ||||
2270 | |||||
2271 | This is a best-effort advisory setting, processing will not be abruptly | ||||
2272 | aborted at an arbitrary point in processing when the time limit is exceeded, | ||||
2273 | but only on reaching one of locations in the program flow equipped with a | ||||
2274 | time test. Currently equipped with the test are the main checking loop, | ||||
2275 | asynchronous DNS lookups, plugins which are calling external programs. | ||||
2276 | Rule evaluation is guarded by starting a timer (alarm) on each set of | ||||
2277 | compiled rules. | ||||
2278 | |||||
2279 | When a message is passed to Mail::SpamAssassin::parse, a deadline time | ||||
2280 | is established as a sum of current time and the C<time_limit> setting. | ||||
2281 | |||||
2282 | This deadline may also be specified by a caller through an option | ||||
2283 | 'master_deadline' in $suppl_attrib on a call to parse(), possibly providing | ||||
2284 | a more accurate deadline taking into account past and expected future | ||||
2285 | processing of a message in a mail filtering setup. If both the config | ||||
2286 | option as well as a 'master_deadline' option in a call are provided, | ||||
2287 | the shorter time limit of the two is used (since version 3.3.2). | ||||
2288 | Note that spamd (and possibly third-party callers of SpamAssassin) will | ||||
2289 | supply the 'master_deadline' option in a call based on its --timeout-child | ||||
2290 | option (or equivalent), unlike the command line C<spamassassin>, which has | ||||
2291 | no such command line option. | ||||
2292 | |||||
2293 | When a time limit is exceeded, most of the remaining tests will be skipped, | ||||
2294 | as well as auto-learning. Whatever tests fired so far will determine the | ||||
2295 | final score. The behaviour is similar to short-circuiting with attribute 'on', | ||||
2296 | as implemented by a Shortcircuit plugin. A synthetic hit on a rule named | ||||
2297 | TIME_LIMIT_EXCEEDED with a near-zero default score is generated, so that | ||||
2298 | the report will reflect the event. A score for TIME_LIMIT_EXCEEDED may | ||||
2299 | be provided explicitly in a configuration file, for example to achieve | ||||
2300 | whitelisting or blacklisting effect for messages with long processing times. | ||||
2301 | |||||
2302 | The C<time_limit> option is a useful protection against excessive processing | ||||
2303 | time on certain degenerate or unusually long or complex mail messages, as well | ||||
2304 | as against some DoS attacks. It is also needed in time-critical pre-queue | ||||
2305 | filtering setups (e.g. milter, proxy, integration with MTA), where message | ||||
2306 | processing must finish before a SMTP client times out. RFC 5321 prescribes | ||||
2307 | in section 4.5.3.2.6 the 'DATA Termination' time limit of 10 minutes, | ||||
2308 | although it is not unusual to see some SMTP clients abort sooner on waiting | ||||
2309 | for a response. A sensible C<time_limit> for a pre-queue filtering setup is | ||||
2310 | maybe 50 seconds, assuming that clients are willing to wait at least a minute. | ||||
2311 | |||||
2312 | =cut | ||||
2313 | |||||
2314 | 1 | 4µs | push (@cmds, { | ||
2315 | setting => 'time_limit', | ||||
2316 | default => 300, | ||||
2317 | type => $CONF_TYPE_DURATION, | ||||
2318 | }); | ||||
2319 | |||||
2320 | =item lock_method type | ||||
2321 | |||||
2322 | Select the file-locking method used to protect database files on-disk. By | ||||
2323 | default, SpamAssassin uses an NFS-safe locking method on UNIX; however, if you | ||||
2324 | are sure that the database files you'll be using for Bayes and AWL storage will | ||||
2325 | never be accessed over NFS, a non-NFS-safe locking system can be selected. | ||||
2326 | |||||
2327 | This will be quite a bit faster, but may risk file corruption if the files are | ||||
2328 | ever accessed by multiple clients at once, and one or more of them is accessing | ||||
2329 | them through an NFS filesystem. | ||||
2330 | |||||
2331 | Note that different platforms require different locking systems. | ||||
2332 | |||||
2333 | The supported locking systems for C<type> are as follows: | ||||
2334 | |||||
2335 | =over 4 | ||||
2336 | |||||
2337 | =item I<nfssafe> - an NFS-safe locking system | ||||
2338 | |||||
2339 | =item I<flock> - simple UNIX C<flock()> locking | ||||
2340 | |||||
2341 | =item I<win32> - Win32 locking using C<sysopen (..., O_CREAT|O_EXCL)>. | ||||
2342 | |||||
2343 | =back | ||||
2344 | |||||
2345 | nfssafe and flock are only available on UNIX, and win32 is only available | ||||
2346 | on Windows. By default, SpamAssassin will choose either nfssafe or | ||||
2347 | win32 depending on the platform in use. | ||||
2348 | |||||
2349 | =cut | ||||
2350 | |||||
2351 | push (@cmds, { | ||||
2352 | setting => 'lock_method', | ||||
2353 | default => '', | ||||
2354 | type => $CONF_TYPE_STRING, | ||||
2355 | code => sub { | ||||
2356 | my ($self, $key, $value, $line) = @_; | ||||
2357 | if ($value !~ /^(nfssafe|flock|win32)$/) { | ||||
2358 | return $INVALID_VALUE; | ||||
2359 | } | ||||
2360 | |||||
2361 | $self->{lock_method} = $value; | ||||
2362 | # recreate the locker | ||||
2363 | $self->{main}->create_locker(); | ||||
2364 | } | ||||
2365 | 1 | 10µs | }); | ||
2366 | |||||
2367 | =item fold_headers ( 0 | 1 ) (default: 1) | ||||
2368 | |||||
2369 | By default, headers added by SpamAssassin will be whitespace folded. | ||||
2370 | In other words, they will be broken up into multiple lines instead of | ||||
2371 | one very long one and each continuation line will have a tabulator | ||||
2372 | prepended to mark it as a continuation of the preceding one. | ||||
2373 | |||||
2374 | The automatic wrapping can be disabled here. Note that this can generate very | ||||
2375 | long lines. RFC 2822 required that header lines do not exceed 998 characters | ||||
2376 | (not counting the final CRLF). | ||||
2377 | |||||
2378 | =cut | ||||
2379 | |||||
2380 | 1 | 4µs | push (@cmds, { | ||
2381 | setting => 'fold_headers', | ||||
2382 | default => 1, | ||||
2383 | type => $CONF_TYPE_BOOL, | ||||
2384 | }); | ||||
2385 | |||||
2386 | =item report_safe_copy_headers header_name ... | ||||
2387 | |||||
2388 | If using C<report_safe>, a few of the headers from the original message | ||||
2389 | are copied into the wrapper header (From, To, Cc, Subject, Date, etc.) | ||||
2390 | If you want to have other headers copied as well, you can add them | ||||
2391 | using this option. You can specify multiple headers on the same line, | ||||
2392 | separated by spaces, or you can just use multiple lines. | ||||
2393 | |||||
2394 | =cut | ||||
2395 | |||||
2396 | push (@cmds, { | ||||
2397 | setting => 'report_safe_copy_headers', | ||||
2398 | default => [], | ||||
2399 | type => $CONF_TYPE_STRINGLIST, | ||||
2400 | code => sub { | ||||
2401 | my ($self, $key, $value, $line) = @_; | ||||
2402 | if ($value eq '') { | ||||
2403 | return $MISSING_REQUIRED_VALUE; | ||||
2404 | } | ||||
2405 | push(@{$self->{report_safe_copy_headers}}, split(/\s+/, $value)); | ||||
2406 | } | ||||
2407 | 1 | 16µs | }); | ||
2408 | |||||
2409 | =item envelope_sender_header Name-Of-Header | ||||
2410 | |||||
2411 | SpamAssassin will attempt to discover the address used in the 'MAIL FROM:' | ||||
2412 | phase of the SMTP transaction that delivered this message, if this data has | ||||
2413 | been made available by the SMTP server. This is used in the C<EnvelopeFrom> | ||||
2414 | pseudo-header, and for various rules such as SPF checking. | ||||
2415 | |||||
2416 | By default, various MTAs will use different headers, such as the following: | ||||
2417 | |||||
2418 | X-Envelope-From | ||||
2419 | Envelope-Sender | ||||
2420 | X-Sender | ||||
2421 | Return-Path | ||||
2422 | |||||
2423 | SpamAssassin will attempt to use these, if some heuristics (such as the header | ||||
2424 | placement in the message, or the absence of fetchmail signatures) appear to | ||||
2425 | indicate that they are safe to use. However, it may choose the wrong headers | ||||
2426 | in some mailserver configurations. (More discussion of this can be found | ||||
2427 | in bug 2142 and bug 4747 in the SpamAssassin BugZilla.) | ||||
2428 | |||||
2429 | To avoid this heuristic failure, the C<envelope_sender_header> setting may be | ||||
2430 | helpful. Name the header that your MTA or MDA adds to messages containing the | ||||
2431 | address used at the MAIL FROM step of the SMTP transaction. | ||||
2432 | |||||
2433 | If the header in question contains C<E<lt>> or C<E<gt>> characters at the start | ||||
2434 | and end of the email address in the right-hand side, as in the SMTP | ||||
2435 | transaction, these will be stripped. | ||||
2436 | |||||
2437 | If the header is not found in a message, or if it's value does not contain an | ||||
2438 | C<@> sign, SpamAssassin will issue a warning in the logs and fall back to its | ||||
2439 | default heuristics. | ||||
2440 | |||||
2441 | (Note for MTA developers: we would prefer if the use of a single header be | ||||
2442 | avoided in future, since that precludes 'downstream' spam scanning. | ||||
2443 | C<http://wiki.apache.org/spamassassin/EnvelopeSenderInReceived> details a | ||||
2444 | better proposal, storing the envelope sender at each hop in the C<Received> | ||||
2445 | header.) | ||||
2446 | |||||
2447 | example: | ||||
2448 | |||||
2449 | envelope_sender_header X-SA-Exim-Mail-From | ||||
2450 | |||||
2451 | =cut | ||||
2452 | |||||
2453 | 1 | 5µs | push (@cmds, { | ||
2454 | setting => 'envelope_sender_header', | ||||
2455 | default => undef, | ||||
2456 | type => $CONF_TYPE_STRING, | ||||
2457 | }); | ||||
2458 | |||||
2459 | =item describe SYMBOLIC_TEST_NAME description ... | ||||
2460 | |||||
2461 | Used to describe a test. This text is shown to users in the detailed report. | ||||
2462 | |||||
2463 | Note that test names which begin with '__' are reserved for meta-match | ||||
2464 | sub-rules, and are not scored or listed in the 'tests hit' reports. | ||||
2465 | |||||
2466 | Also note that by convention, rule descriptions should be limited in | ||||
2467 | length to no more than 50 characters. | ||||
2468 | |||||
2469 | =cut | ||||
2470 | |||||
2471 | 1 | 11µs | push (@cmds, { | ||
2472 | command => 'describe', | ||||
2473 | setting => 'descriptions', | ||||
2474 | is_frequent => 1, | ||||
2475 | type => $CONF_TYPE_HASH_KEY_VALUE, | ||||
2476 | }); | ||||
2477 | |||||
2478 | =item report_charset CHARSET (default: unset) | ||||
2479 | |||||
2480 | Set the MIME Content-Type charset used for the text/plain report which | ||||
2481 | is attached to spam mail messages. | ||||
2482 | |||||
2483 | =cut | ||||
2484 | |||||
2485 | 1 | 5µs | push (@cmds, { | ||
2486 | setting => 'report_charset', | ||||
2487 | default => '', | ||||
2488 | type => $CONF_TYPE_STRING, | ||||
2489 | }); | ||||
2490 | |||||
2491 | =item report ...some text for a report... | ||||
2492 | |||||
2493 | Set the report template which is attached to spam mail messages. See the | ||||
2494 | C<10_default_prefs.cf> configuration file in C</usr/share/spamassassin> for an | ||||
2495 | example. | ||||
2496 | |||||
2497 | If you change this, try to keep it under 78 columns. Each C<report> | ||||
2498 | line appends to the existing template, so use C<clear_report_template> | ||||
2499 | to restart. | ||||
2500 | |||||
2501 | Tags can be included as explained above. | ||||
2502 | |||||
2503 | =cut | ||||
2504 | |||||
2505 | 1 | 6µs | push (@cmds, { | ||
2506 | command => 'report', | ||||
2507 | setting => 'report_template', | ||||
2508 | default => '', | ||||
2509 | type => $CONF_TYPE_TEMPLATE, | ||||
2510 | }); | ||||
2511 | |||||
2512 | =item clear_report_template | ||||
2513 | |||||
2514 | Clear the report template. | ||||
2515 | |||||
2516 | =cut | ||||
2517 | |||||
2518 | 1 | 7µs | push (@cmds, { | ||
2519 | command => 'clear_report_template', | ||||
2520 | setting => 'report_template', | ||||
2521 | type => $CONF_TYPE_NOARGS, | ||||
2522 | code => \&Mail::SpamAssassin::Conf::Parser::set_template_clear | ||||
2523 | }); | ||||
2524 | |||||
2525 | =item report_contact ...text of contact address... | ||||
2526 | |||||
2527 | Set what _CONTACTADDRESS_ is replaced with in the above report text. | ||||
2528 | By default, this is 'the administrator of that system', since the hostname | ||||
2529 | of the system the scanner is running on is also included. | ||||
2530 | |||||
2531 | =cut | ||||
2532 | |||||
2533 | 1 | 5µs | push (@cmds, { | ||
2534 | setting => 'report_contact', | ||||
2535 | default => 'the administrator of that system', | ||||
2536 | type => $CONF_TYPE_STRING, | ||||
2537 | }); | ||||
2538 | |||||
2539 | =item report_hostname ...hostname to use... | ||||
2540 | |||||
2541 | Set what _HOSTNAME_ is replaced with in the above report text. | ||||
2542 | By default, this is determined dynamically as whatever the host running | ||||
2543 | SpamAssassin calls itself. | ||||
2544 | |||||
2545 | =cut | ||||
2546 | |||||
2547 | 1 | 5µs | push (@cmds, { | ||
2548 | setting => 'report_hostname', | ||||
2549 | default => '', | ||||
2550 | type => $CONF_TYPE_STRING, | ||||
2551 | }); | ||||
2552 | |||||
2553 | =item unsafe_report ...some text for a report... | ||||
2554 | |||||
2555 | Set the report template which is attached to spam mail messages which contain a | ||||
2556 | non-text/plain part. See the C<10_default_prefs.cf> configuration file in | ||||
2557 | C</usr/share/spamassassin> for an example. | ||||
2558 | |||||
2559 | Each C<unsafe-report> line appends to the existing template, so use | ||||
2560 | C<clear_unsafe_report_template> to restart. | ||||
2561 | |||||
2562 | Tags can be used in this template (see above for details). | ||||
2563 | |||||
2564 | =cut | ||||
2565 | |||||
2566 | 1 | 6µs | push (@cmds, { | ||
2567 | command => 'unsafe_report', | ||||
2568 | setting => 'unsafe_report_template', | ||||
2569 | default => '', | ||||
2570 | type => $CONF_TYPE_TEMPLATE, | ||||
2571 | }); | ||||
2572 | |||||
2573 | =item clear_unsafe_report_template | ||||
2574 | |||||
2575 | Clear the unsafe_report template. | ||||
2576 | |||||
2577 | =cut | ||||
2578 | |||||
2579 | 1 | 6µs | push (@cmds, { | ||
2580 | command => 'clear_unsafe_report_template', | ||||
2581 | setting => 'unsafe_report_template', | ||||
2582 | type => $CONF_TYPE_NOARGS, | ||||
2583 | code => \&Mail::SpamAssassin::Conf::Parser::set_template_clear | ||||
2584 | }); | ||||
2585 | |||||
2586 | =item mbox_format_from_regex | ||||
2587 | |||||
2588 | Set a specific regular expression to be used for mbox file From separators. | ||||
2589 | |||||
2590 | For example, this setting will allow sa-learn to process emails stored in | ||||
2591 | a kmail 2 mbox: | ||||
2592 | |||||
2593 | mbox_format_from_regex /^From \S+ ?[[:upper:]][[:lower:]]{2}(?:, \d\d [[:upper:]][[:lower:]]{2} \d{4} [0-2]\d:\d\d:\d\d [+-]\d{4}| [[:upper:]][[:lower:]]{2} [ 1-3]\d [ 0-2]\d:\d\d:\d\d \d{4})/ | ||||
2594 | |||||
2595 | |||||
2596 | =cut | ||||
2597 | |||||
2598 | 1 | 4µs | push (@cmds, { | ||
2599 | setting => 'mbox_format_from_regex', | ||||
2600 | type => $CONF_TYPE_STRING | ||||
2601 | }); | ||||
2602 | |||||
2603 | |||||
2604 | =item parse_dkim_uris ( 0 | 1 ) (default: 0) | ||||
2605 | |||||
2606 | If this option is set to 1 and the message contains DKIM headers, the headers will be parsed for URIs to process alongside URIs found in the body with some rules and moduels (ex. URIDNSBL) | ||||
2607 | |||||
2608 | =cut | ||||
2609 | |||||
2610 | 1 | 5µs | push (@cmds, { | ||
2611 | setting => 'parse_dkim_uris', | ||||
2612 | default => 0, | ||||
2613 | type => $CONF_TYPE_BOOL, | ||||
2614 | }); | ||||
2615 | |||||
2616 | =back | ||||
2617 | |||||
2618 | =head1 RULE DEFINITIONS AND PRIVILEGED SETTINGS | ||||
2619 | |||||
2620 | These settings differ from the ones above, in that they are considered | ||||
2621 | 'privileged'. Only users running C<spamassassin> from their procmailrc's or | ||||
2622 | forward files, or sysadmins editing a file in C</etc/mail/spamassassin>, can | ||||
2623 | use them. C<spamd> users cannot use them in their C<user_prefs> files, for | ||||
2624 | security and efficiency reasons, unless C<allow_user_rules> is enabled (and | ||||
2625 | then, they may only add rules from below). | ||||
2626 | |||||
2627 | =over 4 | ||||
2628 | |||||
2629 | =item allow_user_rules ( 0 | 1 ) (default: 0) | ||||
2630 | |||||
2631 | This setting allows users to create rules (and only rules) in their | ||||
2632 | C<user_prefs> files for use with C<spamd>. It defaults to off, because | ||||
2633 | this could be a severe security hole. It may be possible for users to | ||||
2634 | gain root level access if C<spamd> is run as root. It is NOT a good | ||||
2635 | idea, unless you have some other way of ensuring that users' tests are | ||||
2636 | safe. Don't use this unless you are certain you know what you are | ||||
2637 | doing. Furthermore, this option causes spamassassin to recompile all | ||||
2638 | the tests each time it processes a message for a user with a rule in | ||||
2639 | his/her C<user_prefs> file, which could have a significant effect on | ||||
2640 | server load. It is not recommended. | ||||
2641 | |||||
2642 | Note that it is not currently possible to use C<allow_user_rules> to modify an | ||||
2643 | existing system rule from a C<user_prefs> file with C<spamd>. | ||||
2644 | |||||
2645 | =cut | ||||
2646 | |||||
2647 | push (@cmds, { | ||||
2648 | setting => 'allow_user_rules', | ||||
2649 | is_priv => 1, | ||||
2650 | default => 0, | ||||
2651 | type => $CONF_TYPE_BOOL, | ||||
2652 | code => sub { | ||||
2653 | my ($self, $key, $value, $line) = @_; | ||||
2654 | if ($value eq '') { | ||||
2655 | return $MISSING_REQUIRED_VALUE; | ||||
2656 | } | ||||
2657 | elsif ($value !~ /^[01]$/) { | ||||
2658 | return $INVALID_VALUE; | ||||
2659 | } | ||||
2660 | |||||
2661 | $self->{allow_user_rules} = $value+0; | ||||
2662 | dbg("config: " . ($self->{allow_user_rules} ? "allowing":"not allowing") . " user rules!"); | ||||
2663 | } | ||||
2664 | 1 | 12µs | }); | ||
2665 | |||||
2666 | =item redirector_pattern /pattern/modifiers | ||||
2667 | |||||
2668 | A regex pattern that matches both the redirector site portion, and | ||||
2669 | the target site portion of a URI. | ||||
2670 | |||||
2671 | Note: The target URI portion must be surrounded in parentheses and | ||||
2672 | no other part of the pattern may create a backreference. | ||||
2673 | |||||
2674 | Example: http://chkpt.zdnet.com/chkpt/whatever/spammer.domain/yo/dude | ||||
2675 | |||||
2676 | redirector_pattern /^https?:\/\/(?:opt\.)?chkpt\.zdnet\.com\/chkpt\/\w+\/(.*)$/i | ||||
2677 | |||||
2678 | =cut | ||||
2679 | |||||
2680 | push (@cmds, { | ||||
2681 | setting => 'redirector_pattern', | ||||
2682 | is_priv => 1, | ||||
2683 | # spent 5.28ms (1.13+4.14) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2701] which was called 15 times, avg 352µs/call:
# 15 times (1.13ms+4.14ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 352µs/call | ||||
2684 | 15 | 82µs | my ($self, $key, $value, $line) = @_; | ||
2685 | 15 | 122µs | 15 | 3.36ms | if ($value eq '') { # spent 3.36ms making 15 calls to Mail::SpamAssassin::Conf::Parser::is_delimited_regexp_valid, avg 224µs/call |
2686 | return $MISSING_REQUIRED_VALUE; | ||||
2687 | } | ||||
2688 | elsif (!$self->{parser}->is_delimited_regexp_valid("redirector_pattern", $value)) { | ||||
2689 | return $INVALID_VALUE; | ||||
2690 | } | ||||
2691 | |||||
2692 | # convert to qr// while including modifiers | ||||
2693 | 15 | 65µs | local ($1,$2,$3); | ||
2694 | 15 | 223µs | 15 | 95µs | $value =~ /^m?(\W)(.*)(?:\1|>|}|\)|\])(.*?)$/; # spent 95µs making 15 calls to Mail::SpamAssassin::Conf::CORE:match, avg 6µs/call |
2695 | 15 | 59µs | my $pattern = $2; | ||
2696 | 15 | 79µs | $pattern = "(?".$3.")".$pattern if $3; | ||
2697 | 15 | 952µs | 30 | 687µs | $pattern = qr/$pattern/; # spent 584µs making 15 calls to Mail::SpamAssassin::Conf::CORE:regcomp, avg 39µs/call
# spent 103µs making 15 calls to Mail::SpamAssassin::Conf::CORE:qr, avg 7µs/call |
2698 | |||||
2699 | 30 | 317µs | push @{$self->{main}->{conf}->{redirector_patterns}}, $pattern; | ||
2700 | # dbg("config: adding redirector regex: " . $value); | ||||
2701 | } | ||||
2702 | 1 | 16µs | }); | ||
2703 | |||||
2704 | =item header SYMBOLIC_TEST_NAME header op /pattern/modifiers [if-unset: STRING] | ||||
2705 | |||||
2706 | Define a test. C<SYMBOLIC_TEST_NAME> is a symbolic test name, such as | ||||
2707 | 'FROM_ENDS_IN_NUMS'. C<header> is the name of a mail header field, | ||||
2708 | such as 'Subject', 'To', 'From', etc. Header field names are matched | ||||
2709 | case-insensitively (conforming to RFC 5322 section 1.2.2), except for | ||||
2710 | all-capitals metaheader fields such as ALL, MESSAGEID, ALL-TRUSTED. | ||||
2711 | |||||
2712 | Appending a modifier C<:raw> to a header field name will inhibit decoding of | ||||
2713 | quoted-printable or base-64 encoded strings, and will preserve all whitespace | ||||
2714 | inside the header string. The C<:raw> may also be applied to pseudo-headers | ||||
2715 | e.g. C<ALL:raw> will return a pristine (unmodified) header section. | ||||
2716 | |||||
2717 | Appending a modifier C<:addr> to a header field name will cause everything | ||||
2718 | except the first email address to be removed from the header field. It is | ||||
2719 | mainly applicable to header fields 'From', 'Sender', 'To', 'Cc' along with | ||||
2720 | their 'Resent-*' counterparts, and the 'Return-Path'. | ||||
2721 | |||||
2722 | Appending a modifier C<:name> to a header field name will cause everything | ||||
2723 | except the first display name to be removed from the header field. It is | ||||
2724 | mainly applicable to header fields containing a single mail address: 'From', | ||||
2725 | 'Sender', along with their 'Resent-From' and 'Resent-Sender' counterparts. | ||||
2726 | |||||
2727 | It is syntactically permitted to append more than one modifier to a header | ||||
2728 | field name, although currently most combinations achieve no additional effect, | ||||
2729 | for example C<From:addr:raw> or C<From:raw:addr> is currently the same as | ||||
2730 | C<From:addr> . | ||||
2731 | |||||
2732 | For example, appending C<:addr> to a header name will result in example@foo | ||||
2733 | in all of the following cases: | ||||
2734 | |||||
2735 | =over 4 | ||||
2736 | |||||
2737 | =item example@foo | ||||
2738 | |||||
2739 | =item example@foo (Foo Blah) | ||||
2740 | |||||
2741 | =item example@foo, example@bar | ||||
2742 | |||||
2743 | =item display: example@foo (Foo Blah), example@bar ; | ||||
2744 | |||||
2745 | =item Foo Blah <example@foo> | ||||
2746 | |||||
2747 | =item "Foo Blah" <example@foo> | ||||
2748 | |||||
2749 | =item "'Foo Blah'" <example@foo> | ||||
2750 | |||||
2751 | =back | ||||
2752 | |||||
2753 | For example, appending C<:name> to a header name will result in "Foo Blah" | ||||
2754 | (without quotes) in all of the following cases: | ||||
2755 | |||||
2756 | =over 4 | ||||
2757 | |||||
2758 | =item example@foo (Foo Blah) | ||||
2759 | |||||
2760 | =item example@foo (Foo Blah), example@bar | ||||
2761 | |||||
2762 | =item display: example@foo (Foo Blah), example@bar ; | ||||
2763 | |||||
2764 | =item Foo Blah <example@foo> | ||||
2765 | |||||
2766 | =item "Foo Blah" <example@foo> | ||||
2767 | |||||
2768 | =item "'Foo Blah'" <example@foo> | ||||
2769 | |||||
2770 | =back | ||||
2771 | |||||
2772 | There are several special pseudo-headers that can be specified: | ||||
2773 | |||||
2774 | =over 4 | ||||
2775 | |||||
2776 | =item C<ALL> can be used to mean the text of all the message's headers. | ||||
2777 | Note that all whitespace inside the headers, at line folds, is currently | ||||
2778 | compressed into a single space (' ') character. To obtain a pristine | ||||
2779 | (unmodified) header section, use C<ALL:raw> - the :raw modifier is documented | ||||
2780 | above. | ||||
2781 | |||||
2782 | =item C<ToCc> can be used to mean the contents of both the 'To' and 'Cc' | ||||
2783 | headers. | ||||
2784 | |||||
2785 | =item C<EnvelopeFrom> is the address used in the 'MAIL FROM:' phase of the SMTP | ||||
2786 | transaction that delivered this message, if this data has been made available | ||||
2787 | by the SMTP server. See C<envelope_sender_header> for more information | ||||
2788 | on how to set this. | ||||
2789 | |||||
2790 | =item C<MESSAGEID> is a symbol meaning all Message-Id's found in the message; | ||||
2791 | some mailing list software moves the real 'Message-Id' to 'Resent-Message-Id' | ||||
2792 | or to 'X-Message-Id', then uses its own one in the 'Message-Id' header. | ||||
2793 | The value returned for this symbol is the text from all 3 headers, separated | ||||
2794 | by newlines. | ||||
2795 | |||||
2796 | =item C<X-Spam-Relays-Untrusted>, C<X-Spam-Relays-Trusted>, | ||||
2797 | C<X-Spam-Relays-Internal> and C<X-Spam-Relays-External> represent a portable, | ||||
2798 | pre-parsed representation of the message's network path, as recorded in the | ||||
2799 | Received headers, divided into 'trusted' vs 'untrusted' and 'internal' vs | ||||
2800 | 'external' sets. See C<http://wiki.apache.org/spamassassin/TrustedRelays> for | ||||
2801 | more details. | ||||
2802 | |||||
2803 | =back | ||||
2804 | |||||
2805 | C<op> is either C<=~> (contains regular expression) or C<!~> (does not contain | ||||
2806 | regular expression), and C<pattern> is a valid Perl regular expression, with | ||||
2807 | C<modifiers> as regexp modifiers in the usual style. Note that multi-line | ||||
2808 | rules are not supported, even if you use C<x> as a modifier. Also note that | ||||
2809 | the C<#> character must be escaped (C<\#>) or else it will be considered to be | ||||
2810 | the start of a comment and not part of the regexp. | ||||
2811 | |||||
2812 | If the C<[if-unset: STRING]> tag is present, then C<STRING> will | ||||
2813 | be used if the header is not found in the mail message. | ||||
2814 | |||||
2815 | Test names must not start with a number, and must contain only | ||||
2816 | alphanumerics and underscores. It is suggested that lower-case characters | ||||
2817 | not be used, and names have a length of no more than 22 characters, | ||||
2818 | as an informal convention. Dashes are not allowed. | ||||
2819 | |||||
2820 | Note that test names which begin with '__' are reserved for meta-match | ||||
2821 | sub-rules, and are not scored or listed in the 'tests hit' reports. | ||||
2822 | Test names which begin with 'T_' are reserved for tests which are | ||||
2823 | undergoing QA, and these are given a very low score. | ||||
2824 | |||||
2825 | If you add or modify a test, please be sure to run a sanity check afterwards | ||||
2826 | by running C<spamassassin --lint>. This will avoid confusing error | ||||
2827 | messages, or other tests being skipped as a side-effect. | ||||
2828 | |||||
2829 | =item header SYMBOLIC_TEST_NAME exists:header_field_name | ||||
2830 | |||||
2831 | Define a header field existence test. C<header_field_name> is the name | ||||
2832 | of a header field to test for existence. Not to be confused with a | ||||
2833 | test for a nonempty header field body, which can be implemented by a | ||||
2834 | C<header SYMBOLIC_TEST_NAME header =~ /\S/> rule as described above. | ||||
2835 | |||||
2836 | =item header SYMBOLIC_TEST_NAME eval:name_of_eval_method([arguments]) | ||||
2837 | |||||
2838 | Define a header eval test. C<name_of_eval_method> is the name of | ||||
2839 | a method on the C<Mail::SpamAssassin::EvalTests> object. C<arguments> | ||||
2840 | are optional arguments to the function call. | ||||
2841 | |||||
2842 | =item header SYMBOLIC_TEST_NAME eval:check_rbl('set', 'zone' [, 'sub-test']) | ||||
2843 | |||||
2844 | Check a DNSBL (a DNS blacklist or whitelist). This will retrieve Received: | ||||
2845 | headers from the message, extract the IP addresses, select which ones are | ||||
2846 | 'untrusted' based on the C<trusted_networks> logic, and query that DNSBL | ||||
2847 | zone. There's a few things to note: | ||||
2848 | |||||
2849 | =over 4 | ||||
2850 | |||||
2851 | =item duplicated or private IPs | ||||
2852 | |||||
2853 | Duplicated IPs are only queried once and reserved IPs are not queried. | ||||
2854 | Private IPs are those listed in | ||||
2855 | <http://www.iana.org/assignments/ipv4-address-space>, | ||||
2856 | <http://duxcw.com/faq/network/privip.htm>, | ||||
2857 | <http://duxcw.com/faq/network/autoip.htm>, or | ||||
2858 | <http://tools.ietf.org/html/rfc5735> as private. | ||||
2859 | |||||
2860 | =item the 'set' argument | ||||
2861 | |||||
2862 | This is used as a 'zone ID'. If you want to look up a multiple-meaning zone | ||||
2863 | like SORBS, you can then query the results from that zone using it; | ||||
2864 | but all check_rbl_sub() calls must use that zone ID. | ||||
2865 | |||||
2866 | Also, if more than one IP address gets a DNSBL hit for a particular rule, it | ||||
2867 | does not affect the score because rules only trigger once per message. | ||||
2868 | |||||
2869 | =item the 'zone' argument | ||||
2870 | |||||
2871 | This is the root zone of the DNSBL. | ||||
2872 | |||||
2873 | The domain name is considered to be a fully qualified domain name | ||||
2874 | (i.e. not subject to DNS resolver's search or default domain options). | ||||
2875 | No trailing period is needed, and will be removed if specified. | ||||
2876 | |||||
2877 | =item the 'sub-test' argument | ||||
2878 | |||||
2879 | This optional argument behaves the same as the sub-test argument in | ||||
2880 | C<check_rbl_sub()> below. | ||||
2881 | |||||
2882 | =item selecting all IPs except for the originating one | ||||
2883 | |||||
2884 | This is accomplished by placing '-notfirsthop' at the end of the set name. | ||||
2885 | This is useful for querying against DNS lists which list dialup IP | ||||
2886 | addresses; the first hop may be a dialup, but as long as there is at least | ||||
2887 | one more hop, via their outgoing SMTP server, that's legitimate, and so | ||||
2888 | should not gain points. If there is only one hop, that will be queried | ||||
2889 | anyway, as it should be relaying via its outgoing SMTP server instead of | ||||
2890 | sending directly to your MX (mail exchange). | ||||
2891 | |||||
2892 | =item selecting IPs by whether they are trusted | ||||
2893 | |||||
2894 | When checking a 'nice' DNSBL (a DNS whitelist), you cannot trust the IP | ||||
2895 | addresses in Received headers that were not added by trusted relays. To | ||||
2896 | test the first IP address that can be trusted, place '-firsttrusted' at the | ||||
2897 | end of the set name. That should test the IP address of the relay that | ||||
2898 | connected to the most remote trusted relay. | ||||
2899 | |||||
2900 | Note that this requires that SpamAssassin know which relays are trusted. For | ||||
2901 | simple cases, SpamAssassin can make a good estimate. For complex cases, you | ||||
2902 | may get better results by setting C<trusted_networks> manually. | ||||
2903 | |||||
2904 | In addition, you can test all untrusted IP addresses by placing '-untrusted' | ||||
2905 | at the end of the set name. Important note -- this does NOT include the | ||||
2906 | IP address from the most recent 'untrusted line', as used in '-firsttrusted' | ||||
2907 | above. That's because we're talking about the trustworthiness of the | ||||
2908 | IP address data, not the source header line, here; and in the case of | ||||
2909 | the most recent header (the 'firsttrusted'), that data can be trusted. | ||||
2910 | See the Wiki page at C<http://wiki.apache.org/spamassassin/TrustedRelays> | ||||
2911 | for more information on this. | ||||
2912 | |||||
2913 | =item Selecting just the last external IP | ||||
2914 | |||||
2915 | By using '-lastexternal' at the end of the set name, you can select only | ||||
2916 | the external host that connected to your internal network, or at least | ||||
2917 | the last external host with a public IP. | ||||
2918 | |||||
2919 | =back | ||||
2920 | |||||
2921 | =item header SYMBOLIC_TEST_NAME eval:check_rbl_txt('set', 'zone') | ||||
2922 | |||||
2923 | Same as check_rbl(), except querying using IN TXT instead of IN A records. | ||||
2924 | If the zone supports it, it will result in a line of text describing | ||||
2925 | why the IP is listed, typically a hyperlink to a database entry. | ||||
2926 | |||||
2927 | =item header SYMBOLIC_TEST_NAME eval:check_rbl_sub('set', 'sub-test') | ||||
2928 | |||||
2929 | Create a sub-test for 'set'. If you want to look up a multi-meaning zone | ||||
2930 | like relays.osirusoft.com, you can then query the results from that zone | ||||
2931 | using the zone ID from the original query. The sub-test may either be an | ||||
2932 | IPv4 dotted address for RBLs that return multiple A records or a | ||||
2933 | non-negative decimal number to specify a bitmask for RBLs that return a | ||||
2934 | single A record containing a bitmask of results, a SenderBase test | ||||
2935 | beginning with "sb:", or (if none of the preceding options seem to fit) a | ||||
2936 | regular expression. | ||||
2937 | |||||
2938 | Note: the set name must be exactly the same for as the main query rule, | ||||
2939 | including selections like '-notfirsthop' appearing at the end of the set | ||||
2940 | name. | ||||
2941 | |||||
2942 | =cut | ||||
2943 | |||||
2944 | push (@cmds, { | ||||
2945 | setting => 'header', | ||||
2946 | is_frequent => 1, | ||||
2947 | is_priv => 1, | ||||
2948 | # spent 324ms (58.6+266) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] which was called 781 times, avg 415µs/call:
# 781 times (58.6ms+266ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 415µs/call | ||||
2949 | 781 | 5.29ms | my ($self, $key, $value, $line) = @_; | ||
2950 | 781 | 3.24ms | local ($1,$2); | ||
2951 | 781 | 44.1ms | 1387 | 4.82ms | if ($value =~ /^(\S+)\s+(?:rbl)?eval:(.*)$/) { # spent 4.82ms making 1387 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
2952 | 175 | 834µs | my ($rulename, $fn) = ($1, $2); | ||
2953 | |||||
2954 | 175 | 2.58ms | 175 | 637µs | if ($fn =~ /^check_(?:rbl|dns)/) { # spent 637µs making 175 calls to Mail::SpamAssassin::Conf::CORE:match, avg 4µs/call |
2955 | 73 | 578µs | 73 | 6.04ms | $self->{parser}->add_test ($rulename, $fn, $TYPE_RBL_EVALS); # spent 6.04ms making 73 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 83µs/call |
2956 | } | ||||
2957 | else { | ||||
2958 | 102 | 792µs | 102 | 7.59ms | $self->{parser}->add_test ($rulename, $fn, $TYPE_HEAD_EVALS); # spent 7.59ms making 102 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 74µs/call |
2959 | } | ||||
2960 | } | ||||
2961 | elsif ($value =~ /^(\S+)\s+exists:(.*)$/) { | ||||
2962 | 58 | 271µs | my ($rulename, $header_name) = ($1, $2); | ||
2963 | # RFC 5322 section 3.6.8, ftext printable US-ASCII ch not including ":" | ||||
2964 | 58 | 1.27ms | 116 | 513µs | if ($header_name !~ /\S/) { # spent 513µs making 116 calls to Mail::SpamAssassin::Conf::CORE:match, avg 4µs/call |
2965 | return $MISSING_REQUIRED_VALUE; | ||||
2966 | # } elsif ($header_name !~ /^([!-9;-\176]+)$/) { | ||||
2967 | } elsif ($header_name !~ /^([^: \t]+)$/) { # be generous | ||||
2968 | return $INVALID_HEADER_FIELD_NAME; | ||||
2969 | } | ||||
2970 | 58 | 728µs | 58 | 5.29ms | $self->{parser}->add_test ($rulename, "defined($header_name)", # spent 5.29ms making 58 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 91µs/call |
2971 | $TYPE_HEAD_TESTS); | ||||
2972 | 58 | 1.46ms | 116 | 12.1ms | $self->{descriptions}->{$rulename} = "Found a $header_name header"; # spent 6.73ms making 58 calls to Mail::SpamAssassin::Util::TieOneStringHash::STORE, avg 116µs/call
# spent 5.42ms making 58 calls to Mail::SpamAssassin::Util::TieOneStringHash::FETCH, avg 93µs/call |
2973 | } | ||||
2974 | else { | ||||
2975 | 548 | 4.03ms | my @values = split(/\s+/, $value, 2); | ||
2976 | 548 | 1.19ms | if (@values != 2) { | ||
2977 | return $MISSING_REQUIRED_VALUE; | ||||
2978 | } | ||||
2979 | 548 | 4.89ms | 548 | 229ms | $self->{parser}->add_test (@values, $TYPE_HEAD_TESTS); # spent 229ms making 548 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 417µs/call |
2980 | } | ||||
2981 | } | ||||
2982 | 1 | 20µs | }); | ||
2983 | |||||
2984 | =item body SYMBOLIC_TEST_NAME /pattern/modifiers | ||||
2985 | |||||
2986 | Define a body pattern test. C<pattern> is a Perl regular expression. Note: | ||||
2987 | as per the header tests, C<#> must be escaped (C<\#>) or else it is considered | ||||
2988 | the beginning of a comment. | ||||
2989 | |||||
2990 | The 'body' in this case is the textual parts of the message body; | ||||
2991 | any non-text MIME parts are stripped, and the message decoded from | ||||
2992 | Quoted-Printable or Base-64-encoded format if necessary. The message | ||||
2993 | Subject header is considered part of the body and becomes the first | ||||
2994 | paragraph when running the rules. All HTML tags and line breaks will | ||||
2995 | be removed before matching. | ||||
2996 | |||||
2997 | =item body SYMBOLIC_TEST_NAME eval:name_of_eval_method([args]) | ||||
2998 | |||||
2999 | Define a body eval test. See above. | ||||
3000 | |||||
3001 | =cut | ||||
3002 | |||||
3003 | push (@cmds, { | ||||
3004 | setting => 'body', | ||||
3005 | is_frequent => 1, | ||||
3006 | is_priv => 1, | ||||
3007 | # spent 233ms (30.6+202) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3020] which was called 655 times, avg 356µs/call:
# 655 times (30.6ms+202ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 356µs/call | ||||
3008 | 655 | 3.64ms | my ($self, $key, $value, $line) = @_; | ||
3009 | 655 | 2.47ms | local ($1,$2); | ||
3010 | 655 | 16.2ms | 655 | 2.78ms | if ($value =~ /^(\S+)\s+eval:(.*)$/) { # spent 2.78ms making 655 calls to Mail::SpamAssassin::Conf::CORE:match, avg 4µs/call |
3011 | 142 | 1.07ms | 142 | 19.5ms | $self->{parser}->add_test ($1, $2, $TYPE_BODY_EVALS); # spent 19.5ms making 142 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 137µs/call |
3012 | } | ||||
3013 | else { | ||||
3014 | 513 | 3.37ms | my @values = split(/\s+/, $value, 2); | ||
3015 | 513 | 1.04ms | if (@values != 2) { | ||
3016 | return $MISSING_REQUIRED_VALUE; | ||||
3017 | } | ||||
3018 | 513 | 4.40ms | 513 | 180ms | $self->{parser}->add_test (@values, $TYPE_BODY_TESTS); # spent 180ms making 513 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 351µs/call |
3019 | } | ||||
3020 | } | ||||
3021 | 1 | 11µs | }); | ||
3022 | |||||
3023 | =item uri SYMBOLIC_TEST_NAME /pattern/modifiers | ||||
3024 | |||||
3025 | Define a uri pattern test. C<pattern> is a Perl regular expression. Note: as | ||||
3026 | per the header tests, C<#> must be escaped (C<\#>) or else it is considered | ||||
3027 | the beginning of a comment. | ||||
3028 | |||||
3029 | The 'uri' in this case is a list of all the URIs in the body of the email, | ||||
3030 | and the test will be run on each and every one of those URIs, adjusting the | ||||
3031 | score if a match is found. Use this test instead of one of the body tests | ||||
3032 | when you need to match a URI, as it is more accurately bound to the start/end | ||||
3033 | points of the URI, and will also be faster. | ||||
3034 | |||||
3035 | =cut | ||||
3036 | |||||
3037 | # we don't do URI evals yet - maybe later | ||||
3038 | # if (/^uri\s+(\S+)\s+eval:(.*)$/) { | ||||
3039 | # $self->{parser}->add_test ($1, $2, $TYPE_URI_EVALS); | ||||
3040 | # next; | ||||
3041 | # } | ||||
3042 | push (@cmds, { | ||||
3043 | setting => 'uri', | ||||
3044 | is_priv => 1, | ||||
3045 | # spent 24.1ms (2.43+21.7) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3052] which was called 71 times, avg 340µs/call:
# 71 times (2.43ms+21.7ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 340µs/call | ||||
3046 | 71 | 396µs | my ($self, $key, $value, $line) = @_; | ||
3047 | 71 | 451µs | my @values = split(/\s+/, $value, 2); | ||
3048 | 71 | 156µs | if (@values != 2) { | ||
3049 | return $MISSING_REQUIRED_VALUE; | ||||
3050 | } | ||||
3051 | 71 | 1.15ms | 71 | 21.7ms | $self->{parser}->add_test (@values, $TYPE_URI_TESTS); # spent 21.7ms making 71 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 306µs/call |
3052 | } | ||||
3053 | 1 | 11µs | }); | ||
3054 | |||||
3055 | =item rawbody SYMBOLIC_TEST_NAME /pattern/modifiers | ||||
3056 | |||||
3057 | Define a raw-body pattern test. C<pattern> is a Perl regular expression. | ||||
3058 | Note: as per the header tests, C<#> must be escaped (C<\#>) or else it is | ||||
3059 | considered the beginning of a comment. | ||||
3060 | |||||
3061 | The 'raw body' of a message is the raw data inside all textual parts. The | ||||
3062 | text will be decoded from base64 or quoted-printable encoding, but HTML | ||||
3063 | tags and line breaks will still be present. Multiline expressions will | ||||
3064 | need to be used to match strings that are broken by line breaks. | ||||
3065 | |||||
3066 | =item rawbody SYMBOLIC_TEST_NAME eval:name_of_eval_method([args]) | ||||
3067 | |||||
3068 | Define a raw-body eval test. See above. | ||||
3069 | |||||
3070 | =cut | ||||
3071 | |||||
3072 | push (@cmds, { | ||||
3073 | setting => 'rawbody', | ||||
3074 | is_frequent => 1, | ||||
3075 | is_priv => 1, | ||||
3076 | # spent 13.9ms (2.08+11.8) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3088] which was called 40 times, avg 347µs/call:
# 40 times (2.08ms+11.8ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 347µs/call | ||||
3077 | 40 | 237µs | my ($self, $key, $value, $line) = @_; | ||
3078 | 40 | 155µs | local ($1,$2); | ||
3079 | 40 | 905µs | 40 | 149µs | if ($value =~ /^(\S+)\s+eval:(.*)$/) { # spent 149µs making 40 calls to Mail::SpamAssassin::Conf::CORE:match, avg 4µs/call |
3080 | 7 | 52µs | 7 | 401µs | $self->{parser}->add_test ($1, $2, $TYPE_RAWBODY_EVALS); # spent 401µs making 7 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 57µs/call |
3081 | } else { | ||||
3082 | 33 | 245µs | my @values = split(/\s+/, $value, 2); | ||
3083 | 33 | 76µs | if (@values != 2) { | ||
3084 | return $MISSING_REQUIRED_VALUE; | ||||
3085 | } | ||||
3086 | 33 | 297µs | 33 | 11.3ms | $self->{parser}->add_test (@values, $TYPE_RAWBODY_TESTS); # spent 11.3ms making 33 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 341µs/call |
3087 | } | ||||
3088 | } | ||||
3089 | 1 | 13µs | }); | ||
3090 | |||||
3091 | =item full SYMBOLIC_TEST_NAME /pattern/modifiers | ||||
3092 | |||||
3093 | Define a full message pattern test. C<pattern> is a Perl regular expression. | ||||
3094 | Note: as per the header tests, C<#> must be escaped (C<\#>) or else it is | ||||
3095 | considered the beginning of a comment. | ||||
3096 | |||||
3097 | The full message is the pristine message headers plus the pristine message | ||||
3098 | body, including all MIME data such as images, other attachments, MIME | ||||
3099 | boundaries, etc. | ||||
3100 | |||||
3101 | =item full SYMBOLIC_TEST_NAME eval:name_of_eval_method([args]) | ||||
3102 | |||||
3103 | Define a full message eval test. See above. | ||||
3104 | |||||
3105 | =cut | ||||
3106 | |||||
3107 | push (@cmds, { | ||||
3108 | setting => 'full', | ||||
3109 | is_priv => 1, | ||||
3110 | # spent 2.33ms (640µs+1.69) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3122] which was called 13 times, avg 179µs/call:
# 13 times (640µs+1.69ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 179µs/call | ||||
3111 | 13 | 93µs | my ($self, $key, $value, $line) = @_; | ||
3112 | 13 | 55µs | local ($1,$2); | ||
3113 | 13 | 413µs | 13 | 74µs | if ($value =~ /^(\S+)\s+eval:(.*)$/) { # spent 74µs making 13 calls to Mail::SpamAssassin::Conf::CORE:match, avg 6µs/call |
3114 | 11 | 98µs | 11 | 1.05ms | $self->{parser}->add_test ($1, $2, $TYPE_FULL_EVALS); # spent 1.05ms making 11 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 95µs/call |
3115 | } else { | ||||
3116 | 2 | 15µs | my @values = split(/\s+/, $value, 2); | ||
3117 | 2 | 5µs | if (@values != 2) { | ||
3118 | return $MISSING_REQUIRED_VALUE; | ||||
3119 | } | ||||
3120 | 2 | 18µs | 2 | 564µs | $self->{parser}->add_test (@values, $TYPE_FULL_TESTS); # spent 564µs making 2 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 282µs/call |
3121 | } | ||||
3122 | } | ||||
3123 | 1 | 10µs | }); | ||
3124 | |||||
3125 | =item meta SYMBOLIC_TEST_NAME boolean expression | ||||
3126 | |||||
3127 | Define a boolean expression test in terms of other tests that have | ||||
3128 | been hit or not hit. For example: | ||||
3129 | |||||
3130 | meta META1 TEST1 && !(TEST2 || TEST3) | ||||
3131 | |||||
3132 | Note that English language operators ("and", "or") will be treated as | ||||
3133 | rule names, and that there is no C<XOR> operator. | ||||
3134 | |||||
3135 | =item meta SYMBOLIC_TEST_NAME boolean arithmetic expression | ||||
3136 | |||||
3137 | Can also define an arithmetic expression in terms of other tests, | ||||
3138 | with an unhit test having the value "0" and a hit test having a | ||||
3139 | nonzero value. The value of a hit meta test is that of its arithmetic | ||||
3140 | expression. The value of a hit eval test is that returned by its | ||||
3141 | method. The value of a hit header, body, rawbody, uri, or full test | ||||
3142 | which has the "multiple" tflag is the number of times the test hit. | ||||
3143 | The value of any other type of hit test is "1". | ||||
3144 | |||||
3145 | For example: | ||||
3146 | |||||
3147 | meta META2 (3 * TEST1 - 2 * TEST2) > 0 | ||||
3148 | |||||
3149 | Note that Perl builtins and functions, like C<abs()>, B<can't> be | ||||
3150 | used, and will be treated as rule names. | ||||
3151 | |||||
3152 | If you want to define a meta-rule, but do not want its individual sub-rules to | ||||
3153 | count towards the final score unless the entire meta-rule matches, give the | ||||
3154 | sub-rules names that start with '__' (two underscores). SpamAssassin will | ||||
3155 | ignore these for scoring. | ||||
3156 | |||||
3157 | =cut | ||||
3158 | |||||
3159 | push (@cmds, { | ||||
3160 | setting => 'meta', | ||||
3161 | is_frequent => 1, | ||||
3162 | is_priv => 1, | ||||
3163 | # spent 322ms (21.5+301) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3174] which was called 465 times, avg 693µs/call:
# 465 times (21.5ms+301ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 693µs/call | ||||
3164 | 465 | 2.85ms | my ($self, $key, $value, $line) = @_; | ||
3165 | 465 | 3.43ms | my @values = split(/\s+/, $value, 2); | ||
3166 | 465 | 966µs | if (@values != 2) { | ||
3167 | return $MISSING_REQUIRED_VALUE; | ||||
3168 | } | ||||
3169 | 465 | 5.83ms | 465 | 1.46ms | if ($values[1] =~ /\*\s*\*/) { # spent 1.46ms making 465 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
3170 | info("config: found invalid '**' or '* *' operator in meta command"); | ||||
3171 | return $INVALID_VALUE; | ||||
3172 | } | ||||
3173 | 465 | 8.28ms | 465 | 299ms | $self->{parser}->add_test (@values, $TYPE_META_TESTS); # spent 299ms making 465 calls to Mail::SpamAssassin::Conf::Parser::add_test, avg 643µs/call |
3174 | } | ||||
3175 | 1 | 11µs | }); | ||
3176 | |||||
3177 | =item reuse SYMBOLIC_TEST_NAME [ OLD_SYMBOLIC_TEST_NAME_1 ... ] | ||||
3178 | |||||
3179 | Defines the name of a test that should be "reused" during the scoring | ||||
3180 | process. If a message has an X-Spam-Status header that shows a hit for | ||||
3181 | this rule or any of the old rule names given, a hit will be added for | ||||
3182 | this rule when B<mass-check --reuse> is used. Examples: | ||||
3183 | |||||
3184 | C<reuse SPF_PASS> | ||||
3185 | |||||
3186 | C<reuse MY_NET_RULE_V2 MY_NET_RULE_V1> | ||||
3187 | |||||
3188 | The actual logic for reuse tests is done by | ||||
3189 | B<Mail::SpamAssassin::Plugin::Reuse>. | ||||
3190 | |||||
3191 | =cut | ||||
3192 | |||||
3193 | push (@cmds, { | ||||
3194 | setting => 'reuse', | ||||
3195 | is_priv => 1, | ||||
3196 | # spent 2.70ms (2.22+477µs) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3206] which was called 77 times, avg 35µs/call:
# 77 times (2.22ms+477µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 35µs/call | ||||
3197 | 77 | 363µs | my ($self, $key, $value, $line) = @_; | ||
3198 | 77 | 1.20ms | 77 | 401µs | if ($value !~ /\s*(\w+)(?:\s+(?:\w+(?:\s+\w+)*))?\s*$/) { # spent 401µs making 77 calls to Mail::SpamAssassin::Conf::CORE:match, avg 5µs/call |
3199 | return $INVALID_VALUE; | ||||
3200 | } | ||||
3201 | 77 | 251µs | my $rule_name = $1; | ||
3202 | # don't overwrite tests, just define them so scores, priorities work | ||||
3203 | 77 | 1.03ms | if (!exists $self->{tests}->{$rule_name}) { | ||
3204 | 1 | 10µs | 1 | 77µs | $self->{parser}->add_test($rule_name, undef, $TYPE_EMPTY_TESTS); # spent 77µs making 1 call to Mail::SpamAssassin::Conf::Parser::add_test |
3205 | } | ||||
3206 | } | ||||
3207 | 1 | 10µs | }); | ||
3208 | |||||
3209 | =item tflags SYMBOLIC_TEST_NAME flags | ||||
3210 | |||||
3211 | Used to set flags on a test. Parameter is a space-separated list of flag | ||||
3212 | names or flag name = value pairs. | ||||
3213 | These flags are used in the score-determination back end system for details | ||||
3214 | of the test's behaviour. Please see C<bayes_auto_learn> for more information | ||||
3215 | about tflag interaction with those systems. The following flags can be set: | ||||
3216 | |||||
3217 | =over 4 | ||||
3218 | |||||
3219 | =item net | ||||
3220 | |||||
3221 | The test is a network test, and will not be run in the mass checking system | ||||
3222 | or if B<-L> is used, therefore its score should not be modified. | ||||
3223 | |||||
3224 | =item nice | ||||
3225 | |||||
3226 | The test is intended to compensate for common false positives, and should be | ||||
3227 | assigned a negative score. | ||||
3228 | |||||
3229 | =item userconf | ||||
3230 | |||||
3231 | The test requires user configuration before it can be used (like | ||||
3232 | language-specific tests). | ||||
3233 | |||||
3234 | =item learn | ||||
3235 | |||||
3236 | The test requires training before it can be used. | ||||
3237 | |||||
3238 | =item noautolearn | ||||
3239 | |||||
3240 | The test will explicitly be ignored when calculating the score for | ||||
3241 | learning systems. | ||||
3242 | |||||
3243 | =item autolearn_force | ||||
3244 | |||||
3245 | The test will be subject to less stringent autolearn thresholds. | ||||
3246 | |||||
3247 | Normally, SpamAssassin will require 3 points from the header and 3 | ||||
3248 | points from the body to be auto-learned as spam. This option keeps | ||||
3249 | the threshold at 6 points total but changes it to have no regard to the | ||||
3250 | source of the points. | ||||
3251 | |||||
3252 | =item noawl | ||||
3253 | |||||
3254 | This flag is specific when using AWL plugin. | ||||
3255 | |||||
3256 | Normally, AWL plugin normalizes scores via auto-whitelist. In some scenarios | ||||
3257 | it works against the system administrator when trying to add some rules to | ||||
3258 | correct miss-classified email. When AWL plugin searches the email and finds | ||||
3259 | the noawl flag it will exit without normalizing the score nor storing the | ||||
3260 | value in db. | ||||
3261 | |||||
3262 | =item multiple | ||||
3263 | |||||
3264 | The test will be evaluated multiple times, for use with meta rules. | ||||
3265 | Only affects header, body, rawbody, uri, and full tests. | ||||
3266 | |||||
3267 | =item maxhits=N | ||||
3268 | |||||
3269 | If B<multiple> is specified, limit the number of hits found to N. | ||||
3270 | If the rule is used in a meta that counts the hits (e.g. __RULENAME > 5), | ||||
3271 | this is a way to avoid wasted extra work (use "tflags multiple maxhits=6"). | ||||
3272 | |||||
3273 | For example: | ||||
3274 | |||||
3275 | uri __KAM_COUNT_URIS /^./ | ||||
3276 | tflags __KAM_COUNT_URIS multiple maxhits=16 | ||||
3277 | describe __KAM_COUNT_URIS A multiple match used to count URIs in a message | ||||
3278 | |||||
3279 | meta __KAM_HAS_0_URIS (__KAM_COUNT_URIS == 0) | ||||
3280 | meta __KAM_HAS_1_URIS (__KAM_COUNT_URIS >= 1) | ||||
3281 | meta __KAM_HAS_2_URIS (__KAM_COUNT_URIS >= 2) | ||||
3282 | meta __KAM_HAS_3_URIS (__KAM_COUNT_URIS >= 3) | ||||
3283 | meta __KAM_HAS_4_URIS (__KAM_COUNT_URIS >= 4) | ||||
3284 | meta __KAM_HAS_5_URIS (__KAM_COUNT_URIS >= 5) | ||||
3285 | meta __KAM_HAS_10_URIS (__KAM_COUNT_URIS >= 10) | ||||
3286 | meta __KAM_HAS_15_URIS (__KAM_COUNT_URIS >= 15) | ||||
3287 | |||||
3288 | =item ips_only | ||||
3289 | |||||
3290 | This flag is specific to rules invoking an URIDNSBL plugin, | ||||
3291 | it is documented there. | ||||
3292 | |||||
3293 | =item domains_only | ||||
3294 | |||||
3295 | This flag is specific to rules invoking an URIDNSBL plugin, | ||||
3296 | it is documented there. | ||||
3297 | |||||
3298 | =item ns | ||||
3299 | |||||
3300 | This flag is specific to rules invoking an URIDNSBL plugin, | ||||
3301 | it is documented there. | ||||
3302 | |||||
3303 | =item a | ||||
3304 | |||||
3305 | This flag is specific to rules invoking an URIDNSBL plugin, | ||||
3306 | it is documented there. | ||||
3307 | |||||
3308 | =back | ||||
3309 | |||||
3310 | =cut | ||||
3311 | |||||
3312 | 1 | 6µs | push (@cmds, { | ||
3313 | setting => 'tflags', | ||||
3314 | is_frequent => 1, | ||||
3315 | is_priv => 1, | ||||
3316 | type => $CONF_TYPE_HASH_KEY_VALUE, | ||||
3317 | }); | ||||
3318 | |||||
3319 | =item priority SYMBOLIC_TEST_NAME n | ||||
3320 | |||||
3321 | Assign a specific priority to a test. All tests, except for DNS and Meta | ||||
3322 | tests, are run in increasing priority value order (negative priority values | ||||
3323 | are run before positive priority values). The default test priority is 0 | ||||
3324 | (zero). | ||||
3325 | |||||
3326 | The values <-99999999999999> and <-99999999999998> have a special meaning | ||||
3327 | internally, and should not be used. | ||||
3328 | |||||
3329 | =cut | ||||
3330 | |||||
3331 | 1 | 6µs | push (@cmds, { | ||
3332 | setting => 'priority', | ||||
3333 | is_priv => 1, | ||||
3334 | type => $CONF_TYPE_HASH_KEY_VALUE, | ||||
3335 | }); | ||||
3336 | |||||
3337 | =back | ||||
3338 | |||||
3339 | =head1 ADMINISTRATOR SETTINGS | ||||
3340 | |||||
3341 | These settings differ from the ones above, in that they are considered 'more | ||||
3342 | privileged' -- even more than the ones in the B<PRIVILEGED SETTINGS> section. | ||||
3343 | No matter what C<allow_user_rules> is set to, these can never be set from a | ||||
3344 | user's C<user_prefs> file when spamc/spamd is being used. However, all | ||||
3345 | settings can be used by local programs run directly by the user. | ||||
3346 | |||||
3347 | =over 4 | ||||
3348 | |||||
3349 | =item version_tag string | ||||
3350 | |||||
3351 | This tag is appended to the SA version in the X-Spam-Status header. You should | ||||
3352 | include it when modify your ruleset, especially if you plan to distribute it. | ||||
3353 | A good choice for I<string> is your last name or your initials followed by a | ||||
3354 | number which you increase with each change. | ||||
3355 | |||||
3356 | The version_tag will be lowercased, and any non-alphanumeric or period | ||||
3357 | character will be replaced by an underscore. | ||||
3358 | |||||
3359 | e.g. | ||||
3360 | |||||
3361 | version_tag myrules1 # version=2.41-myrules1 | ||||
3362 | |||||
3363 | =cut | ||||
3364 | |||||
3365 | push (@cmds, { | ||||
3366 | setting => 'version_tag', | ||||
3367 | is_admin => 1, | ||||
3368 | code => sub { | ||||
3369 | my ($self, $key, $value, $line) = @_; | ||||
3370 | if ($value eq '') { | ||||
3371 | return $MISSING_REQUIRED_VALUE; | ||||
3372 | } | ||||
3373 | my $tag = lc($value); | ||||
3374 | $tag =~ tr/a-z0-9./_/c; | ||||
3375 | foreach (@Mail::SpamAssassin::EXTRA_VERSION) { | ||||
3376 | if($_ eq $tag) { $tag = undef; last; } | ||||
3377 | } | ||||
3378 | push(@Mail::SpamAssassin::EXTRA_VERSION, $tag) if($tag); | ||||
3379 | } | ||||
3380 | 1 | 10µs | }); | ||
3381 | |||||
3382 | =item test SYMBOLIC_TEST_NAME (ok|fail) Some string to test against | ||||
3383 | |||||
3384 | Define a regression testing string. You can have more than one regression test | ||||
3385 | string per symbolic test name. Simply specify a string that you wish the test | ||||
3386 | to match. | ||||
3387 | |||||
3388 | These tests are only run as part of the test suite - they should not affect the | ||||
3389 | general running of SpamAssassin. | ||||
3390 | |||||
3391 | =cut | ||||
3392 | |||||
3393 | push (@cmds, { | ||||
3394 | setting => 'test', | ||||
3395 | is_admin => 1, | ||||
3396 | # spent 215µs within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3402] which was called 36 times, avg 6µs/call:
# 36 times (215µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 6µs/call | ||||
3397 | 36 | 414µs | return unless defined $COLLECT_REGRESSION_TESTS; | ||
3398 | my ($self, $key, $value, $line) = @_; | ||||
3399 | local ($1,$2,$3); | ||||
3400 | if ($value !~ /^(\S+)\s+(ok|fail)\s+(.*)$/) { return $INVALID_VALUE; } | ||||
3401 | $self->{parser}->add_regression_test($1, $2, $3); | ||||
3402 | } | ||||
3403 | 1 | 10µs | }); | ||
3404 | |||||
3405 | =item rbl_timeout t [t_min] [zone] (default: 15 3) | ||||
3406 | |||||
3407 | All DNS queries are made at the beginning of a check and we try to read | ||||
3408 | the results at the end. This value specifies the maximum period of time | ||||
3409 | (in seconds) to wait for a DNS query. If most of the DNS queries have | ||||
3410 | succeeded for a particular message, then SpamAssassin will not wait for | ||||
3411 | the full period to avoid wasting time on unresponsive server(s), but will | ||||
3412 | shrink the timeout according to a percentage of queries already completed. | ||||
3413 | As the number of queries remaining approaches 0, the timeout value will | ||||
3414 | gradually approach a t_min value, which is an optional second parameter | ||||
3415 | and defaults to 0.2 * t. If t is smaller than t_min, the initial timeout | ||||
3416 | is set to t_min. Here is a chart of queries remaining versus the timeout | ||||
3417 | in seconds, for the default 15 second / 3 second timeout setting: | ||||
3418 | |||||
3419 | queries left 100% 90% 80% 70% 60% 50% 40% 30% 20% 10% 0% | ||||
3420 | timeout 15 14.9 14.5 13.9 13.1 12.0 10.7 9.1 7.3 5.3 3 | ||||
3421 | |||||
3422 | For example, if 20 queries are made at the beginning of a message check | ||||
3423 | and 16 queries have returned (leaving 20%), the remaining 4 queries should | ||||
3424 | finish within 7.3 seconds since their query started or they will be timed out. | ||||
3425 | Note that timed out queries are only aborted when there is nothing else left | ||||
3426 | for SpamAssassin to do - long evaluation of other rules may grant queries | ||||
3427 | additional time. | ||||
3428 | |||||
3429 | If a parameter 'zone' is specified (it must end with a letter, which | ||||
3430 | distinguishes it from other numeric parametrs), then the setting only | ||||
3431 | applies to DNS queries against the specified DNS domain (host, domain or | ||||
3432 | RBL (sub)zone). Matching is case-insensitive, the actual domain may be a | ||||
3433 | subdomain of the specified zone. | ||||
3434 | |||||
3435 | =cut | ||||
3436 | |||||
3437 | push (@cmds, { | ||||
3438 | setting => 'rbl_timeout', | ||||
3439 | is_admin => 1, | ||||
3440 | default => 15, | ||||
3441 | code => sub { | ||||
3442 | my ($self, $key, $value, $line) = @_; | ||||
3443 | unless (defined $value && $value !~ /^$/) { | ||||
3444 | return $MISSING_REQUIRED_VALUE; | ||||
3445 | } | ||||
3446 | local ($1,$2,$3); | ||||
3447 | unless ($value =~ /^ ( \+? \d+ (?: \. \d*)? [smhdw]? ) | ||||
3448 | (?: \s+ ( \+? \d+ (?: \. \d*)? [smhdw]? ) )? | ||||
3449 | (?: \s+ (\S* [a-zA-Z]) )? $/xsi) { | ||||
3450 | return $INVALID_VALUE; | ||||
3451 | } | ||||
3452 | my($timeout, $timeout_min, $zone) = ($1, $2, $3); | ||||
3453 | foreach ($timeout, $timeout_min) { | ||||
3454 | if (defined $_ && s/\s*([smhdw])\z//i) { | ||||
3455 | $_ *= { s => 1, m => 60, h => 3600, | ||||
3456 | d => 24*3600, w => 7*24*3600 }->{lc $1}; | ||||
3457 | } | ||||
3458 | } | ||||
3459 | if (!defined $zone) { # a global setting | ||||
3460 | $self->{rbl_timeout} = 0 + $timeout; | ||||
3461 | $self->{rbl_timeout_min} = 0 + $timeout_min if defined $timeout_min; | ||||
3462 | } | ||||
3463 | else { # per-zone settings | ||||
3464 | $zone =~ s/^\.//; $zone =~ s/\.\z//; # strip leading and trailing dot | ||||
3465 | $zone = lc $zone; | ||||
3466 | $self->{by_zone}{$zone}{rbl_timeout} = 0 + $timeout; | ||||
3467 | $self->{by_zone}{$zone}{rbl_timeout_min} = | ||||
3468 | 0 + $timeout_min if defined $timeout_min; | ||||
3469 | } | ||||
3470 | }, | ||||
3471 | 1 | 13µs | type => $CONF_TYPE_DURATION, | ||
3472 | }); | ||||
3473 | |||||
3474 | =item util_rb_tld tld1 tld2 ... | ||||
3475 | |||||
3476 | This option maintains list of valid TLDs in the RegistryBoundaries code. | ||||
3477 | TLDs include things like com, net, org, etc. | ||||
3478 | |||||
3479 | =cut | ||||
3480 | |||||
3481 | # DO NOT UPDATE THIS HARDCODED LIST!! It is only as fallback for | ||||
3482 | # transitional period and to be removed later. TLDs are now maintained in | ||||
3483 | # sa-update 20_aux_tlds.cf. | ||||
3484 | 1 | 112µs | foreach (qw/ | ||
3485 | ac academy accountants active actor ad ae aero af ag agency ai airforce al am an | ||||
3486 | ao aq ar archi army arpa as asia associates at attorney au auction audio autos | ||||
3487 | aw ax axa az ba bar bargains bayern bb bd be beer berlin best bf bg bh bi bid | ||||
3488 | bike bio biz bj black blackfriday blue bm bmw bn bnpparibas bo boo boutique br | ||||
3489 | brussels bs bt build builders business buzz bv bw by bz bzh ca cab camera camp | ||||
3490 | cancerresearch capetown capital caravan cards care career careers cash cat | ||||
3491 | catering cc cd center ceo cern cf cg ch cheap christmas church ci citic city ck | ||||
3492 | cl claims cleaning click clinic clothing club cm cn co codes coffee college | ||||
3493 | cologne com community company computer condos construction consulting | ||||
3494 | contractors cooking cool coop country cr credit creditcard cruises cu cuisinella | ||||
3495 | cv cw cx cy cymru cz dad dance dating day de deals degree democrat dental | ||||
3496 | dentist desi diamonds diet digital direct directory discount dj dk dm dnp do | ||||
3497 | domains durban dz eat ec edu education ee eg email engineer engineering | ||||
3498 | enterprises equipment er es esq estate et eu eus events exchange expert exposed | ||||
3499 | fail farm feedback fi finance financial fish fishing fitness fj fk flights | ||||
3500 | florist fm fo foo foundation fr frl frogans fund furniture futbol ga gal gallery | ||||
3501 | gb gbiz gd ge gent gf gg gh gi gift gifts gives gl glass global globo gm gmail | ||||
3502 | gmo gn gop gov gp gq gr graphics gratis green gripe gs gt gu guide guitars guru | ||||
3503 | gw gy hamburg haus healthcare help here hiphop hiv hk hm hn holdings holiday | ||||
3504 | homes horse host hosting house how hr ht hu id ie il im immo immobilien in | ||||
3505 | industries info ing ink institute insure int international investments io iq ir | ||||
3506 | is it je jetzt jm jo jobs joburg jp juegos kaufen ke kg kh ki kim kitchen kiwi | ||||
3507 | km kn koeln kp kr krd kred kw ky kz la lacaixa land lawyer lb lc lease lgbt li | ||||
3508 | life lighting limited limo link lk loans london lotto lr ls lt ltda lu luxe | ||||
3509 | luxury lv ly ma maison management mango market marketing mc md me media meet | ||||
3510 | melbourne meme menu mg mh miami mil mini mk ml mm mn mo mobi moda moe monash | ||||
3511 | mortgage moscow motorcycles mov mp mq mr ms mt mu museum mv mw mx my mz na | ||||
3512 | nagoya name navy nc ne net network neustar new nf ng ngo nhk ni ninja nl no np | ||||
3513 | nr nra nrw nu nyc nz okinawa om ong onl ooo org organic otsuka ovh pa paris | ||||
3514 | partners parts pe pf pg ph photo photography photos physio pics pictures pink | ||||
3515 | pizza pk pl place plumbing pm pn post pr praxi press pro prod productions | ||||
3516 | properties property ps pt pub pw py qa qpon quebec re realtor recipes red rehab | ||||
3517 | reise reisen ren rentals repair report republican rest restaurant reviews rich | ||||
3518 | rio ro rocks rodeo rs rsvp ru ruhr rw ryukyu sa saarland sarl sb sc sca scb | ||||
3519 | schmidt schule scot sd se services sexy sg sh shiksha shoes si singles sj sk sl | ||||
3520 | sm sn so social software sohu solar solutions soy space spiegel sr st su | ||||
3521 | supplies supply support surf surgery suzuki sv sx sy systems sz tatar tattoo tax | ||||
3522 | tc td technology tel tf tg th tienda tips tirol tj tk tl tm tn to today tokyo | ||||
3523 | tools top town toys tr trade training travel tt tv tw tz ua ug uk university | ||||
3524 | uno uol us uy uz va vacations vc ve vegas ventures versicherung vet vg vi viajes | ||||
3525 | villas vision vlaanderen vn vodka vote voting voto voyage vu wales wang watch | ||||
3526 | webcam website wed wf whoswho wien wiki williamhill works ws wtc wtf xn--1qqw23a | ||||
3527 | xn--3bst00m xn--3ds443g xn--3e0b707e xn--45brj9c xn--4gbrim xn--55qw42g | ||||
3528 | xn--55qx5d xn--6frz82g xn--6qq986b3xl xn--80adxhks xn--80ao21a xn--80asehdb | ||||
3529 | xn--80aswg xn--90a3ac xn--c1avg xn--cg4bki xn--clchc0ea0b2g2a9gcd xn--czr694b | ||||
3530 | xn--czru2d xn--d1acj3b xn--fiq228c5hs xn--fiq64b xn--fiqs8s xn--fiqz9s | ||||
3531 | xn--fpcrj9c3d xn--fzc2c9e2c xn--gecrj9c xn--h2brj9c xn--i1b6b1a6a2e xn--io0a7i | ||||
3532 | xn--j1amh xn--j6w193g xn--kprw13d xn--kpry57d xn--kput3i xn--l1acc | ||||
3533 | xn--lgbbat1ad8j xn--mgb9awbf xn--mgba3a4f16a xn--mgbaam7a8h xn--mgbab2bd | ||||
3534 | xn--mgbayh7gpa xn--mgbbh1a71e xn--mgbc0a9azcg xn--mgberp4a5d4ar xn--mgbx4cd0ab | ||||
3535 | xn--ngbc5azd xn--nqv7f xn--nqv7fs00ema xn--o3cw4h xn--ogbpf8fl xn--p1ai | ||||
3536 | xn--pgbs0dh xn--q9jyb4c xn--rhqv96g xn--s9brj9c xn--ses554g xn--unup4y xn--vhquv | ||||
3537 | xn--wgbh1c xn--wgbl6a xn--xhq521b xn--xkc2al3hye2a xn--xkc2dl3a5ee0h | ||||
3538 | xn--yfro4i67o xn--ygbi2ammx xn--zfr164b xxx xyz yachts yandex ye yokohama | ||||
3539 | youtube yt za zm zone zw | ||||
3540 | 699 | 12.5ms | /) { $self->{valid_tlds}{lc $_} = 1; } | ||
3541 | |||||
3542 | push (@cmds, { | ||||
3543 | setting => 'util_rb_tld', | ||||
3544 | is_admin => 1, | ||||
3545 | # spent 15.9ms (13.5+2.34) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3557] which was called 128 times, avg 124µs/call:
# 128 times (13.5ms+2.34ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 124µs/call | ||||
3546 | 128 | 561µs | my ($self, $key, $value, $line) = @_; | ||
3547 | 128 | 1.06ms | 128 | 326µs | unless (defined $value && $value !~ /^$/) { # spent 326µs making 128 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
3548 | return $MISSING_REQUIRED_VALUE; | ||||
3549 | } | ||||
3550 | 128 | 1.84ms | 128 | 1.09ms | unless ($value =~ /^[^\s.]+(?:\s+[^\s.]+)*$/) { # spent 1.09ms making 128 calls to Mail::SpamAssassin::Conf::CORE:match, avg 9µs/call |
3551 | return $INVALID_VALUE; | ||||
3552 | } | ||||
3553 | 128 | 2.51ms | foreach (split(/\s+/, $value)) { | ||
3554 | 1488 | 7.34ms | $self->{valid_tlds}{lc $_} = 1; | ||
3555 | } | ||||
3556 | 128 | 1.60ms | 128 | 923µs | dbg("config: added tld list - $value"); # spent 923µs making 128 calls to Mail::SpamAssassin::Logger::dbg, avg 7µs/call |
3557 | } | ||||
3558 | 1 | 38µs | }); | ||
3559 | |||||
3560 | =item util_rb_2tld 2tld-1.tld 2tld-2.tld ... | ||||
3561 | |||||
3562 | This option maintains list of valid 2nd-level TLDs in the RegistryBoundaries | ||||
3563 | code. 2TLDs include things like co.uk, fed.us, etc. | ||||
3564 | |||||
3565 | =cut | ||||
3566 | |||||
3567 | # DO NOT UPDATE THIS HARDCODED LIST!! It is only as fallback for | ||||
3568 | # transitional period and to be removed later. TLDs are now maintained in | ||||
3569 | # sa-update 20_aux_tlds.cf. | ||||
3570 | 1 | 244µs | foreach (qw/ | ||
3571 | com.ac edu.ac gov.ac mil.ac net.ac org.ac nom.ad ac.ae co.ae com.ae gov.ae | ||||
3572 | mil.ae name.ae net.ae org.ae pro.ae sch.ae com.af edu.af gov.af net.af | ||||
3573 | co.ag com.ag net.ag nom.ag org.ag com.ai edu.ai gov.ai net.ai off.ai | ||||
3574 | org.ai com.al edu.al gov.al net.al org.al com.an edu.an net.an org.an | ||||
3575 | co.ao ed.ao gv.ao it.ao og.ao pb.ao com.ar edu.ar gov.ar int.ar mil.ar | ||||
3576 | net.ar org.ar e164.arpa in-addr.arpa ip6.arpa iris.arpa uri.arpa urn.arpa | ||||
3577 | ac.at co.at gv.at or.at priv.at act.au asn.au com.au conf.au csiro.au | ||||
3578 | edu.au gov.au id.au info.au net.au nsw.au nt.au org.au otc.au oz.au qld.au | ||||
3579 | sa.au tas.au telememo.au vic.au wa.au com.aw biz.az com.az edu.az gov.az | ||||
3580 | info.az int.az mil.az name.az net.az org.az pp.az co.ba com.ba edu.ba | ||||
3581 | gov.ba mil.ba net.ba org.ba rs.ba unbi.ba unsa.ba com.bb edu.bb gov.bb | ||||
3582 | net.bb org.bb ac.bd com.bd edu.bd gov.bd mil.bd net.bd org.bd ac.be | ||||
3583 | belgie.be dns.be fgov.be gov.bf biz.bh cc.bh com.bh edu.bh gov.bh info.bh | ||||
3584 | net.bh org.bh com.bm edu.bm gov.bm net.bm org.bm com.bn edu.bn net.bn | ||||
3585 | org.bn com.bo edu.bo gob.bo gov.bo int.bo mil.bo net.bo org.bo tv.bo | ||||
3586 | adm.br adv.br agr.br am.br arq.br art.br ato.br bio.br bmd.br cim.br | ||||
3587 | cng.br cnt.br com.br coop.br dpn.br eco.br ecn.br edu.br eng.br esp.br | ||||
3588 | etc.br eti.br far.br fm.br fnd.br fot.br fst.br g12.br ggf.br gov.br | ||||
3589 | imb.br ind.br inf.br jor.br lel.br mat.br med.br mil.br mus.br net.br | ||||
3590 | nom.br not.br ntr.br odo.br org.br ppg.br pro.br psc.br psi.br qsl.br | ||||
3591 | rec.br slg.br srv.br tmp.br trd.br tur.br tv.br vet.br zlg.br com.bs | ||||
3592 | net.bs org.bs com.bt edu.bt gov.bt net.bt org.bt co.bw org.bw gov.by | ||||
3593 | mil.by com.bz net.bz org.bz ab.ca bc.ca gc.ca mb.ca nb.ca nf.ca nl.ca | ||||
3594 | ns.ca nt.ca nu.ca on.ca pe.ca qc.ca sk.ca yk.ca co.ck edu.ck gov.ck net.ck | ||||
3595 | org.ck ac.cn ah.cn bj.cn com.cn cq.cn edu.cn fj.cn gd.cn gov.cn gs.cn | ||||
3596 | gx.cn gz.cn ha.cn hb.cn he.cn hi.cn hk.cn hl.cn hn.cn jl.cn js.cn jx.cn | ||||
3597 | ln.cn mo.cn net.cn nm.cn nx.cn org.cn qh.cn sc.cn sd.cn sh.cn sn.cn sx.cn | ||||
3598 | tj.cn tw.cn xj.cn xz.cn yn.cn zj.cn arts.co com.co edu.co firm.co gov.co | ||||
3599 | info.co int.co mil.co net.co nom.co org.co rec.co web.co lkd.co.im | ||||
3600 | ltd.co.im plc.co.im co.cm com.cm net.cm au.com br.com cn.com de.com eu.com | ||||
3601 | gb.com hu.com no.com qc.com ru.com sa.com se.com uk.com us.com uy.com | ||||
3602 | za.com ac.cr co.cr ed.cr fi.cr go.cr or.cr sa.cr com.cu edu.cu gov.cu | ||||
3603 | inf.cu net.cu org.cu gov.cx ac.cy biz.cy com.cy ekloges.cy gov.cy ltd.cy | ||||
3604 | name.cy net.cy org.cy parliament.cy press.cy pro.cy tm.cy co.dk com.dm | ||||
3605 | edu.dm gov.dm net.dm org.dm art.do com.do edu.do gob.do gov.do mil.do | ||||
3606 | net.do org.do sld.do web.do art.dz asso.dz com.dz edu.dz gov.dz net.dz | ||||
3607 | org.dz pol.dz com.ec edu.ec fin.ec gov.ec info.ec k12.ec med.ec mil.ec | ||||
3608 | net.ec org.ec pro.ec gob.ec co.ee com.ee edu.ee fie.ee med.ee org.ee | ||||
3609 | pri.ee com.eg edu.eg eun.eg gov.eg mil.eg net.eg org.eg sci.eg com.er | ||||
3610 | edu.er gov.er ind.er mil.er net.er org.er com.es edu.es gob.es nom.es | ||||
3611 | org.es biz.et com.et edu.et gov.et info.et name.et net.et org.et aland.fi | ||||
3612 | ac.fj biz.fj com.fj gov.fj id.fj info.fj mil.fj name.fj net.fj org.fj | ||||
3613 | pro.fj school.fj ac.fk co.fk com.fk gov.fk net.fk nom.fk org.fk tm.fr | ||||
3614 | asso.fr nom.fr prd.fr presse.fr com.fr gouv.fr com.ge edu.ge gov.ge mil.ge | ||||
3615 | net.ge org.ge pvt.ge ac.gg alderney.gg co.gg gov.gg guernsey.gg ind.gg | ||||
3616 | ltd.gg net.gg org.gg sark.gg sch.gg com.gh edu.gh gov.gh mil.gh org.gh | ||||
3617 | com.gi edu.gi gov.gi ltd.gi mod.gi org.gi ac.gn com.gn gov.gn net.gn | ||||
3618 | org.gn asso.gp com.gp edu.gp net.gp org.gp com.gr edu.gr gov.gr net.gr | ||||
3619 | org.gr com.gt edu.gt gob.gt ind.gt mil.gt net.gt org.gt com.gu edu.gu | ||||
3620 | gov.gu mil.gu net.gu org.gu com.hk edu.hk gov.hk idv.hk net.hk org.hk | ||||
3621 | com.hn edu.hn gob.hn mil.hn net.hn org.hn com.hr from.hr iz.hr name.hr | ||||
3622 | adult.ht art.ht asso.ht com.ht coop.ht edu.ht firm.ht gouv.ht info.ht | ||||
3623 | med.ht net.ht org.ht perso.ht pol.ht pro.ht rel.ht shop.ht 2000.hu | ||||
3624 | agrar.hu bolt.hu casino.hu city.hu co.hu erotica.hu erotika.hu film.hu | ||||
3625 | forum.hu games.hu hotel.hu info.hu ingatlan.hu jogasz.hu konyvelo.hu | ||||
3626 | lakas.hu media.hu news.hu org.hu priv.hu reklam.hu sex.hu shop.hu sport.hu | ||||
3627 | suli.hu szex.hu tm.hu tozsde.hu utazas.hu video.hu ac.id co.id go.id | ||||
3628 | mil.id net.id or.id sch.id web.id gov.ie ac.il co.il gov.il idf.il k12.il | ||||
3629 | muni.il net.il org.il ac.im co.im gov.im net.im nic.im org.im ac.in co.in | ||||
3630 | edu.in ernet.in firm.in gen.in gov.in ind.in mil.in net.in nic.in org.in | ||||
3631 | res.in com.io gov.io mil.io net.io org.io ac.ir co.ir gov.ir id.ir net.ir | ||||
3632 | org.ir sch.ir edu.it gov.it ac.je co.je gov.je ind.je jersey.je ltd.je | ||||
3633 | net.je org.je sch.je com.jm edu.jm gov.jm net.jm org.jm com.jo edu.jo | ||||
3634 | gov.jo mil.jo net.jo org.jo ac.jp ad.jp aichi.jp akita.jp aomori.jp | ||||
3635 | chiba.jp co.jp ed.jp ehime.jp fukui.jp fukuoka.jp fukushima.jp gifu.jp | ||||
3636 | go.jp gov.jp gr.jp gunma.jp hiroshima.jp hokkaido.jp hyogo.jp ibaraki.jp | ||||
3637 | ishikawa.jp iwate.jp kagawa.jp kagoshima.jp kanagawa.jp kanazawa.jp | ||||
3638 | kawasaki.jp kitakyushu.jp kobe.jp kochi.jp kumamoto.jp kyoto.jp lg.jp | ||||
3639 | matsuyama.jp mie.jp miyagi.jp miyazaki.jp nagano.jp nagasaki.jp nagoya.jp | ||||
3640 | nara.jp ne.jp net.jp niigata.jp oita.jp okayama.jp okinawa.jp or.jp org.jp | ||||
3641 | osaka.jp saga.jp saitama.jp sapporo.jp sendai.jp shiga.jp shimane.jp | ||||
3642 | shizuoka.jp takamatsu.jp tochigi.jp tokushima.jp tokyo.jp tottori.jp | ||||
3643 | toyama.jp utsunomiya.jp wakayama.jp yamagata.jp yamaguchi.jp yamanashi.jp | ||||
3644 | yokohama.jp ac.ke co.ke go.ke ne.ke new.ke or.ke sc.ke com.kg edu.kg | ||||
3645 | gov.kg mil.kg net.kg org.kg com.kh edu.kh gov.kh mil.kh net.kh org.kh | ||||
3646 | per.kh ac.kr busan.kr chungbuk.kr chungnam.kr co.kr daegu.kr daejeon.kr | ||||
3647 | es.kr gangwon.kr go.kr gwangju.kr gyeongbuk.kr gyeonggi.kr gyeongnam.kr | ||||
3648 | hs.kr incheon.kr jeju.kr jeonbuk.kr jeonnam.kr kg.kr kyonggi.kr mil.kr | ||||
3649 | ms.kr ne.kr or.kr pe.kr re.kr sc.kr seoul.kr ulsan.kr com.kw edu.kw gov.kw | ||||
3650 | mil.kw net.kw org.kw com.ky edu.ky gov.ky net.ky org.ky com.kz edu.kz | ||||
3651 | gov.kz mil.kz net.kz org.kz com.la net.la org.la com.lb edu.lb gov.lb | ||||
3652 | mil.lb net.lb org.lb com.lc edu.lc gov.lc net.lc org.lc assn.lk com.lk | ||||
3653 | edu.lk gov.lk grp.lk hotel.lk int.lk ltd.lk net.lk ngo.lk org.lk sch.lk | ||||
3654 | soc.lk web.lk com.lr edu.lr gov.lr net.lr org.lr co.ls org.ls gov.lt | ||||
3655 | mil.lt asn.lv com.lv conf.lv edu.lv gov.lv id.lv mil.lv net.lv org.lv | ||||
3656 | biz.ly com.ly edu.ly gov.ly id.ly med.ly net.ly org.ly plc.ly sch.ly ac.ma | ||||
3657 | co.ma gov.ma net.ma org.ma press.ma asso.mc tm.mc ac.me co.me edu.me | ||||
3658 | gov.me its.me net.me org.me priv.me com.mg edu.mg gov.mg mil.mg nom.mg | ||||
3659 | org.mg prd.mg tm.mg army.mil navy.mil com.mk org.mk com.mm edu.mm gov.mm | ||||
3660 | net.mm org.mm edu.mn gov.mn org.mn com.mo edu.mo gov.mo net.mo org.mo | ||||
3661 | music.mobi weather.mobi co.mp edu.mp gov.mp net.mp org.mp com.mt edu.mt | ||||
3662 | gov.mt net.mt org.mt tm.mt uu.mt co.mu com.mu aero.mv biz.mv com.mv | ||||
3663 | coop.mv edu.mv gov.mv info.mv int.mv mil.mv museum.mv name.mv net.mv | ||||
3664 | org.mv pro.mv ac.mw co.mw com.mw coop.mw edu.mw gov.mw int.mw museum.mw | ||||
3665 | net.mw org.mw com.mx edu.mx gob.mx net.mx org.mx com.my edu.my gov.my | ||||
3666 | mil.my name.my net.my org.my alt.na com.na cul.na edu.na net.na org.na | ||||
3667 | telecom.na unam.na com.nc net.nc org.nc de.net gb.net uk.net ac.ng com.ng | ||||
3668 | edu.ng gov.ng net.ng org.ng sch.ng ac.ni biz.ni com.ni edu.ni gob.ni in.ni | ||||
3669 | info.ni int.ni mil.ni net.ni nom.ni org.ni web.ni fhs.no folkebibl.no | ||||
3670 | fylkesbibl.no herad.no idrett.no kommune.no mil.no museum.no priv.no | ||||
3671 | stat.no tel.no vgs.no com.np edu.np gov.np mil.np net.np org.np biz.nr | ||||
3672 | co.nr com.nr edu.nr fax.nr gov.nr info.nr mob.nr mobil.nr mobile.nr net.nr | ||||
3673 | org.nr tel.nr tlf.nr ac.nz co.nz cri.nz geek.nz gen.nz govt.nz iwi.nz | ||||
3674 | maori.nz mil.nz net.nz org.nz school.nz ac.om biz.om co.om com.om edu.om | ||||
3675 | gov.om med.om mil.om mod.om museum.om net.om org.om pro.om sch.om dk.org | ||||
3676 | eu.org abo.pa ac.pa com.pa edu.pa gob.pa ing.pa med.pa net.pa nom.pa | ||||
3677 | org.pa sld.pa com.pe edu.pe gob.pe mil.pe net.pe nom.pe org.pe com.pf | ||||
3678 | edu.pf org.pf ac.pg com.pg net.pg com.ph edu.ph gov.ph mil.ph net.ph | ||||
3679 | ngo.ph org.ph biz.pk com.pk edu.pk fam.pk gob.pk gok.pk gon.pk gop.pk | ||||
3680 | gos.pk gov.pk net.pk org.pk web.pk art.pl biz.pl com.pl edu.pl gov.pl | ||||
3681 | info.pl mil.pl net.pl ngo.pl org.pl biz.pr com.pr edu.pr gov.pr info.pr | ||||
3682 | isla.pr name.pr net.pr org.pr pro.pr cpa.pro law.pro med.pro com.ps edu.ps | ||||
3683 | gov.ps net.ps org.ps plo.ps sec.ps com.pt edu.pt gov.pt int.pt net.pt | ||||
3684 | nome.pt org.pt publ.pt com.py edu.py gov.py net.py org.py com.qa edu.qa | ||||
3685 | gov.qa net.qa org.qa asso.re com.re nom.re arts.ro com.ro firm.ro info.ro | ||||
3686 | nom.ro nt.ro org.ro rec.ro store.ro tm.ro www.ro ac.rs co.rs edu.rs gov.rs | ||||
3687 | in.rs org.rs ac.ru com.ru edu.ru gov.ru int.ru mil.ru net.ru org.ru pp.ru | ||||
3688 | ac.rw co.rw com.rw edu.rw gouv.rw gov.rw int.rw mil.rw net.rw com.sa | ||||
3689 | edu.sa gov.sa med.sa net.sa org.sa pub.sa sch.sa com.sb edu.sb gov.sb | ||||
3690 | net.sb org.sb com.sc edu.sc gov.sc net.sc org.sc com.sd edu.sd gov.sd | ||||
3691 | info.sd med.sd net.sd org.sd sch.sd tv.sd ab.se ac.se bd.se brand.se c.se | ||||
3692 | d.se e.se f.se fh.se fhsk.se fhv.se g.se h.se i.se k.se komforb.se | ||||
3693 | kommunalforbund.se komvux.se lanarb.se lanbib.se m.se mil.se n.se | ||||
3694 | naturbruksgymn.se o.se org.se parti.se pp.se press.se s.se sshn.se t.se | ||||
3695 | tm.se u.se w.se x.se y.se z.se com.sg edu.sg gov.sg idn.sg net.sg org.sg | ||||
3696 | per.sg com.sh edu.sh gov.sh mil.sh net.sh org.sh edu.sk gov.sk mil.sk | ||||
3697 | co.st com.st consulado.st edu.st embaixada.st gov.st mil.st net.st org.st | ||||
3698 | principe.st saotome.st store.st com.sv edu.sv gob.sv org.sv red.sv com.sy | ||||
3699 | gov.sy net.sy org.sy at.tf bg.tf ca.tf ch.tf cz.tf de.tf edu.tf eu.tf | ||||
3700 | int.tf net.tf pl.tf ru.tf sg.tf us.tf ac.th co.th go.th in.th mi.th net.th | ||||
3701 | or.th ac.tj biz.tj co.tj com.tj edu.tj go.tj gov.tj int.tj mil.tj name.tj | ||||
3702 | net.tj org.tj web.tj com.tn edunet.tn ens.tn fin.tn gov.tn ind.tn info.tn | ||||
3703 | intl.tn nat.tn net.tn org.tn rnrt.tn rns.tn rnu.tn tourism.tn gov.to | ||||
3704 | av.tr bbs.tr bel.tr biz.tr com.tr dr.tr edu.tr gen.tr gov.tr | ||||
3705 | info.tr k12.tr mil.tr name.tr net.tr org.tr pol.tr tel.tr web.tr aero.tt | ||||
3706 | at.tt au.tt be.tt biz.tt ca.tt co.tt com.tt coop.tt de.tt dk.tt edu.tt | ||||
3707 | es.tt eu.tt fr.tt gov.tt info.tt int.tt it.tt jobs.tt mobi.tt museum.tt | ||||
3708 | name.tt net.tt nic.tt org.tt pro.tt se.tt travel.tt uk.tt us.tt co.tv | ||||
3709 | gov.tv club.tw com.tw ebiz.tw edu.tw game.tw gov.tw idv.tw mil.tw net.tw | ||||
3710 | org.tw ac.tz co.tz go.tz ne.tz or.tz cherkassy.ua chernigov.ua | ||||
3711 | chernovtsy.ua ck.ua cn.ua co.ua com.ua crimea.ua cv.ua dn.ua | ||||
3712 | dnepropetrovsk.ua donetsk.ua dp.ua edu.ua gov.ua if.ua in.ua | ||||
3713 | ivano-frankivsk.ua kh.ua kharkov.ua kherson.ua khmelnitskiy.ua kiev.ua | ||||
3714 | kirovograd.ua km.ua kr.ua ks.ua kv.ua lg.ua lugansk.ua lutsk.ua lviv.ua | ||||
3715 | mk.ua net.ua nikolaev.ua od.ua odessa.ua org.ua pl.ua poltava.ua rovno.ua | ||||
3716 | rv.ua sebastopol.ua sumy.ua te.ua ternopil.ua uzhgorod.ua vinnica.ua vn.ua | ||||
3717 | zaporizhzhe.ua zhitomir.ua zp.ua zt.ua ac.ug co.ug go.ug ne.ug or.ug sc.ug | ||||
3718 | ac.uk bl.uk british-library.uk co.uk edu.uk gov.uk icnet.uk jet.uk ltd.uk | ||||
3719 | me.uk mod.uk national-library-scotland.uk net.uk nhs.uk nic.uk nls.uk | ||||
3720 | org.uk parliament.uk plc.uk police.uk sch.uk ak.us al.us ar.us az.us ca.us | ||||
3721 | co.us ct.us dc.us de.us dni.us fed.us fl.us ga.us hi.us ia.us id.us il.us | ||||
3722 | in.us isa.us kids.us ks.us ky.us la.us ma.us md.us me.us mi.us mn.us mo.us | ||||
3723 | ms.us mt.us nc.us nd.us ne.us nh.us nj.us nm.us nsn.us nv.us ny.us oh.us | ||||
3724 | ok.us or.us pa.us ri.us sc.us sd.us tn.us tx.us ut.us va.us vt.us wa.us | ||||
3725 | wi.us wv.us wy.us com.uy edu.uy gub.uy mil.uy net.uy org.uy vatican.va | ||||
3726 | arts.ve bib.ve co.ve com.ve edu.ve firm.ve gov.ve info.ve int.ve mil.ve | ||||
3727 | net.ve nom.ve org.ve rec.ve store.ve tec.ve web.ve co.vi com.vi edu.vi | ||||
3728 | gov.vi net.vi org.vi ac.vn biz.vn com.vn edu.vn gov.vn health.vn info.vn | ||||
3729 | int.vn name.vn net.vn org.vn pro.vn ch.vu com.vu de.vu edu.vu fr.vu net.vu | ||||
3730 | org.vu com.ws edu.ws gov.ws net.ws org.ws com.ye edu.ye gov.ye mil.ye | ||||
3731 | net.ye org.ye ac.za alt.za bourse.za city.za co.za edu.za gov.za law.za | ||||
3732 | mil.za net.za ngo.za nom.za org.za school.za tm.za web.za ac.zm co.zm | ||||
3733 | com.zm edu.zm gov.zm org.zm sch.zm ac.zw co.zw gov.zw org.zw | ||||
3734 | 1587 | 6.43ms | /) { $self->{two_level_domains}{lc $_} = 1; } | ||
3735 | |||||
3736 | push (@cmds, { | ||||
3737 | setting => 'util_rb_2tld', | ||||
3738 | is_admin => 1, | ||||
3739 | # spent 28.2ms (23.4+4.75) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3750] which was called 459 times, avg 61µs/call:
# 459 times (23.4ms+4.75ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 61µs/call | ||||
3740 | 459 | 2.15ms | my ($self, $key, $value, $line) = @_; | ||
3741 | 459 | 4.51ms | 459 | 1.77ms | unless (defined $value && $value !~ /^$/) { # spent 1.77ms making 459 calls to Mail::SpamAssassin::Conf::CORE:match, avg 4µs/call |
3742 | return $MISSING_REQUIRED_VALUE; | ||||
3743 | } | ||||
3744 | 459 | 5.62ms | 459 | 2.99ms | unless ($value =~ /^[^\s.]+\.[^\s.]+(?:\s+[^\s.]+\.[^\s.]+)*$/) { # spent 2.99ms making 459 calls to Mail::SpamAssassin::Conf::CORE:match, avg 7µs/call |
3745 | return $INVALID_VALUE; | ||||
3746 | } | ||||
3747 | 459 | 7.48ms | foreach (split(/\s+/, $value)) { | ||
3748 | 1868 | 9.17ms | $self->{two_level_domains}{lc $_} = 1; | ||
3749 | } | ||||
3750 | } | ||||
3751 | 1 | 15µs | }); | ||
3752 | |||||
3753 | =item util_rb_3tld 3tld1.some.tld 3tld2.other.tld ... | ||||
3754 | |||||
3755 | This option maintains list of valid 3rd-level TLDs in the RegistryBoundaries | ||||
3756 | code. 3TLDs include things like demon.co.uk, plc.co.im, etc. | ||||
3757 | |||||
3758 | =cut | ||||
3759 | |||||
3760 | # DO NOT UPDATE THIS HARDCODED LIST!! It is only as fallback for | ||||
3761 | # transitional period and to be removed later. TLDs are now maintained in | ||||
3762 | # sa-update 20_aux_tlds.cf. | ||||
3763 | 1 | 5µs | foreach (qw/ | ||
3764 | demon.co.uk esc.edu.ar lkd.co.im plc.co.im | ||||
3765 | 4 | 17µs | /) { $self->{three_level_domains}{lc $_} = 1; } | ||
3766 | |||||
3767 | push (@cmds, { | ||||
3768 | setting => 'util_rb_3tld', | ||||
3769 | is_admin => 1, | ||||
3770 | # spent 1.91ms (1.52+389µs) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3781] which was called 48 times, avg 40µs/call:
# 48 times (1.52ms+389µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 40µs/call | ||||
3771 | 48 | 222µs | my ($self, $key, $value, $line) = @_; | ||
3772 | 48 | 439µs | 48 | 154µs | unless (defined $value && $value !~ /^$/) { # spent 154µs making 48 calls to Mail::SpamAssassin::Conf::CORE:match, avg 3µs/call |
3773 | return $MISSING_REQUIRED_VALUE; | ||||
3774 | } | ||||
3775 | 48 | 516µs | 48 | 235µs | unless ($value =~ /^[^\s.]+\.[^\s.]+\.[^\s.]+(?:\s+[^\s.]+\.[^\s.]+\.[^\s.]+)*$/) { # spent 235µs making 48 calls to Mail::SpamAssassin::Conf::CORE:match, avg 5µs/call |
3776 | return $INVALID_VALUE; | ||||
3777 | } | ||||
3778 | 48 | 516µs | foreach (split(/\s+/, $value)) { | ||
3779 | 48 | 302µs | $self->{three_level_domains}{lc $_} = 1; | ||
3780 | } | ||||
3781 | } | ||||
3782 | 1 | 10µs | }); | ||
3783 | |||||
3784 | =item clear_util_rb | ||||
3785 | |||||
3786 | Empty internal list of valid TLDs (including 2nd and 3rd level) which | ||||
3787 | RegistryBoundaries code uses. Only useful if you want to override the | ||||
3788 | standard lists supplied by sa-update. | ||||
3789 | |||||
3790 | =cut | ||||
3791 | |||||
3792 | push (@cmds, { | ||||
3793 | setting => 'clear_util_rb', | ||||
3794 | type => $CONF_TYPE_NOARGS, | ||||
3795 | # spent 1.20ms (1.19+14µs) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3804] which was called:
# once (1.19ms+14µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm | ||||
3796 | 1 | 6µs | my ($self, $key, $value, $line) = @_; | ||
3797 | 1 | 3µs | unless (!defined $value || $value eq '') { | ||
3798 | return $INVALID_VALUE; | ||||
3799 | } | ||||
3800 | 1 | 365µs | $self->{valid_tlds} = (); | ||
3801 | 1 | 778µs | $self->{two_level_domains} = (); | ||
3802 | 1 | 7µs | $self->{three_level_domains} = (); | ||
3803 | 1 | 22µs | 1 | 14µs | dbg("config: cleared tld lists"); # spent 14µs making 1 call to Mail::SpamAssassin::Logger::dbg |
3804 | } | ||||
3805 | 1 | 15µs | }); | ||
3806 | |||||
3807 | =item bayes_path /path/filename (default: ~/.spamassassin/bayes) | ||||
3808 | |||||
3809 | This is the directory and filename for Bayes databases. Several databases | ||||
3810 | will be created, with this as the base directory and filename, with C<_toks>, | ||||
3811 | C<_seen>, etc. appended to the base. The default setting results in files | ||||
3812 | called C<~/.spamassassin/bayes_seen>, C<~/.spamassassin/bayes_toks>, etc. | ||||
3813 | |||||
3814 | By default, each user has their own in their C<~/.spamassassin> directory with | ||||
3815 | mode 0700/0600. For system-wide SpamAssassin use, you may want to reduce disk | ||||
3816 | space usage by sharing this across all users. However, Bayes appears to be | ||||
3817 | more effective with individual user databases. | ||||
3818 | |||||
3819 | =cut | ||||
3820 | |||||
3821 | push (@cmds, { | ||||
3822 | setting => 'bayes_path', | ||||
3823 | is_admin => 1, | ||||
3824 | default => '__userstate__/bayes', | ||||
3825 | type => $CONF_TYPE_STRING, | ||||
3826 | # spent 132µs (92+40) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3835] which was called:
# once (92µs+40µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm | ||||
3827 | 1 | 12µs | my ($self, $key, $value, $line) = @_; | ||
3828 | 1 | 28µs | 1 | 6µs | unless (defined $value && $value !~ /^$/) { # spent 6µs making 1 call to Mail::SpamAssassin::Conf::CORE:match |
3829 | return $MISSING_REQUIRED_VALUE; | ||||
3830 | } | ||||
3831 | 1 | 61µs | 1 | 35µs | if (-d $value) { # spent 35µs making 1 call to Mail::SpamAssassin::Conf::CORE:ftdir |
3832 | return $INVALID_VALUE; | ||||
3833 | } | ||||
3834 | 1 | 16µs | $self->{bayes_path} = $value; | ||
3835 | } | ||||
3836 | 1 | 12µs | }); | ||
3837 | |||||
3838 | =item bayes_file_mode (default: 0700) | ||||
3839 | |||||
3840 | The file mode bits used for the Bayesian filtering database files. | ||||
3841 | |||||
3842 | Make sure you specify this using the 'x' mode bits set, as it may also be used | ||||
3843 | to create directories. However, if a file is created, the resulting file will | ||||
3844 | not have any execute bits set (the umask is set to 111). The argument is a | ||||
3845 | string of octal digits, it is converted to a numeric value internally. | ||||
3846 | |||||
3847 | =cut | ||||
3848 | |||||
3849 | push (@cmds, { | ||||
3850 | setting => 'bayes_file_mode', | ||||
3851 | is_admin => 1, | ||||
3852 | default => '0700', | ||||
3853 | type => $CONF_TYPE_NUMERIC, | ||||
3854 | # spent 88µs (44+45) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3858] which was called:
# once (44µs+45µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm | ||||
3855 | 1 | 8µs | my ($self, $key, $value, $line) = @_; | ||
3856 | 1 | 20µs | 1 | 7µs | if ($value !~ /^0?[0-7]{3}$/) { return $INVALID_VALUE } # spent 7µs making 1 call to Mail::SpamAssassin::Conf::CORE:match |
3857 | 1 | 22µs | 1 | 38µs | $self->{bayes_file_mode} = untaint_var($value); # spent 38µs making 1 call to Mail::SpamAssassin::Util::untaint_var |
3858 | } | ||||
3859 | 1 | 13µs | }); | ||
3860 | |||||
3861 | =item bayes_store_module Name::Of::BayesStore::Module | ||||
3862 | |||||
3863 | If this option is set, the module given will be used as an alternate | ||||
3864 | to the default bayes storage mechanism. It must conform to the | ||||
3865 | published storage specification (see | ||||
3866 | Mail::SpamAssassin::BayesStore). For example, set this to | ||||
3867 | Mail::SpamAssassin::BayesStore::SQL to use the generic SQL storage | ||||
3868 | module. | ||||
3869 | |||||
3870 | =cut | ||||
3871 | |||||
3872 | push (@cmds, { | ||||
3873 | setting => 'bayes_store_module', | ||||
3874 | is_admin => 1, | ||||
3875 | default => '', | ||||
3876 | type => $CONF_TYPE_STRING, | ||||
3877 | code => sub { | ||||
3878 | my ($self, $key, $value, $line) = @_; | ||||
3879 | local ($1); | ||||
3880 | if ($value !~ /^([_A-Za-z0-9:]+)$/) { return $INVALID_VALUE; } | ||||
3881 | $self->{bayes_store_module} = $1; | ||||
3882 | } | ||||
3883 | 1 | 18µs | }); | ||
3884 | |||||
3885 | =item bayes_sql_dsn DBI::databasetype:databasename:hostname:port | ||||
3886 | |||||
3887 | Used for BayesStore::SQL storage implementation. | ||||
3888 | |||||
3889 | This option give the connect string used to connect to the SQL based Bayes storage. | ||||
3890 | |||||
3891 | =cut | ||||
3892 | |||||
3893 | 1 | 6µs | push (@cmds, { | ||
3894 | setting => 'bayes_sql_dsn', | ||||
3895 | is_admin => 1, | ||||
3896 | default => '', | ||||
3897 | type => $CONF_TYPE_STRING, | ||||
3898 | }); | ||||
3899 | |||||
3900 | =item bayes_sql_username | ||||
3901 | |||||
3902 | Used by BayesStore::SQL storage implementation. | ||||
3903 | |||||
3904 | This option gives the username used by the above DSN. | ||||
3905 | |||||
3906 | =cut | ||||
3907 | |||||
3908 | 1 | 6µs | push (@cmds, { | ||
3909 | setting => 'bayes_sql_username', | ||||
3910 | is_admin => 1, | ||||
3911 | default => '', | ||||
3912 | type => $CONF_TYPE_STRING, | ||||
3913 | }); | ||||
3914 | |||||
3915 | =item bayes_sql_password | ||||
3916 | |||||
3917 | Used by BayesStore::SQL storage implementation. | ||||
3918 | |||||
3919 | This option gives the password used by the above DSN. | ||||
3920 | |||||
3921 | =cut | ||||
3922 | |||||
3923 | 1 | 6µs | push (@cmds, { | ||
3924 | setting => 'bayes_sql_password', | ||||
3925 | is_admin => 1, | ||||
3926 | default => '', | ||||
3927 | type => $CONF_TYPE_STRING, | ||||
3928 | }); | ||||
3929 | |||||
3930 | =item bayes_sql_username_authorized ( 0 | 1 ) (default: 0) | ||||
3931 | |||||
3932 | Whether to call the services_authorized_for_username plugin hook in BayesSQL. | ||||
3933 | If the hook does not determine that the user is allowed to use bayes or is | ||||
3934 | invalid then then database will not be initialized. | ||||
3935 | |||||
3936 | NOTE: By default the user is considered invalid until a plugin returns | ||||
3937 | a true value. If you enable this, but do not have a proper plugin | ||||
3938 | loaded, all users will turn up as invalid. | ||||
3939 | |||||
3940 | The username passed into the plugin can be affected by the | ||||
3941 | bayes_sql_override_username config option. | ||||
3942 | |||||
3943 | =cut | ||||
3944 | |||||
3945 | 1 | 5µs | push (@cmds, { | ||
3946 | setting => 'bayes_sql_username_authorized', | ||||
3947 | is_admin => 1, | ||||
3948 | default => 0, | ||||
3949 | type => $CONF_TYPE_BOOL, | ||||
3950 | }); | ||||
3951 | |||||
3952 | =item user_scores_dsn DBI:databasetype:databasename:hostname:port | ||||
3953 | |||||
3954 | If you load user scores from an SQL database, this will set the DSN | ||||
3955 | used to connect. Example: C<DBI:mysql:spamassassin:localhost> | ||||
3956 | |||||
3957 | If you load user scores from an LDAP directory, this will set the DSN used to | ||||
3958 | connect. You have to write the DSN as an LDAP URL, the components being the | ||||
3959 | host and port to connect to, the base DN for the search, the scope of the | ||||
3960 | search (base, one or sub), the single attribute being the multivalued attribute | ||||
3961 | used to hold the configuration data (space separated pairs of key and value, | ||||
3962 | just as in a file) and finally the filter being the expression used to filter | ||||
3963 | out the wanted username. Note that the filter expression is being used in a | ||||
3964 | sprintf statement with the username as the only parameter, thus is can hold a | ||||
3965 | single __USERNAME__ expression. This will be replaced with the username. | ||||
3966 | |||||
3967 | Example: C<ldap://localhost:389/dc=koehntopp,dc=de?saconfig?uid=__USERNAME__> | ||||
3968 | |||||
3969 | =cut | ||||
3970 | |||||
3971 | 1 | 5µs | push (@cmds, { | ||
3972 | setting => 'user_scores_dsn', | ||||
3973 | is_admin => 1, | ||||
3974 | default => '', | ||||
3975 | type => $CONF_TYPE_STRING, | ||||
3976 | }); | ||||
3977 | |||||
3978 | =item user_scores_sql_username username | ||||
3979 | |||||
3980 | The authorized username to connect to the above DSN. | ||||
3981 | |||||
3982 | =cut | ||||
3983 | |||||
3984 | 1 | 5µs | push (@cmds, { | ||
3985 | setting => 'user_scores_sql_username', | ||||
3986 | is_admin => 1, | ||||
3987 | default => '', | ||||
3988 | type => $CONF_TYPE_STRING, | ||||
3989 | }); | ||||
3990 | |||||
3991 | =item user_scores_sql_password password | ||||
3992 | |||||
3993 | The password for the database username, for the above DSN. | ||||
3994 | |||||
3995 | =cut | ||||
3996 | |||||
3997 | 1 | 6µs | push (@cmds, { | ||
3998 | setting => 'user_scores_sql_password', | ||||
3999 | is_admin => 1, | ||||
4000 | default => '', | ||||
4001 | type => $CONF_TYPE_STRING, | ||||
4002 | }); | ||||
4003 | |||||
4004 | =item user_scores_sql_custom_query query | ||||
4005 | |||||
4006 | This option gives you the ability to create a custom SQL query to | ||||
4007 | retrieve user scores and preferences. In order to work correctly your | ||||
4008 | query should return two values, the preference name and value, in that | ||||
4009 | order. In addition, there are several "variables" that you can use | ||||
4010 | as part of your query, these variables will be substituted for the | ||||
4011 | current values right before the query is run. The current allowed | ||||
4012 | variables are: | ||||
4013 | |||||
4014 | =over 4 | ||||
4015 | |||||
4016 | =item _TABLE_ | ||||
4017 | |||||
4018 | The name of the table where user scores and preferences are stored. Currently | ||||
4019 | hardcoded to userpref, to change this value you need to create a new custom | ||||
4020 | query with the new table name. | ||||
4021 | |||||
4022 | =item _USERNAME_ | ||||
4023 | |||||
4024 | The current user's username. | ||||
4025 | |||||
4026 | =item _MAILBOX_ | ||||
4027 | |||||
4028 | The portion before the @ as derived from the current user's username. | ||||
4029 | |||||
4030 | =item _DOMAIN_ | ||||
4031 | |||||
4032 | The portion after the @ as derived from the current user's username, this | ||||
4033 | value may be null. | ||||
4034 | |||||
4035 | =back | ||||
4036 | |||||
4037 | The query must be one continuous line in order to parse correctly. | ||||
4038 | |||||
4039 | Here are several example queries, please note that these are broken up | ||||
4040 | for easy reading, in your config it should be one continuous line. | ||||
4041 | |||||
4042 | =over 4 | ||||
4043 | |||||
4044 | =item Current default query: | ||||
4045 | |||||
4046 | C<SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '@GLOBAL' ORDER BY username ASC> | ||||
4047 | |||||
4048 | =item Use global and then domain level defaults: | ||||
4049 | |||||
4050 | C<SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '@GLOBAL' OR username = '@~'||_DOMAIN_ ORDER BY username ASC> | ||||
4051 | |||||
4052 | =item Maybe global prefs should override user prefs: | ||||
4053 | |||||
4054 | C<SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '@GLOBAL' ORDER BY username DESC> | ||||
4055 | |||||
4056 | =back | ||||
4057 | |||||
4058 | =cut | ||||
4059 | |||||
4060 | 1 | 6µs | push (@cmds, { | ||
4061 | setting => 'user_scores_sql_custom_query', | ||||
4062 | is_admin => 1, | ||||
4063 | default => undef, | ||||
4064 | type => $CONF_TYPE_STRING, | ||||
4065 | }); | ||||
4066 | |||||
4067 | =item user_scores_ldap_username | ||||
4068 | |||||
4069 | This is the Bind DN used to connect to the LDAP server. It defaults | ||||
4070 | to the empty string (""), allowing anonymous binding to work. | ||||
4071 | |||||
4072 | Example: C<cn=master,dc=koehntopp,dc=de> | ||||
4073 | |||||
4074 | =cut | ||||
4075 | |||||
4076 | 1 | 6µs | push (@cmds, { | ||
4077 | setting => 'user_scores_ldap_username', | ||||
4078 | is_admin => 1, | ||||
4079 | default => '', | ||||
4080 | type => $CONF_TYPE_STRING, | ||||
4081 | }); | ||||
4082 | |||||
4083 | =item user_scores_ldap_password | ||||
4084 | |||||
4085 | This is the password used to connect to the LDAP server. It defaults | ||||
4086 | to the empty string (""). | ||||
4087 | |||||
4088 | =cut | ||||
4089 | |||||
4090 | 1 | 6µs | push (@cmds, { | ||
4091 | setting => 'user_scores_ldap_password', | ||||
4092 | is_admin => 1, | ||||
4093 | default => '', | ||||
4094 | type => $CONF_TYPE_STRING, | ||||
4095 | }); | ||||
4096 | |||||
4097 | =item user_scores_fallback_to_global (default: 1) | ||||
4098 | |||||
4099 | Fall back to global scores and settings if userprefs can't be loaded | ||||
4100 | from SQL or LDAP, instead of passing the message through unprocessed. | ||||
4101 | |||||
4102 | =cut | ||||
4103 | |||||
4104 | 1 | 6µs | push (@cmds, { | ||
4105 | setting => 'user_scores_fallback_to_global', | ||||
4106 | is_admin => 1, | ||||
4107 | default => 1, | ||||
4108 | type => $CONF_TYPE_BOOL, | ||||
4109 | }); | ||||
4110 | |||||
4111 | =item loadplugin PluginModuleName [/path/module.pm] | ||||
4112 | |||||
4113 | Load a SpamAssassin plugin module. The C<PluginModuleName> is the perl module | ||||
4114 | name, used to create the plugin object itself. | ||||
4115 | |||||
4116 | C</path/to/module.pm> is the file to load, containing the module's perl code; | ||||
4117 | if it's specified as a relative path, it's considered to be relative to the | ||||
4118 | current configuration file. If it is omitted, the module will be loaded | ||||
4119 | using perl's search path (the C<@INC> array). | ||||
4120 | |||||
4121 | See C<Mail::SpamAssassin::Plugin> for more details on writing plugins. | ||||
4122 | |||||
4123 | =cut | ||||
4124 | |||||
4125 | push (@cmds, { | ||||
4126 | setting => 'loadplugin', | ||||
4127 | is_admin => 1, | ||||
4128 | # spent 510ms (2.13+508) within Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:4145] which was called 27 times, avg 18.9ms/call:
# 27 times (2.13ms+508ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438 of Mail/SpamAssassin/Conf/Parser.pm, avg 18.9ms/call | ||||
4129 | 27 | 168µs | my ($self, $key, $value, $line) = @_; | ||
4130 | 27 | 66µs | if ($value eq '') { | ||
4131 | return $MISSING_REQUIRED_VALUE; | ||||
4132 | } | ||||
4133 | 27 | 46µs | my ($package, $path); | ||
4134 | 27 | 113µs | local ($1,$2); | ||
4135 | 27 | 742µs | 54 | 361µs | if ($value =~ /^(\S+)\s+(\S+)$/) { # spent 361µs making 54 calls to Mail::SpamAssassin::Conf::CORE:match, avg 7µs/call |
4136 | ($package, $path) = ($1, $2); | ||||
4137 | } elsif ($value =~ /^\S+$/) { | ||||
4138 | 27 | 88µs | ($package, $path) = ($value, undef); | ||
4139 | } else { | ||||
4140 | return $INVALID_VALUE; | ||||
4141 | } | ||||
4142 | # is blindly untainting safe? it is no worse than before | ||||
4143 | 27 | 557µs | 54 | 1.04ms | $_ = untaint_var($_) for ($package,$path); # spent 1.04ms making 54 calls to Mail::SpamAssassin::Util::untaint_var, avg 19µs/call |
4144 | 27 | 603µs | 27 | 507ms | $self->load_plugin ($package, $path); # spent 507ms making 27 calls to Mail::SpamAssassin::Conf::load_plugin, avg 18.8ms/call |
4145 | } | ||||
4146 | 1 | 13µs | }); | ||
4147 | |||||
4148 | =item tryplugin PluginModuleName [/path/module.pm] | ||||
4149 | |||||
4150 | Same as C<loadplugin>, but silently ignored if the .pm file cannot be found in | ||||
4151 | the filesystem. | ||||
4152 | |||||
4153 | =cut | ||||
4154 | |||||
4155 | push (@cmds, { | ||||
4156 | setting => 'tryplugin', | ||||
4157 | is_admin => 1, | ||||
4158 | code => sub { | ||||
4159 | my ($self, $key, $value, $line) = @_; | ||||
4160 | if ($value eq '') { | ||||
4161 | return $MISSING_REQUIRED_VALUE; | ||||
4162 | } | ||||
4163 | my ($package, $path); | ||||
4164 | local ($1,$2); | ||||
4165 | if ($value =~ /^(\S+)\s+(\S+)$/) { | ||||
4166 | ($package, $path) = ($1, $2); | ||||
4167 | } elsif ($value =~ /^\S+$/) { | ||||
4168 | ($package, $path) = ($value, undef); | ||||
4169 | } else { | ||||
4170 | return $INVALID_VALUE; | ||||
4171 | } | ||||
4172 | # is blindly untainting safe? it is no worse than before | ||||
4173 | $_ = untaint_var($_) for ($package,$path); | ||||
4174 | $self->load_plugin ($package, $path, 1); | ||||
4175 | } | ||||
4176 | 1 | 10µs | }); | ||
4177 | |||||
4178 | =item ignore_always_matching_regexps (Default: 0) | ||||
4179 | |||||
4180 | Ignore any rule which contains a regexp which always matches. | ||||
4181 | Currently only catches regexps which contain '||', or which begin or | ||||
4182 | end with a '|'. Also ignore rules with C<some> combinatorial explosions. | ||||
4183 | |||||
4184 | =cut | ||||
4185 | |||||
4186 | 1 | 6µs | push (@cmds, { | ||
4187 | setting => 'ignore_always_matching_regexps', | ||||
4188 | is_admin => 1, | ||||
4189 | default => 0, | ||||
4190 | type => $CONF_TYPE_BOOL, | ||||
4191 | }); | ||||
4192 | |||||
4193 | =back | ||||
4194 | |||||
4195 | =head1 PREPROCESSING OPTIONS | ||||
4196 | |||||
4197 | =over 4 | ||||
4198 | |||||
4199 | =item include filename | ||||
4200 | |||||
4201 | Include configuration lines from C<filename>. Relative paths are considered | ||||
4202 | relative to the current configuration file or user preferences file. | ||||
4203 | |||||
4204 | =item if (boolean perl expression) | ||||
4205 | |||||
4206 | Used to support conditional interpretation of the configuration | ||||
4207 | file. Lines between this and a corresponding C<else> or C<endif> line | ||||
4208 | will be ignored unless the expression evaluates as true | ||||
4209 | (in the perl sense; that is, defined and non-0 and non-empty string). | ||||
4210 | |||||
4211 | The conditional accepts a limited subset of perl for security -- just enough to | ||||
4212 | perform basic arithmetic comparisons. The following input is accepted: | ||||
4213 | |||||
4214 | =over 4 | ||||
4215 | |||||
4216 | =item numbers, whitespace, arithmetic operations and grouping | ||||
4217 | |||||
4218 | Namely these characters and ranges: | ||||
4219 | |||||
4220 | ( ) - + * / _ . , < = > ! ~ 0-9 whitespace | ||||
4221 | |||||
4222 | =item version | ||||
4223 | |||||
4224 | This will be replaced with the version number of the currently-running | ||||
4225 | SpamAssassin engine. Note: The version used is in the internal SpamAssassin | ||||
4226 | version format which is C<x.yyyzzz>, where x is major version, y is minor | ||||
4227 | version, and z is maintenance version. So 3.0.0 is C<3.000000>, and 3.4.80 | ||||
4228 | is C<3.004080>. | ||||
4229 | |||||
4230 | =item perl_version | ||||
4231 | |||||
4232 | (Introduced in 3.4.1) This will be replaced with the version number of the | ||||
4233 | currently-running perl engine. Note: The version used is in the $] version | ||||
4234 | format which is C<x.yyyzzz>, where x is major version, y is minor version, | ||||
4235 | and z is maintenance version. So 5.8.8 is C<5.008008>, and 5.10.0 is | ||||
4236 | C<5.010000>. Use to protect rules that incorporate RE syntax elements | ||||
4237 | introduced in later versions of perl, such as the C<++> non-backtracking | ||||
4238 | match introduced in perl 5.10. For example: | ||||
4239 | |||||
4240 | # Avoid lint error on older perl installs | ||||
4241 | # Check SA version first to avoid warnings on checking perl_version on older SA | ||||
4242 | if version > 3.004001 && perl_version >= 5.018000 | ||||
4243 | body INVALID_RE_SYNTAX_IN_PERL_BEFORE_5_18 /(?[ \p{Thai} & \p{Digit} ])/ | ||||
4244 | endif | ||||
4245 | |||||
4246 | Note that the above will still generate a warning on perl older than 5.10.0; | ||||
4247 | to avoid that warning do this instead: | ||||
4248 | |||||
4249 | # Avoid lint error on older perl installs | ||||
4250 | if can(Mail::SpamAssassin::Conf::perl_min_version_5010000) | ||||
4251 | body INVALID_RE_SYNTAX_IN_PERL_5_8 /\w++/ | ||||
4252 | endif | ||||
4253 | |||||
4254 | Warning: a can() test is only defined for perl 5.10.0! | ||||
4255 | |||||
4256 | |||||
4257 | =item plugin(Name::Of::Plugin) | ||||
4258 | |||||
4259 | This is a function call that returns C<1> if the plugin named | ||||
4260 | C<Name::Of::Plugin> is loaded, or C<undef> otherwise. | ||||
4261 | |||||
4262 | =item has(Name::Of::Package::function_name) | ||||
4263 | |||||
4264 | This is a function call that returns C<1> if the perl package named | ||||
4265 | C<Name::Of::Package> includes a function called C<function_name>, or C<undef> | ||||
4266 | otherwise. Note that packages can be SpamAssassin plugins or built-in classes, | ||||
4267 | there's no difference in this respect. Internally this invokes UNIVERSAL::can. | ||||
4268 | |||||
4269 | =item can(Name::Of::Package::function_name) | ||||
4270 | |||||
4271 | This is a function call that returns C<1> if the perl package named | ||||
4272 | C<Name::Of::Package> includes a function called C<function_name> | ||||
4273 | B<and> that function returns a true value when called with no arguments, | ||||
4274 | otherwise C<undef> is returned. | ||||
4275 | |||||
4276 | Is similar to C<has>, except that it also calls the named function, | ||||
4277 | testing its return value (unlike the perl function UNIVERSAL::can). | ||||
4278 | This makes it possible for a 'feature' function to determine its result | ||||
4279 | value at run time. | ||||
4280 | |||||
4281 | =back | ||||
4282 | |||||
4283 | If the end of a configuration file is reached while still inside a | ||||
4284 | C<if> scope, a warning will be issued, but parsing will restart on | ||||
4285 | the next file. | ||||
4286 | |||||
4287 | For example: | ||||
4288 | |||||
4289 | if (version > 3.000000) | ||||
4290 | header MY_FOO ... | ||||
4291 | endif | ||||
4292 | |||||
4293 | loadplugin MyPlugin plugintest.pm | ||||
4294 | |||||
4295 | if plugin (MyPlugin) | ||||
4296 | header MY_PLUGIN_FOO eval:check_for_foo() | ||||
4297 | score MY_PLUGIN_FOO 0.1 | ||||
4298 | endif | ||||
4299 | |||||
4300 | =item ifplugin PluginModuleName | ||||
4301 | |||||
4302 | An alias for C<if plugin(PluginModuleName)>. | ||||
4303 | |||||
4304 | =item else | ||||
4305 | |||||
4306 | Used to support conditional interpretation of the configuration | ||||
4307 | file. Lines between this and a corresponding C<endif> line, | ||||
4308 | will be ignored unless the conditional expression evaluates as false | ||||
4309 | (in the perl sense; that is, not defined and not 0 and non-empty string). | ||||
4310 | |||||
4311 | =item require_version n.nnnnnn | ||||
4312 | |||||
4313 | Indicates that the entire file, from this line on, requires a certain | ||||
4314 | version of SpamAssassin to run. If a different (older or newer) version | ||||
4315 | of SpamAssassin tries to read the configuration from this file, it will | ||||
4316 | output a warning instead, and ignore it. | ||||
4317 | |||||
4318 | Note: The version used is in the internal SpamAssassin version format which is | ||||
4319 | C<x.yyyzzz>, where x is major version, y is minor version, and z is maintenance | ||||
4320 | version. So 3.0.0 is C<3.000000>, and 3.4.80 is C<3.004080>. | ||||
4321 | |||||
4322 | =cut | ||||
4323 | |||||
4324 | push (@cmds, { | ||||
4325 | setting => 'require_version', | ||||
4326 | type => $CONF_TYPE_STRING, | ||||
4327 | code => sub { | ||||
4328 | } | ||||
4329 | 1 | 8µs | }); | ||
4330 | |||||
4331 | =back | ||||
4332 | |||||
4333 | =head1 TEMPLATE TAGS | ||||
4334 | |||||
4335 | The following C<tags> can be used as placeholders in certain options. | ||||
4336 | They will be replaced by the corresponding value when they are used. | ||||
4337 | |||||
4338 | Some tags can take an argument (in parentheses). The argument is | ||||
4339 | optional, and the default is shown below. | ||||
4340 | |||||
4341 | _YESNO_ "Yes" for spam, "No" for nonspam (=ham) | ||||
4342 | _YESNO(spam_str,ham_str)_ returns the first argument ("Yes" if missing) | ||||
4343 | for spam, and the second argument ("No" if missing) for ham | ||||
4344 | _YESNOCAPS_ "YES" for spam, "NO" for nonspam (=ham) | ||||
4345 | _YESNOCAPS(spam_str,ham_str)_ same as _YESNO(...)_, but uppercased | ||||
4346 | _SCORE(PAD)_ message score, if PAD is included and is either spaces or | ||||
4347 | zeroes, then pad scores with that many spaces or zeroes | ||||
4348 | (default, none) ie: _SCORE(0)_ makes 2.4 become 02.4, | ||||
4349 | _SCORE(00)_ is 002.4. 12.3 would be 12.3 and 012.3 | ||||
4350 | respectively. | ||||
4351 | _REQD_ message threshold | ||||
4352 | _VERSION_ version (eg. 3.0.0 or 3.1.0-r26142-foo1) | ||||
4353 | _SUBVERSION_ sub-version/code revision date (eg. 2004-01-10) | ||||
4354 | _RULESVERSION_ comma-separated list of rules versions, retrieved from | ||||
4355 | an '# UPDATE version' comment in rules files; if there is | ||||
4356 | more than one set of rules (update channels) the order | ||||
4357 | is unspecified (currently sorted by names of files); | ||||
4358 | _HOSTNAME_ hostname of the machine the mail was processed on | ||||
4359 | _REMOTEHOSTNAME_ hostname of the machine the mail was sent from, only | ||||
4360 | available with spamd | ||||
4361 | _REMOTEHOSTADDR_ ip address of the machine the mail was sent from, only | ||||
4362 | available with spamd | ||||
4363 | _BAYES_ bayes score | ||||
4364 | _TOKENSUMMARY_ number of new, neutral, spammy, and hammy tokens found | ||||
4365 | _BAYESTC_ number of new tokens found | ||||
4366 | _BAYESTCLEARNED_ number of seen tokens found | ||||
4367 | _BAYESTCSPAMMY_ number of spammy tokens found | ||||
4368 | _BAYESTCHAMMY_ number of hammy tokens found | ||||
4369 | _HAMMYTOKENS(N)_ the N most significant hammy tokens (default, 5) | ||||
4370 | _SPAMMYTOKENS(N)_ the N most significant spammy tokens (default, 5) | ||||
4371 | _DATE_ rfc-2822 date of scan | ||||
4372 | _STARS(*)_ one "*" (use any character) for each full score point | ||||
4373 | (note: limited to 50 'stars') | ||||
4374 | _SENDERDOMAIN_ a domain name of the envelope sender address, lowercased | ||||
4375 | _AUTHORDOMAIN_ a domain name of the author address (the From header | ||||
4376 | field), lowercased; note that RFC 5322 allows a mail | ||||
4377 | message to have multiple authors - currently only the | ||||
4378 | domain name of the first email address is returned | ||||
4379 | _RELAYSTRUSTED_ relays used and deemed to be trusted (see the | ||||
4380 | 'X-Spam-Relays-Trusted' pseudo-header) | ||||
4381 | _RELAYSUNTRUSTED_ relays used that can not be trusted (see the | ||||
4382 | 'X-Spam-Relays-Untrusted' pseudo-header) | ||||
4383 | _RELAYSINTERNAL_ relays used and deemed to be internal (see the | ||||
4384 | 'X-Spam-Relays-Internal' pseudo-header) | ||||
4385 | _RELAYSEXTERNAL_ relays used and deemed to be external (see the | ||||
4386 | 'X-Spam-Relays-External' pseudo-header) | ||||
4387 | _LASTEXTERNALIP_ IP address of client in the external-to-internal | ||||
4388 | SMTP handover | ||||
4389 | _LASTEXTERNALRDNS_ reverse-DNS of client in the external-to-internal | ||||
4390 | SMTP handover | ||||
4391 | _LASTEXTERNALHELO_ HELO string used by client in the external-to-internal | ||||
4392 | SMTP handover | ||||
4393 | _AUTOLEARN_ autolearn status ("ham", "no", "spam", "disabled", | ||||
4394 | "failed", "unavailable") | ||||
4395 | _AUTOLEARNSCORE_ portion of message score used by autolearn | ||||
4396 | _TESTS(,)_ tests hit separated by "," (or other separator) | ||||
4397 | _TESTSSCORES(,)_ as above, except with scores appended (eg. AWL=-3.0,...) | ||||
4398 | _SUBTESTS(,)_ subtests (start with "__") hit separated by "," | ||||
4399 | (or other separator) | ||||
4400 | _DCCB_ DCC's "Brand" | ||||
4401 | _DCCR_ DCC's results | ||||
4402 | _PYZOR_ Pyzor results | ||||
4403 | _RBL_ full results for positive RBL queries in DNS URI format | ||||
4404 | _LANGUAGES_ possible languages of mail | ||||
4405 | _PREVIEW_ content preview | ||||
4406 | _REPORT_ terse report of tests hit (for header reports) | ||||
4407 | _SUMMARY_ summary of tests hit for standard report (for body reports) | ||||
4408 | _CONTACTADDRESS_ contents of the 'report_contact' setting | ||||
4409 | _HEADER(NAME)_ includes the value of a message header. value is the same | ||||
4410 | as is found for header rules (see elsewhere in this doc) | ||||
4411 | _TIMING_ timing breakdown report | ||||
4412 | _ADDEDHEADERHAM_ resulting header fields as requested by add_header for spam | ||||
4413 | _ADDEDHEADERSPAM_ resulting header fields as requested by add_header for ham | ||||
4414 | _ADDEDHEADER_ same as ADDEDHEADERHAM for ham or ADDEDHEADERSPAM for spam | ||||
4415 | |||||
4416 | If a tag reference uses the name of a tag which is not in this list or defined | ||||
4417 | by a loaded plugin, the reference will be left intact and not replaced by any | ||||
4418 | value. | ||||
4419 | |||||
4420 | The C<HAMMYTOKENS> and C<SPAMMYTOKENS> tags have an optional second argument | ||||
4421 | which specifies a format. See the B<HAMMYTOKENS/SPAMMYTOKENS TAG FORMAT> | ||||
4422 | section, below, for details. | ||||
4423 | |||||
4424 | =head2 HAMMYTOKENS/SPAMMYTOKENS TAG FORMAT | ||||
4425 | |||||
4426 | The C<HAMMYTOKENS> and C<SPAMMYTOKENS> tags have an optional second argument | ||||
4427 | which specifies a format: C<_SPAMMYTOKENS(N,FMT)_>, C<_HAMMYTOKENS(N,FMT)_> | ||||
4428 | The following formats are available: | ||||
4429 | |||||
4430 | =over 4 | ||||
4431 | |||||
4432 | =item short | ||||
4433 | |||||
4434 | Only the tokens themselves are listed. | ||||
4435 | I<For example, preference file entry:> | ||||
4436 | |||||
4437 | C<add_header all Spammy _SPAMMYTOKENS(2,short)_> | ||||
4438 | |||||
4439 | I<Results in message header:> | ||||
4440 | |||||
4441 | C<X-Spam-Spammy: remove.php, UD:jpg> | ||||
4442 | |||||
4443 | Indicating that the top two spammy tokens found are C<remove.php> | ||||
4444 | and C<UD:jpg>. (The token itself follows the last colon, the | ||||
4445 | text before the colon indicates something about the token. | ||||
4446 | C<UD> means the token looks like it might be part of a domain name.) | ||||
4447 | |||||
4448 | =item compact | ||||
4449 | |||||
4450 | The token probability, an abbreviated declassification distance (see | ||||
4451 | example), and the token are listed. | ||||
4452 | I<For example, preference file entry:> | ||||
4453 | |||||
4454 | C<add_header all Spammy _SPAMMYTOKENS(2,compact)_> | ||||
4455 | |||||
4456 | I<Results in message header:> | ||||
4457 | |||||
4458 | C<0.989-6--remove.php, 0.988-+--UD:jpg> | ||||
4459 | |||||
4460 | Indicating that the probabilities of the top two tokens are 0.989 and | ||||
4461 | 0.988, respectively. The first token has a declassification distance | ||||
4462 | of 6, meaning that if the token had appeared in at least 6 more ham | ||||
4463 | messages it would not be considered spammy. The C<+> for the second | ||||
4464 | token indicates a declassification distance greater than 9. | ||||
4465 | |||||
4466 | =item long | ||||
4467 | |||||
4468 | Probability, declassification distance, number of times seen in a ham | ||||
4469 | message, number of times seen in a spam message, age and the token are | ||||
4470 | listed. | ||||
4471 | |||||
4472 | I<For example, preference file entry:> | ||||
4473 | |||||
4474 | C<add_header all Spammy _SPAMMYTOKENS(2,long)_> | ||||
4475 | |||||
4476 | I<Results in message header:> | ||||
4477 | |||||
4478 | C<X-Spam-Spammy: 0.989-6--0h-4s--4d--remove.php, 0.988-33--2h-25s--1d--UD:jpg> | ||||
4479 | |||||
4480 | In addition to the information provided by the compact option, | ||||
4481 | the long option shows that the first token appeared in zero | ||||
4482 | ham messages and four spam messages, and that it was last | ||||
4483 | seen four days ago. The second token appeared in two ham messages, | ||||
4484 | 25 spam messages and was last seen one day ago. | ||||
4485 | (Unlike the C<compact> option, the long option shows declassification | ||||
4486 | distances that are greater than 9.) | ||||
4487 | |||||
4488 | =back | ||||
4489 | |||||
4490 | =cut | ||||
4491 | |||||
4492 | 1 | 31µs | return \@cmds; | ||
4493 | } | ||||
4494 | |||||
4495 | ########################################################################### | ||||
4496 | |||||
4497 | # settings that were once part of core, but are now in (possibly-optional) | ||||
4498 | # bundled plugins. These will be warned about, but do not generate a fatal | ||||
4499 | # error when "spamassassin --lint" is run like a normal syntax error would. | ||||
4500 | |||||
4501 | 1 | 3µs | @MIGRATED_SETTINGS = qw{ | ||
4502 | ok_languages | ||||
4503 | }; | ||||
4504 | |||||
4505 | ########################################################################### | ||||
4506 | |||||
4507 | # spent 29.8ms (350µs+29.5) within Mail::SpamAssassin::Conf::new which was called:
# once (350µs+29.5ms) by Mail::SpamAssassin::new at line 431 of Mail/SpamAssassin.pm | ||||
4508 | 1 | 2µs | my $class = shift; | ||
4509 | 1 | 2µs | $class = ref($class) || $class; | ||
4510 | 1 | 6µs | my $self = { | ||
4511 | main => shift, | ||||
4512 | registered_commands => [], | ||||
4513 | 1 | 2µs | }; bless ($self, $class); | ||
4514 | |||||
4515 | 1 | 20µs | 1 | 30µs | $self->{parser} = Mail::SpamAssassin::Conf::Parser->new($self); # spent 30µs making 1 call to Mail::SpamAssassin::Conf::Parser::new |
4516 | 1 | 28µs | 2 | 22.7ms | $self->{parser}->register_commands($self->set_default_commands()); # spent 20.4ms making 1 call to Mail::SpamAssassin::Conf::set_default_commands
# spent 2.28ms making 1 call to Mail::SpamAssassin::Conf::Parser::register_commands |
4517 | |||||
4518 | 1 | 4µs | $self->{errors} = 0; | ||
4519 | 1 | 3µs | $self->{plugins_loaded} = { }; | ||
4520 | |||||
4521 | 1 | 3µs | $self->{tests} = { }; | ||
4522 | 1 | 6µs | $self->{test_types} = { }; | ||
4523 | 1 | 8µs | $self->{scoreset} = [ {}, {}, {}, {} ]; | ||
4524 | 1 | 3µs | $self->{scoreset_current} = 0; | ||
4525 | 1 | 10µs | 1 | 40µs | $self->set_score_set (0); # spent 40µs making 1 call to Mail::SpamAssassin::Conf::set_score_set |
4526 | 1 | 3µs | $self->{tflags} = { }; | ||
4527 | 1 | 3µs | $self->{source_file} = { }; | ||
4528 | |||||
4529 | # keep descriptions in a slow but space-efficient single-string | ||||
4530 | # data structure | ||||
4531 | 2 | 35µs | 1 | 15µs | tie %{$self->{descriptions}}, 'Mail::SpamAssassin::Util::TieOneStringHash' # spent 15µs making 1 call to Mail::SpamAssassin::Util::TieOneStringHash::TIEHASH |
4532 | or warn "tie failed"; | ||||
4533 | |||||
4534 | # after parsing, tests are refiled into these hashes for each test type. | ||||
4535 | # this allows e.g. a full-text test to be rewritten as a body test in | ||||
4536 | # the user's user_prefs file. | ||||
4537 | 1 | 4µs | $self->{body_tests} = { }; | ||
4538 | 1 | 3µs | $self->{uri_tests} = { }; | ||
4539 | 1 | 3µs | $self->{uri_evals} = { }; # not used/implemented yet | ||
4540 | 1 | 3µs | $self->{head_tests} = { }; | ||
4541 | 1 | 3µs | $self->{head_evals} = { }; | ||
4542 | 1 | 3µs | $self->{body_evals} = { }; | ||
4543 | 1 | 3µs | $self->{full_tests} = { }; | ||
4544 | 1 | 3µs | $self->{full_evals} = { }; | ||
4545 | 1 | 3µs | $self->{rawbody_tests} = { }; | ||
4546 | 1 | 3µs | $self->{rawbody_evals} = { }; | ||
4547 | 1 | 3µs | $self->{meta_tests} = { }; | ||
4548 | 1 | 3µs | $self->{eval_plugins} = { }; | ||
4549 | 1 | 4µs | $self->{duplicate_rules} = { }; | ||
4550 | |||||
4551 | # testing stuff | ||||
4552 | 1 | 4µs | $self->{regression_tests} = { }; | ||
4553 | |||||
4554 | 1 | 3µs | $self->{rewrite_header} = { }; | ||
4555 | 1 | 3µs | $self->{want_rebuild_for_type} = { }; | ||
4556 | 1 | 3µs | $self->{user_defined_rules} = { }; | ||
4557 | 1 | 3µs | $self->{headers_spam} = [ ]; | ||
4558 | 1 | 3µs | $self->{headers_ham} = [ ]; | ||
4559 | |||||
4560 | 1 | 3µs | $self->{bayes_ignore_headers} = [ ]; | ||
4561 | 1 | 3µs | $self->{bayes_ignore_from} = { }; | ||
4562 | 1 | 2µs | $self->{bayes_ignore_to} = { }; | ||
4563 | |||||
4564 | 1 | 3µs | $self->{whitelist_auth} = { }; | ||
4565 | 1 | 2µs | $self->{def_whitelist_auth} = { }; | ||
4566 | 1 | 2µs | $self->{whitelist_from} = { }; | ||
4567 | 1 | 2µs | $self->{whitelist_allows_relays} = { }; | ||
4568 | 1 | 2µs | $self->{blacklist_from} = { }; | ||
4569 | 1 | 3µs | $self->{whitelist_from_rcvd} = { }; | ||
4570 | 1 | 2µs | $self->{def_whitelist_from_rcvd} = { }; | ||
4571 | |||||
4572 | 1 | 2µs | $self->{blacklist_to} = { }; | ||
4573 | 1 | 2µs | $self->{whitelist_to} = { }; | ||
4574 | 1 | 3µs | $self->{more_spam_to} = { }; | ||
4575 | 1 | 2µs | $self->{all_spam_to} = { }; | ||
4576 | |||||
4577 | 1 | 11µs | 1 | 4.43ms | $self->{trusted_networks} = $self->new_netset('trusted_networks',1); # spent 4.43ms making 1 call to Mail::SpamAssassin::Conf::new_netset |
4578 | 1 | 9µs | 1 | 2.24ms | $self->{internal_networks} = $self->new_netset('internal_networks',1); # spent 2.24ms making 1 call to Mail::SpamAssassin::Conf::new_netset |
4579 | 1 | 8µs | 1 | 66µs | $self->{msa_networks} = $self->new_netset('msa_networks',0); # no loopback IP # spent 66µs making 1 call to Mail::SpamAssassin::Conf::new_netset |
4580 | 1 | 3µs | $self->{trusted_networks_configured} = 0; | ||
4581 | 1 | 3µs | $self->{internal_networks_configured} = 0; | ||
4582 | |||||
4583 | # Make sure we add in X-Spam-Checker-Version | ||||
4584 | 2 | 7µs | { my $r = [ "Checker-Version", | ||
4585 | "SpamAssassin _VERSION_ (_SUBVERSION_) on _HOSTNAME_" ]; | ||||
4586 | 2 | 7µs | push(@{$self->{headers_spam}}, $r); | ||
4587 | 2 | 7µs | push(@{$self->{headers_ham}}, $r); | ||
4588 | } | ||||
4589 | |||||
4590 | # RFC 6891: A good compromise may be the use of an EDNS maximum payload size | ||||
4591 | # of 4096 octets as a starting point. | ||||
4592 | 1 | 4µs | $self->{dns_options}->{edns} = 4096; | ||
4593 | |||||
4594 | # these should potentially be settable by end-users | ||||
4595 | # perhaps via plugin? | ||||
4596 | 1 | 2µs | $self->{num_check_received} = 9; | ||
4597 | 1 | 3µs | $self->{bayes_expiry_pct} = 0.75; | ||
4598 | 1 | 3µs | $self->{bayes_expiry_period} = 43200; | ||
4599 | 1 | 2µs | $self->{bayes_expiry_max_exponent} = 9; | ||
4600 | |||||
4601 | 1 | 3µs | $self->{encapsulated_content_description} = 'original message before SpamAssassin'; | ||
4602 | |||||
4603 | 1 | 10µs | $self; | ||
4604 | } | ||||
4605 | |||||
4606 | sub mtime { | ||||
4607 | my $self = shift; | ||||
4608 | if (@_) { | ||||
4609 | $self->{mtime} = shift; | ||||
4610 | } | ||||
4611 | return $self->{mtime}; | ||||
4612 | } | ||||
4613 | |||||
4614 | ########################################################################### | ||||
4615 | |||||
4616 | sub parse_scores_only { | ||||
4617 | my ($self) = @_; | ||||
4618 | $_[0]->{parser}->parse ($_[1], 1); | ||||
4619 | } | ||||
4620 | |||||
4621 | # spent 5.03s (24µs+5.03) within Mail::SpamAssassin::Conf::parse_rules which was called:
# once (24µs+5.03s) by Mail::SpamAssassin::init at line 1759 of Mail/SpamAssassin.pm | ||||
4622 | 1 | 2µs | my ($self) = @_; | ||
4623 | 1 | 23µs | 1 | 5.03s | $_[0]->{parser}->parse ($_[1], 0); # spent 5.03s making 1 call to Mail::SpamAssassin::Conf::Parser::parse |
4624 | } | ||||
4625 | |||||
4626 | ########################################################################### | ||||
4627 | |||||
4628 | # spent 86µs (67+19) within Mail::SpamAssassin::Conf::set_score_set which was called 2 times, avg 43µs/call:
# once (38µs+7µs) by Mail::SpamAssassin::init at line 1781 of Mail/SpamAssassin.pm
# once (28µs+12µs) by Mail::SpamAssassin::Conf::new at line 4525 | ||||
4629 | 2 | 5µs | my ($self, $set) = @_; | ||
4630 | 2 | 12µs | $self->{scores} = $self->{scoreset}->[$set]; | ||
4631 | 2 | 6µs | $self->{scoreset_current} = $set; | ||
4632 | 2 | 39µs | 2 | 19µs | dbg("config: score set $set chosen."); # spent 19µs making 2 calls to Mail::SpamAssassin::Logger::dbg, avg 9µs/call |
4633 | } | ||||
4634 | |||||
4635 | sub get_score_set { | ||||
4636 | my($self) = @_; | ||||
4637 | return $self->{scoreset_current}; | ||||
4638 | } | ||||
4639 | |||||
4640 | sub get_rule_types { | ||||
4641 | my ($self) = @_; | ||||
4642 | return @rule_types; | ||||
4643 | } | ||||
4644 | |||||
4645 | sub get_rule_keys { | ||||
4646 | my ($self, $test_type, $priority) = @_; | ||||
4647 | |||||
4648 | # special case rbl_evals since they do not have a priority | ||||
4649 | if ($test_type eq 'rbl_evals') { | ||||
4650 | return keys(%{$self->{$test_type}}); | ||||
4651 | } | ||||
4652 | |||||
4653 | if (defined($priority)) { | ||||
4654 | return keys(%{$self->{$test_type}->{$priority}}); | ||||
4655 | } | ||||
4656 | else { | ||||
4657 | my @rules; | ||||
4658 | foreach my $pri (keys(%{$self->{priorities}})) { | ||||
4659 | push(@rules, keys(%{$self->{$test_type}->{$pri}})); | ||||
4660 | } | ||||
4661 | return @rules; | ||||
4662 | } | ||||
4663 | } | ||||
4664 | |||||
4665 | sub get_rule_value { | ||||
4666 | my ($self, $test_type, $rulename, $priority) = @_; | ||||
4667 | |||||
4668 | # special case rbl_evals since they do not have a priority | ||||
4669 | if ($test_type eq 'rbl_evals') { | ||||
4670 | return keys(%{$self->{$test_type}->{$rulename}}); | ||||
4671 | } | ||||
4672 | |||||
4673 | if (defined($priority)) { | ||||
4674 | return $self->{$test_type}->{$priority}->{$rulename}; | ||||
4675 | } | ||||
4676 | else { | ||||
4677 | foreach my $pri (keys(%{$self->{priorities}})) { | ||||
4678 | if (exists($self->{$test_type}->{$pri}->{$rulename})) { | ||||
4679 | return $self->{$test_type}->{$pri}->{$rulename}; | ||||
4680 | } | ||||
4681 | } | ||||
4682 | return; # if we get here we didn't find the rule | ||||
4683 | } | ||||
4684 | } | ||||
4685 | |||||
4686 | sub delete_rule { | ||||
4687 | my ($self, $test_type, $rulename, $priority) = @_; | ||||
4688 | |||||
4689 | # special case rbl_evals since they do not have a priority | ||||
4690 | if ($test_type eq 'rbl_evals') { | ||||
4691 | return delete($self->{$test_type}->{$rulename}); | ||||
4692 | } | ||||
4693 | |||||
4694 | if (defined($priority)) { | ||||
4695 | return delete($self->{$test_type}->{$priority}->{$rulename}); | ||||
4696 | } | ||||
4697 | else { | ||||
4698 | foreach my $pri (keys(%{$self->{priorities}})) { | ||||
4699 | if (exists($self->{$test_type}->{$pri}->{$rulename})) { | ||||
4700 | return delete($self->{$test_type}->{$pri}->{$rulename}); | ||||
4701 | } | ||||
4702 | } | ||||
4703 | return; # if we get here we didn't find the rule | ||||
4704 | } | ||||
4705 | } | ||||
4706 | |||||
4707 | # trim_rules ($regexp) | ||||
4708 | # | ||||
4709 | # Remove all rules that don't match the given regexp (or are sub-rules of | ||||
4710 | # meta-tests that match the regexp). | ||||
4711 | |||||
4712 | sub trim_rules { | ||||
4713 | my ($self, $regexp) = @_; | ||||
4714 | |||||
4715 | my @all_rules; | ||||
4716 | |||||
4717 | foreach my $rule_type ($self->get_rule_types()) { | ||||
4718 | push(@all_rules, $self->get_rule_keys($rule_type)); | ||||
4719 | } | ||||
4720 | |||||
4721 | my @rules_to_keep = grep(/$regexp/, @all_rules); | ||||
4722 | |||||
4723 | if (@rules_to_keep == 0) { | ||||
4724 | die "config: trim_rules: all rules excluded, nothing to test\n"; | ||||
4725 | } | ||||
4726 | |||||
4727 | my @meta_tests = grep(/$regexp/, $self->get_rule_keys('meta_tests')); | ||||
4728 | foreach my $meta (@meta_tests) { | ||||
4729 | push(@rules_to_keep, $self->add_meta_depends($meta)) | ||||
4730 | } | ||||
4731 | |||||
4732 | my %rules_to_keep_hash; | ||||
4733 | |||||
4734 | foreach my $rule (@rules_to_keep) { | ||||
4735 | $rules_to_keep_hash{$rule} = 1; | ||||
4736 | } | ||||
4737 | |||||
4738 | foreach my $rule_type ($self->get_rule_types()) { | ||||
4739 | foreach my $rulekey ($self->get_rule_keys($rule_type)) { | ||||
4740 | $self->delete_rule($rule_type, $rulekey) | ||||
4741 | if (!$rules_to_keep_hash{$rulekey}); | ||||
4742 | } | ||||
4743 | } | ||||
4744 | } # trim_rules() | ||||
4745 | |||||
4746 | sub add_meta_depends { | ||||
4747 | my ($self, $meta) = @_; | ||||
4748 | |||||
4749 | my @rules; | ||||
4750 | my @tokens = $self->get_rule_value('meta_tests', $meta) =~ m/(\w+)/g; | ||||
4751 | |||||
4752 | @tokens = grep(!/^\d+$/, @tokens); | ||||
4753 | # @tokens now only consists of sub-rules | ||||
4754 | |||||
4755 | foreach my $token (@tokens) { | ||||
4756 | die "config: meta test $meta depends on itself\n" if $token eq $meta; | ||||
4757 | push(@rules, $token); | ||||
4758 | |||||
4759 | # If the sub-rule is a meta-test, recurse | ||||
4760 | if ($self->get_rule_value('meta_tests', $token)) { | ||||
4761 | push(@rules, $self->add_meta_depends($token)); | ||||
4762 | } | ||||
4763 | } # foreach my $token (@tokens) | ||||
4764 | |||||
4765 | return @rules; | ||||
4766 | } # add_meta_depends() | ||||
4767 | |||||
4768 | # spent 244ms within Mail::SpamAssassin::Conf::is_rule_active which was called 5382 times, avg 45µs/call:
# 5382 times (244ms+0s) by Mail::SpamAssassin::Plugin::URIDNSBL::parsed_metadata at line 368 of Mail/SpamAssassin/Plugin/URIDNSBL.pm, avg 45µs/call | ||||
4769 | 5382 | 11.4ms | my ($self, $test_type, $rulename, $priority) = @_; | ||
4770 | |||||
4771 | # special case rbl_evals since they do not have a priority | ||||
4772 | 5382 | 9.63ms | if ($test_type eq 'rbl_evals') { | ||
4773 | return 0 unless ($self->{$test_type}->{$rulename}); | ||||
4774 | return ($self->{scores}->{$rulename}); | ||||
4775 | } | ||||
4776 | |||||
4777 | # first determine if the rule is defined | ||||
4778 | 5382 | 17.3ms | if (defined($priority)) { | ||
4779 | # we have a specific priority | ||||
4780 | return 0 unless ($self->{$test_type}->{$priority}->{$rulename}); | ||||
4781 | } | ||||
4782 | else { | ||||
4783 | # no specific priority so we must loop over all currently defined | ||||
4784 | # priorities to see if the rule is defined | ||||
4785 | 5382 | 9.58ms | my $found_p = 0; | ||
4786 | 10764 | 38.3ms | foreach my $pri (keys %{$self->{priorities}}) { | ||
4787 | 5382 | 52.6ms | if ($self->{$test_type}->{$pri}->{$rulename}) { | ||
4788 | 5382 | 8.74ms | $found_p = 1; | ||
4789 | 5382 | 24.9ms | last; | ||
4790 | } | ||||
4791 | } | ||||
4792 | 5382 | 8.99ms | return 0 unless ($found_p); | ||
4793 | } | ||||
4794 | |||||
4795 | 5382 | 90.9ms | return ($self->{scores}->{$rulename}); | ||
4796 | } | ||||
4797 | |||||
4798 | ########################################################################### | ||||
4799 | |||||
4800 | # treats a bitset argument as a bit vector of all possible port numbers (8 kB) | ||||
4801 | # and sets bit values to $value (0 or 1) in the specified range of port numbers | ||||
4802 | # | ||||
4803 | # spent 80.1ms (80.1+22µs) within Mail::SpamAssassin::Conf::set_ports_range which was called 190 times, avg 422µs/call:
# 190 times (80.1ms+22µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1685] at line 1683, avg 422µs/call | ||||
4804 | 190 | 887µs | my($bitset_ref, $port_range_lo, $port_range_hi, $value) = @_; | ||
4805 | 190 | 365µs | $port_range_lo = 0 if $port_range_lo < 0; | ||
4806 | 190 | 320µs | $port_range_hi = 65535 if $port_range_hi > 65535; | ||
4807 | 190 | 337µs | if (!defined $$bitset_ref) { # provide a sensible default | ||
4808 | 1 | 9µs | 1 | 22µs | wipe_ports_range($bitset_ref, 1); # turn on all bits 0..65535 # spent 22µs making 1 call to Mail::SpamAssassin::Conf::wipe_ports_range |
4809 | 1 | 2.55ms | vec($$bitset_ref,$_,1) = 0 for 0..1023; # avoid 0 and privileged ports | ||
4810 | } elsif ($$bitset_ref eq '') { # repopulate the bitset (late configuration) | ||||
4811 | wipe_ports_range($bitset_ref, 0); # turn off all bits 0..65535 | ||||
4812 | } | ||||
4813 | 190 | 319µs | $value = !$value ? 0 : 1; | ||
4814 | 190 | 45.9ms | for (my $j = $port_range_lo; $j <= $port_range_hi; $j++) { | ||
4815 | 11578 | 29.7ms | vec($$bitset_ref,$j,1) = $value; | ||
4816 | } | ||||
4817 | } | ||||
4818 | |||||
4819 | # spent 22µs within Mail::SpamAssassin::Conf::wipe_ports_range which was called:
# once (22µs+0s) by Mail::SpamAssassin::Conf::set_ports_range at line 4808 | ||||
4820 | 1 | 2µs | my($bitset_ref, $value) = @_; | ||
4821 | 1 | 4µs | $value = !$value ? "\000" : "\377"; | ||
4822 | 1 | 19µs | $$bitset_ref = $value x 8192; # quickly turn all bits 0..65535 on or off | ||
4823 | } | ||||
4824 | |||||
4825 | ########################################################################### | ||||
4826 | |||||
4827 | sub add_to_addrlist { | ||||
4828 | my $self = shift; $self->{parser}->add_to_addrlist(@_); | ||||
4829 | } | ||||
4830 | sub add_to_addrlist_rcvd { | ||||
4831 | my $self = shift; $self->{parser}->add_to_addrlist_rcvd(@_); | ||||
4832 | } | ||||
4833 | sub remove_from_addrlist { | ||||
4834 | my $self = shift; $self->{parser}->remove_from_addrlist(@_); | ||||
4835 | } | ||||
4836 | sub remove_from_addrlist_rcvd { | ||||
4837 | my $self = shift; $self->{parser}->remove_from_addrlist_rcvd(@_); | ||||
4838 | } | ||||
4839 | |||||
4840 | ########################################################################### | ||||
4841 | |||||
4842 | sub regression_tests { | ||||
4843 | my $self = shift; | ||||
4844 | if (@_ == 1) { | ||||
4845 | # we specified a symbolic name, return the strings | ||||
4846 | my $name = shift; | ||||
4847 | my $tests = $self->{regression_tests}->{$name}; | ||||
4848 | return @$tests; | ||||
4849 | } | ||||
4850 | else { | ||||
4851 | # no name asked for, just return the symbolic names we have tests for | ||||
4852 | return keys %{$self->{regression_tests}}; | ||||
4853 | } | ||||
4854 | } | ||||
4855 | |||||
4856 | ########################################################################### | ||||
4857 | |||||
4858 | # spent 7.67s (31µs+7.67) within Mail::SpamAssassin::Conf::finish_parsing which was called:
# once (31µs+7.67s) by Mail::SpamAssassin::init at line 1760 of Mail/SpamAssassin.pm | ||||
4859 | 1 | 2µs | my ($self, $user) = @_; | ||
4860 | 1 | 21µs | 1 | 7.67s | $self->{parser}->finish_parsing($user); # spent 7.67s making 1 call to Mail::SpamAssassin::Conf::Parser::finish_parsing |
4861 | } | ||||
4862 | |||||
4863 | ########################################################################### | ||||
4864 | |||||
4865 | # spent 28µs within Mail::SpamAssassin::Conf::found_any_rules which was called:
# once (28µs+0s) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 947 of Mail/SpamAssassin/Conf/Parser.pm | ||||
4866 | 1 | 3µs | my ($self) = @_; | ||
4867 | 1 | 6µs | if (!defined $self->{found_any_rules}) { | ||
4868 | 2 | 11µs | $self->{found_any_rules} = (scalar keys %{$self->{tests}} > 0); | ||
4869 | } | ||||
4870 | 1 | 12µs | return $self->{found_any_rules}; | ||
4871 | } | ||||
4872 | |||||
4873 | ########################################################################### | ||||
4874 | |||||
4875 | sub get_description_for_rule { | ||||
4876 | my ($self, $rule) = @_; | ||||
4877 | # as silly as it looks, localized $1 here prevents an outer $1 from getting | ||||
4878 | # tainted by the expression or assignment in the next line, bug 6148 | ||||
4879 | local($1); | ||||
4880 | my $rule_descr = $self->{descriptions}->{$rule}; | ||||
4881 | return $rule_descr; | ||||
4882 | } | ||||
4883 | |||||
4884 | ########################################################################### | ||||
4885 | |||||
4886 | sub maybe_header_only { | ||||
4887 | my($self,$rulename) = @_; | ||||
4888 | my $type = $self->{test_types}->{$rulename}; | ||||
4889 | |||||
4890 | if ($rulename =~ /AUTOLEARNTEST/i) { | ||||
4891 | dbg("config: auto-learn: $rulename - Test type is $self->{test_types}->{$rulename}."); | ||||
4892 | } | ||||
4893 | |||||
4894 | return 0 if (!defined ($type)); | ||||
4895 | |||||
4896 | if (($type == $TYPE_HEAD_TESTS) || ($type == $TYPE_HEAD_EVALS)) { | ||||
4897 | return 1; | ||||
4898 | |||||
4899 | } elsif ($type == $TYPE_META_TESTS) { | ||||
4900 | my $tflags = $self->{tflags}->{$rulename}; | ||||
4901 | $tflags ||= ''; | ||||
4902 | if ($tflags =~ m/\bnet\b/i) { | ||||
4903 | return 0; | ||||
4904 | } else { | ||||
4905 | return 1; | ||||
4906 | } | ||||
4907 | } | ||||
4908 | |||||
4909 | return 0; | ||||
4910 | } | ||||
4911 | |||||
4912 | sub maybe_body_only { | ||||
4913 | my($self,$rulename) = @_; | ||||
4914 | my $type = $self->{test_types}->{$rulename}; | ||||
4915 | |||||
4916 | if ($rulename =~ /AUTOLEARNTEST/i) { | ||||
4917 | dbg("config: auto-learn: $rulename - Test type is $self->{test_types}->{$rulename}."); | ||||
4918 | } | ||||
4919 | |||||
4920 | return 0 if (!defined ($type)); | ||||
4921 | |||||
4922 | if (($type == $TYPE_BODY_TESTS) || ($type == $TYPE_BODY_EVALS) | ||||
4923 | || ($type == $TYPE_URI_TESTS) || ($type == $TYPE_URI_EVALS)) | ||||
4924 | { | ||||
4925 | # some rawbody go off of headers... | ||||
4926 | return 1; | ||||
4927 | |||||
4928 | } elsif ($type == $TYPE_META_TESTS) { | ||||
4929 | my $tflags = $self->{tflags}->{$rulename}; $tflags ||= ''; | ||||
4930 | if ($tflags =~ m/\bnet\b/i) { | ||||
4931 | return 0; | ||||
4932 | } else { | ||||
4933 | return 1; | ||||
4934 | } | ||||
4935 | } | ||||
4936 | |||||
4937 | return 0; | ||||
4938 | } | ||||
4939 | |||||
4940 | ########################################################################### | ||||
4941 | |||||
4942 | # spent 507ms (701µs+506) within Mail::SpamAssassin::Conf::load_plugin which was called 27 times, avg 18.8ms/call:
# 27 times (701µs+506ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:4145] at line 4144, avg 18.8ms/call | ||||
4943 | 27 | 94µs | my ($self, $package, $path, $silent) = @_; | ||
4944 | 27 | 48µs | if ($path) { | ||
4945 | $path = $self->{parser}->fix_path_relative_to_current_file($path); | ||||
4946 | } | ||||
4947 | # it wouldn't hurt to do some checking on validity of $package | ||||
4948 | # and $path before untainting them | ||||
4949 | 27 | 530µs | 54 | 506ms | $self->{main}->{plugins}->load_plugin(untaint_var($package), $path, $silent); # spent 506ms making 27 calls to Mail::SpamAssassin::PluginHandler::load_plugin, avg 18.7ms/call
# spent 612µs making 27 calls to Mail::SpamAssassin::Util::untaint_var, avg 23µs/call |
4950 | } | ||||
4951 | |||||
4952 | # spent 304µs within Mail::SpamAssassin::Conf::load_plugin_succeeded which was called 27 times, avg 11µs/call:
# 27 times (304µs+0s) by Mail::SpamAssassin::PluginHandler::load_plugin at line 137 of Mail/SpamAssassin/PluginHandler.pm, avg 11µs/call | ||||
4953 | 27 | 87µs | my ($self, $plugin, $package, $path) = @_; | ||
4954 | 27 | 263µs | $self->{plugins_loaded}->{$package} = 1; | ||
4955 | } | ||||
4956 | |||||
4957 | # spent 1.78ms within Mail::SpamAssassin::Conf::register_eval_rule which was called 192 times, avg 9µs/call:
# 192 times (1.78ms+0s) by Mail::SpamAssassin::Plugin::register_eval_rule at line 1030 of Mail/SpamAssassin/Plugin.pm, avg 9µs/call | ||||
4958 | 192 | 409µs | my ($self, $pluginobj, $nameofsub) = @_; | ||
4959 | 192 | 1.81ms | $self->{eval_plugins}->{$nameofsub} = $pluginobj; | ||
4960 | } | ||||
4961 | |||||
4962 | ########################################################################### | ||||
4963 | |||||
4964 | sub clone { | ||||
4965 | my ($self, $source, $dest) = @_; | ||||
4966 | |||||
4967 | unless (defined $source) { | ||||
4968 | $source = $self; | ||||
4969 | } | ||||
4970 | unless (defined $dest) { | ||||
4971 | $dest = $self; | ||||
4972 | } | ||||
4973 | |||||
4974 | my %done; | ||||
4975 | |||||
4976 | # keys that should not be copied in ->clone(). | ||||
4977 | # bug 4179: include want_rebuild_for_type, so that if a user rule | ||||
4978 | # is defined, its method will be recompiled for future scans in | ||||
4979 | # order to *remove* the generated method calls | ||||
4980 | my @NON_COPIED_KEYS = qw( | ||||
4981 | main eval_plugins plugins_loaded registered_commands sed_path_cache parser | ||||
4982 | scoreset scores want_rebuild_for_type | ||||
4983 | ); | ||||
4984 | |||||
4985 | # special cases. first, skip anything that cannot be changed | ||||
4986 | # by users, and the stuff we take care of here | ||||
4987 | foreach my $var (@NON_COPIED_KEYS) { | ||||
4988 | $done{$var} = undef; | ||||
4989 | } | ||||
4990 | |||||
4991 | # keys that should can be copied using a ->clone() method, in ->clone() | ||||
4992 | my @CLONABLE_KEYS = qw( | ||||
4993 | internal_networks trusted_networks msa_networks | ||||
4994 | ); | ||||
4995 | |||||
4996 | foreach my $key (@CLONABLE_KEYS) { | ||||
4997 | $dest->{$key} = $source->{$key}->clone(); | ||||
4998 | $done{$key} = undef; | ||||
4999 | } | ||||
5000 | |||||
5001 | # two-level hashes | ||||
5002 | foreach my $key (qw(uri_host_lists askdns)) { | ||||
5003 | my $v = $source->{$key}; | ||||
5004 | my $dest_key_ref = $dest->{$key} = {}; # must start from scratch! | ||||
5005 | while(my($k2,$v2) = each %{$v}) { | ||||
5006 | %{$dest_key_ref->{$k2}} = %{$v2}; | ||||
5007 | } | ||||
5008 | $done{$key} = undef; | ||||
5009 | } | ||||
5010 | |||||
5011 | # bug 4179: be smarter about cloning the rule-type structures; | ||||
5012 | # some are like this: $self->{type}->{priority}->{name} = 'value'; | ||||
5013 | # which is an extra level that the below code won't deal with | ||||
5014 | foreach my $t (@rule_types) { | ||||
5015 | foreach my $k (keys %{$source->{$t}}) { | ||||
5016 | my $v = $source->{$t}->{$k}; | ||||
5017 | my $i = ref $v; | ||||
5018 | if ($i eq 'HASH') { | ||||
5019 | %{$dest->{$t}->{$k}} = %{$v}; | ||||
5020 | } | ||||
5021 | elsif ($i eq 'ARRAY') { | ||||
5022 | @{$dest->{$t}->{$k}} = @{$v}; | ||||
5023 | } | ||||
5024 | else { | ||||
5025 | $dest->{$t}->{$k} = $v; | ||||
5026 | } | ||||
5027 | } | ||||
5028 | $done{$t} = undef; | ||||
5029 | } | ||||
5030 | |||||
5031 | # and now, copy over all the rest -- the less complex cases. | ||||
5032 | while(my($k,$v) = each %{$source}) { | ||||
5033 | next if exists $done{$k}; # we handled it above | ||||
5034 | $done{$k} = undef; | ||||
5035 | my $i = ref($v); | ||||
5036 | |||||
5037 | # Not a reference, or a scalar? Just copy the value over. | ||||
5038 | if ($i eq '') { | ||||
5039 | $dest->{$k} = $v; | ||||
5040 | } | ||||
5041 | elsif ($i eq 'SCALAR') { | ||||
5042 | $dest->{$k} = $$v; | ||||
5043 | } | ||||
5044 | elsif ($i eq 'ARRAY') { | ||||
5045 | @{$dest->{$k}} = @{$v}; | ||||
5046 | } | ||||
5047 | elsif ($i eq 'HASH') { | ||||
5048 | %{$dest->{$k}} = %{$v}; | ||||
5049 | } | ||||
5050 | else { | ||||
5051 | # throw a warning for debugging -- should never happen in normal usage | ||||
5052 | warn "config: dup unknown type $k, $i\n"; | ||||
5053 | } | ||||
5054 | } | ||||
5055 | |||||
5056 | foreach my $cmd (@{$self->{registered_commands}}) { | ||||
5057 | my $k = $cmd->{setting}; | ||||
5058 | next if exists $done{$k}; # we handled it above | ||||
5059 | $done{$k} = undef; | ||||
5060 | $dest->{$k} = $source->{$k}; | ||||
5061 | } | ||||
5062 | |||||
5063 | # scoresets | ||||
5064 | delete $dest->{scoreset}; | ||||
5065 | for my $i (0 .. 3) { | ||||
5066 | %{$dest->{scoreset}->[$i]} = %{$source->{scoreset}->[$i]}; | ||||
5067 | } | ||||
5068 | |||||
5069 | # deal with $conf->{scores}, it needs to be a reference into the scoreset | ||||
5070 | # hash array dealy. Do it at the end since scoreset_current isn't set | ||||
5071 | # otherwise. | ||||
5072 | $dest->{scores} = $dest->{scoreset}->[$dest->{scoreset_current}]; | ||||
5073 | |||||
5074 | # ensure we don't copy the path cache from the master | ||||
5075 | delete $dest->{sed_path_cache}; | ||||
5076 | |||||
5077 | return 1; | ||||
5078 | } | ||||
5079 | |||||
5080 | ########################################################################### | ||||
5081 | |||||
5082 | sub free_uncompiled_rule_source { | ||||
5083 | my ($self) = @_; | ||||
5084 | |||||
5085 | if (!$self->{main}->{keep_config_parsing_metadata} && | ||||
5086 | !$self->{allow_user_rules}) | ||||
5087 | { | ||||
5088 | delete $self->{if_stack}; | ||||
5089 | #delete $self->{source_file}; | ||||
5090 | #delete $self->{meta_dependencies}; | ||||
5091 | } | ||||
5092 | } | ||||
5093 | |||||
5094 | # spent 6.73ms (103µs+6.63) within Mail::SpamAssassin::Conf::new_netset which was called 3 times, avg 2.24ms/call:
# once (53µs+4.38ms) by Mail::SpamAssassin::Conf::new at line 4577
# once (34µs+2.20ms) by Mail::SpamAssassin::Conf::new at line 4578
# once (16µs+50µs) by Mail::SpamAssassin::Conf::new at line 4579 | ||||
5095 | 3 | 7µs | my ($self, $netset_name, $add_loopback) = @_; | ||
5096 | 3 | 29µs | 3 | 240µs | my $set = Mail::SpamAssassin::NetSet->new($netset_name); # spent 240µs making 3 calls to Mail::SpamAssassin::NetSet::new, avg 80µs/call |
5097 | 3 | 8µs | if ($add_loopback) { | ||
5098 | 2 | 16µs | 2 | 4.73ms | $set->add_cidr('127.0.0.0/8'); # spent 4.73ms making 2 calls to Mail::SpamAssassin::NetSet::add_cidr, avg 2.36ms/call |
5099 | 2 | 14µs | 2 | 1.66ms | $set->add_cidr('::1'); # spent 1.66ms making 2 calls to Mail::SpamAssassin::NetSet::add_cidr, avg 831µs/call |
5100 | } | ||||
5101 | 3 | 26µs | return $set; | ||
5102 | } | ||||
5103 | |||||
5104 | ########################################################################### | ||||
5105 | |||||
5106 | sub finish { | ||||
5107 | my ($self) = @_; | ||||
5108 | untie %{$self->{descriptions}}; | ||||
5109 | %{$self} = (); | ||||
5110 | } | ||||
5111 | |||||
5112 | ########################################################################### | ||||
5113 | |||||
5114 | sub sa_die { Mail::SpamAssassin::sa_die(@_); } | ||||
5115 | |||||
5116 | ########################################################################### | ||||
5117 | |||||
5118 | # subroutines available to conditionalize rules, for example: | ||||
5119 | # if (can(Mail::SpamAssassin::Conf::feature_originating_ip_headers)) | ||||
5120 | |||||
5121 | 1 | 9µs | # spent 10µs within Mail::SpamAssassin::Conf::feature_originating_ip_headers which was called:
# once (10µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 595 of Mail/SpamAssassin/Conf/Parser.pm | ||
5122 | 1 | 10µs | # spent 8µs within Mail::SpamAssassin::Conf::feature_dns_local_ports_permit_avoid which was called:
# once (8µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 595 of Mail/SpamAssassin/Conf/Parser.pm | ||
5123 | sub feature_bayes_auto_learn_on_error { 1 } | ||||
5124 | sub feature_uri_host_listed { 1 } | ||||
5125 | 1 | 10µs | # spent 9µs within Mail::SpamAssassin::Conf::feature_yesno_takes_args which was called:
# once (9µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 595 of Mail/SpamAssassin/Conf/Parser.pm | ||
5126 | 24 | 237µs | # spent 301µs within Mail::SpamAssassin::Conf::feature_bug6558_free which was called 24 times, avg 13µs/call:
# 24 times (301µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 595 of Mail/SpamAssassin/Conf/Parser.pm, avg 13µs/call | ||
5127 | sub feature_edns { 1 } # supports 'dns_options edns' config option | ||||
5128 | sub feature_dns_query_restriction { 1 } # supported config option | ||||
5129 | 2 | 20µs | # spent 19µs within Mail::SpamAssassin::Conf::feature_registryboundaries which was called 2 times, avg 10µs/call:
# 2 times (19µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 595 of Mail/SpamAssassin/Conf/Parser.pm, avg 10µs/call | ||
5130 | 7 | 66µs | # spent 70µs within Mail::SpamAssassin::Conf::perl_min_version_5010000 which was called 7 times, avg 10µs/call:
# 7 times (70µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 595 of Mail/SpamAssassin/Conf/Parser.pm, avg 10µs/call | ||
5131 | |||||
5132 | ########################################################################### | ||||
5133 | |||||
5134 | 1 | 32µs | 1; | ||
5135 | __END__ | ||||
# spent 35µs within Mail::SpamAssassin::Conf::CORE:ftdir which was called:
# once (35µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3835] at line 3831 | |||||
# spent 31.7ms within Mail::SpamAssassin::Conf::CORE:match which was called 7701 times, avg 4µs/call:
# 2323 times (10.6ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:280] at line 252, avg 5µs/call
# 1387 times (4.82ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2951, avg 3µs/call
# 811 times (2.10ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:280] at line 239, avg 3µs/call
# 655 times (2.78ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3020] at line 3010, avg 4µs/call
# 465 times (1.46ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3174] at line 3169, avg 3µs/call
# 459 times (2.99ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3750] at line 3744, avg 7µs/call
# 459 times (1.77ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3750] at line 3741, avg 4µs/call
# 247 times (847µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1685] at line 1669, avg 3µs/call
# 175 times (637µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2954, avg 4µs/call
# 128 times (1.09ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3557] at line 3550, avg 9µs/call
# 128 times (326µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3557] at line 3547, avg 3µs/call
# 116 times (513µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2964, avg 4µs/call
# 77 times (401µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3206] at line 3198, avg 5µs/call
# 54 times (361µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:4145] at line 4135, avg 7µs/call
# 48 times (235µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3781] at line 3775, avg 5µs/call
# 48 times (154µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3781] at line 3772, avg 3µs/call
# 40 times (149µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3088] at line 3079, avg 4µs/call
# 19 times (67µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:433] at line 428, avg 4µs/call
# 19 times (48µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:433] at line 425, avg 3µs/call
# 15 times (95µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2701] at line 2694, avg 6µs/call
# 13 times (74µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3122] at line 3113, avg 6µs/call
# 5 times (72µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:935] at line 906, avg 14µs/call
# 5 times (15µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:935] at line 911, avg 3µs/call
# 2 times (6µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1419] at line 1411, avg 3µs/call
# once (8µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:1054] at line 1042
# once (7µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3858] at line 3856
# once (6µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3835] at line 3828 | |||||
# spent 103µs within Mail::SpamAssassin::Conf::CORE:qr which was called 15 times, avg 7µs/call:
# 15 times (103µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2701] at line 2697, avg 7µs/call | |||||
# spent 584µs within Mail::SpamAssassin::Conf::CORE:regcomp which was called 15 times, avg 39µs/call:
# 15 times (584µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2701] at line 2697, avg 39µs/call | |||||
# spent 5.10ms within Mail::SpamAssassin::Conf::CORE:subst which was called 2338 times, avg 2µs/call:
# 2323 times (5.07ms+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:280] at line 249, avg 2µs/call
# 5 times (13µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:935] at line 919, avg 3µs/call
# 5 times (12µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:935] at line 921, avg 2µs/call
# 5 times (11µs+0s) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:935] at line 920, avg 2µs/call |