]> git.madduck.net Git - etc/mailfilter.git/blob - procmail/spamfilter

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

replace existing x-tickle-delivered header
[etc/mailfilter.git] / procmail / spamfilter
1 #!/usr/bin/procmail
2
3 #TODO: rewrite to use SPAM variable, and do not autotrain spam here, only ham
4
5 PMDIR=${PMDIR:-$HOME/.etc/mailfilter/procmail}
6
7 :0
8 * !PMVAR ?? .
9 {
10   # PMVAR is not defined, so we are being called as filter
11   # thus source the standard defines
12   INCLUDERC=$PMDIR/defines
13   # prevent feeding back to procmail and delete the leading From line
14   PROCMAIL='/bin/cat'
15   # and tell the fucking procmail piece-of-shit to continue to be a filter
16   DEFAULT='|$PROCMAIL'
17 }
18
19 #VERBOSE=yes
20
21 # no need to reprocess messages that went into a spamtrap
22 # UPDATE: retrain them only if diagnosed as non-spam, see below
23 # Note: add E flag to next recipe when uncommenting
24 #:0
25 #* SPAMTRAPPED ?? .
26 #{
27 #  LOG="spamfilter:  skipping checks for spamtrapped message$NL"
28 #  :0 fw
29 #  |$FORMAIL -I"X-Spam: spamtrapped"
30 #}
31
32 # check whether this message is being reinjected
33 TRAINED_AS
34 :0
35 *$ $MSG_DEJAVU
36 * ^X-Trained-As: \/(h|sp)am
37 {
38   LOG="spamfilter:  skipping already trained $MATCH$NL"
39   :0
40   * MATCH ?? spam
41   { IS_SPAM=already-trained }
42 }
43
44 # let earlier parts of the mailfilter cause bypassing the checks
45 :0 E
46 * SKIP_SPAMCHECKS ?? .
47 {
48   LOG="spamfilter:  skipping checks as requested: $SKIP_SPAMCHECKS$NL"
49   :0 fw
50   |$FORMAIL -I"X-Spam: unknown (skip requested)"
51   SPAM_UNKNOWN=skip-requested
52 }
53
54 # honour skip-spamchecks to exclude certain messages from spam checks
55 # altogether
56 :0 EBH
57 * ? $EGREP -qif $CONF/skip-spamchecks
58 {
59   LOG="spamfilter:  skipping checks as per skip-spamchecks$NL"
60   :0 fw
61   |$FORMAIL -I"X-Spam: unknown (check skipped)"
62   SPAM_UNKNOWN=skip-match
63   SKIP_SPAMCHECKS=match
64 }
65
66 # sanity check on message size
67 :0 E
68 * > $SPAMCHECK_MAX_MESSAGE_SIZE
69 {
70   LOG="spamfilter:  skipping check because message size exceeds $SPAMCHECK_MAX_MESSAGE_SIZE bytes$NL"
71   :0 fw
72   |$FORMAIL -I"X-Spam: unknown (message larger than $SPAMCHECK_MAX_MESSAGE_SIZE bytes)"
73   SPAM_UNKNOWN=too-large
74 }
75
76 # now run the spamfilters
77 :0 E
78 {
79   INCLUDERC=$PMDIR/pre-spam-cleanup
80
81   # crm114
82   CRM_SPAM=UNKNOWN
83   CRM_SCORE=0
84   :0
85   * !SKIP_CRM ?? .
86   {
87     :0 fw
88     |$CRM114
89
90     :0
91     * ^X-CRM114-Status: \/[A-Z]+
92     { CRM_SPAM=$MATCH }
93
94     :0
95     * ^X-CRM114-Status: .+\([ ]*\/-?[.0-9]+
96     { CRM_SCORE=$MATCH }
97
98     LOG="crm114:      $CRM_SPAM/$CRM_SCORE$NL"
99   }
100
101   # spamassassin
102   SA_STATUS=Unknown
103   SA_SCORE=0
104   SA_TESTS=none
105   :0
106   * !SKIP_SA ?? .
107   {
108     :0 fw
109     |$SPAMC
110
111     :0
112     * ^X-Spam-Status: \/[A-Za-z]+
113     { SA_SPAM=$MATCH }
114
115     :0
116     * ^X-Spam-Status: .+score=\/-?[.0-9]+
117     { SA_SCORE=$MATCH }
118
119     :0
120     * ^X-Spam-Status: .+tests=\/[^ ]+
121     { SA_TESTS=$MATCH }
122
123     LOG="SA:          $SA_SPAM/$SA_SCORE/$SA_TESTS$NL"
124   }
125
126   ## CASE 0: crm114 is unsure/untrained
127   :0
128   * CRM_SPAM ?? UNSURE
129   {
130     # retrain spamtrapped message
131     :0
132     * SPAMTRAPPED ?? .
133     {
134       LOG="spamfilter:  scheduling retraining with SPAM due to spamtrap$NL"
135       :0 fw
136       |$FORMAIL -A "X-CRM114-Autotrain: spam, due to spamtrap"
137       RETRAIN=spam
138     }
139
140     # retrain as ham
141     :0 E
142     * ? perl -e "$SA_SCORE <= $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM || exit 1"
143     {
144       LOG="spamfilter:  scheduling retraining with HAM (score $SA_SCORE <= $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM)$NL"
145       :0 fw
146       |$FORMAIL -A "X-CRM114-Autotrain: ham, according to SA (score $SA_SCORE <= $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM)"
147       RETRAIN=ham
148     }
149
150     # retrain as spam
151     :0 E
152     * 1^0 ? perl -e "$SA_SCORE > $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM || exit 1"
153     {
154       LOG="spamfilter:  scheduling retraining with SPAM (score $SA_SCORE > $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)$NL"
155       :0 fw
156       |$FORMAIL -A "X-CRM114-Autotrain: spam, according to SA (score $SA_SCORE > $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)"
157       RETRAIN=spam
158     }
159
160     # skip retraining if SA is not convinced
161     :0 E
162     {
163       LOG="spamfilter:  will not autotrain crm114 because SA is not convinced ($CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM <= $SA_SCORE < $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)$NL"
164       :0 fw
165       |$FORMAIL -A "X-CRM114-Autotrain: SA is unsure ($CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM <= $SA_SCORE < $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)"
166       SPAM_UNSURE=sa-unsure
167     }
168   }
169
170   ## CASE 1: disagreement, SA sees ham
171   :0 E
172   * CRM_SPAM ?? SPAM
173   * SA_SPAM ?? No
174   {
175     # message was spamtrapped anyway
176     :0
177     * SPAMTRAPPED ?? .
178     {
179       LOG="spamfilter:  resolving crm114/SA disagreement due to spamtrap ($CRM_SCORE/$SA_SCORE)$NL"
180       RETRAIN=spam
181       :0 fw
182       |$FORMAIL -A "X-CRM114-Retrain: spam, due to spamtrap"
183     }
184
185     # SA is convincing, so retrain crm114
186     :0 E
187     * ? perl -e "$SA_SCORE <= $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_HAM || exit 1"
188     {
189       LOG="spamfilter:  crm114 found spam ($CRM_SCORE), but SA is more convincing ($SA_SCORE <= $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_HAM)$NL"
190       RETRAIN=ham
191       :0 fw
192       |$FORMAIL -A "X-CRM114-Retrain: ham, according to SA (score $SA_SCORE <= $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_HAM)"
193     }
194
195     # SA is not convincing, mark as disagreement
196     :0 E
197     {
198       LOG="spamfilter:  crm114 found spam ($CRM_SCORE), but SA thinks it's ham ($SA_SCORE)$NL"
199       SPAM_DISAGREE=sa-ham
200       :0 fw
201       |$FORMAIL -I "X-Spam: disagree (crm114:spam/$CRM_SCORE SA:ham/$SA_SCORE)"
202     }
203   }
204
205   ## CASE 1: disagreement, SA sees spam
206   :0 E
207   * CRM_SPAM ?? GOOD
208   * SA_SPAM ?? Yes
209   {
210     # message was spamtrapped anyway
211     :0
212     * SPAMTRAPPED ?? .
213     {
214       LOG="spamfilter:  resolving crm114/SA disagreement due to spamtrap ($CRM_SCORE/$SA_SCORE)$NL"
215       RETRAIN=spam
216       :0 fw
217       |$FORMAIL -A "X-CRM114-Retrain: spam, due to spamtrap"
218     }
219
220     # SA is convincing, so retrain crm114
221     :0
222     * ? perl -e "$SA_SCORE > $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_SPAM || exit 1"
223     {
224       LOG="spamfilter:  crm114 found ham ($CRM_SCORE), but SA is more convincing ($SA_SCORE > $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_SPAM)$NL"
225       RETRAIN=spam
226       :0 fw
227       |$FORMAIL -A "X-CRM114-Retrain: spam, according to SA (score $SA_SCORE > $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_SPAM)"
228     }
229
230     # SA is not convincing, mark as disagreement
231     :0 E
232     {
233       LOG="spamfilter:  crm114 found ham ($CRM_SCORE), but SA thinks it's spam ($SA_SCORE)$NL"
234       SPAM_DISAGREE=sa-spam
235       :0 fw
236       |$FORMAIL -I "X-Spam: disagree (crm114:ham/$CRM_SCORE SA:spam/$SA_SCORE)"
237     }
238   }
239
240   :0 E
241   * CRM_SPAM ?? SPAM
242   * SA_SPAM ?? Yes
243   {
244     IS_SPAM=sa+crm
245     :0 fw
246     |$FORMAIL -I"X-Spam: yes (crm114:$CRM_SCORE SA:$SA_SCORE)"
247   }
248
249   :0 Efw
250   |$FORMAIL -I"X-Spam: no (crm114:$CRM_SCORE SA:$SA_SCORE)"
251 }
252
253 # schedule spamtrapped ham for retraining as spam
254 :0
255 * SPAMTRAPPED ?? .
256 * ! SKIP_SPAMCHECKS ?? .
257 * ! IS_SPAM ?? .
258 {
259   LOG="spamfilter:  found spamtrapped ham, retraining...$NL"
260   :0 fw
261   |$FORMAIL -I"X-Spam: spamtrapped ham"
262   IS_SPAM=spamtrapped-ham
263   RETRAIN=spam
264   SPAM_UNSURE
265 }
266
267 #VERBOSE=no