]> 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:

deliver is in pmdir, not pmrules
[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 resubmitted
33 :0
34 *$ $MSG_DEJAVU
35 {
36   :0
37   * TRAINED_AS ?? .
38   {
39     LOG="spamfilter:  skipping already trained $TRAINED_AS$NL"
40     :0
41     * TRAINED_AS ?? spam
42     { IS_SPAM=already-trained }
43   }
44
45   :0 E
46   { LOG="spamfilter:  skipping resubmitted message$NL" }
47 }
48
49 # let earlier parts of the mailfilter cause bypassing the checks
50 :0 E
51 * SKIP_SPAMCHECKS ?? .
52 {
53   LOG="spamfilter:  skipping checks as requested: $SKIP_SPAMCHECKS$NL"
54   :0 fw
55   |$FORMAIL -I"X-Spam: unknown (skip requested)"
56   SPAM_UNKNOWN=skip-requested
57 }
58
59 # honour skip-spamchecks to exclude certain messages from spam checks
60 # altogether
61 :0 EBH
62 * ? $EGREP -qif $CONF/skip-spamchecks
63 {
64   LOG="spamfilter:  skipping checks as per skip-spamchecks$NL"
65   :0 fw
66   |$FORMAIL -I"X-Spam: unknown (check skipped)"
67   SPAM_UNKNOWN=skip-match
68   SKIP_SPAMCHECKS=match
69 }
70
71 # sanity check on message size
72 :0 E
73 * > $SPAMCHECK_MAX_MESSAGE_SIZE
74 {
75   LOG="spamfilter:  skipping check because message size exceeds $SPAMCHECK_MAX_MESSAGE_SIZE bytes$NL"
76   :0 fw
77   |$FORMAIL -I"X-Spam: unknown (message larger than $SPAMCHECK_MAX_MESSAGE_SIZE bytes)"
78   SPAM_UNKNOWN=too-large
79 }
80
81 # now run the spamfilters
82 :0 E
83 {
84   INCLUDERC=$PMDIR/pre-spam-cleanup
85
86   # crm114
87   CRM_SPAM=UNKNOWN
88   CRM_SCORE=0
89   :0
90   * !SKIP_CRM ?? .
91   {
92     :0 fw
93     |$CRM114
94
95     :0
96     * ^X-CRM114-Status: \/[A-Z]+
97     { CRM_SPAM=$MATCH }
98
99     :0
100     * ^X-CRM114-Status: .+\([ ]*\/-?[.0-9]+
101     { CRM_SCORE=$MATCH }
102
103     LOG="crm114:      $CRM_SPAM/$CRM_SCORE$NL"
104   }
105
106   # spamassassin
107   SA_STATUS=Unknown
108   SA_SCORE=0
109   SA_TESTS=none
110   :0
111   * !SKIP_SA ?? .
112   {
113     :0 fw
114     |$SPAMC
115
116     :0
117     * ^X-Spam-Status: \/[A-Za-z]+
118     { SA_SPAM=$MATCH }
119
120     :0
121     * ^X-Spam-Status: .+score=\/-?[.0-9]+
122     { SA_SCORE=$MATCH }
123
124     :0
125     * ^X-Spam-Status: .+tests=\/[^ ]+
126     { SA_TESTS=$MATCH }
127
128     LOG="SA:          $SA_SPAM/$SA_SCORE/$SA_TESTS$NL"
129   }
130
131   ## CASE 0: crm114 is unsure/untrained
132   :0
133   * CRM_SPAM ?? UNSURE
134   {
135     # retrain spamtrapped message
136     :0
137     * SPAMTRAPPED ?? .
138     {
139       LOG="spamfilter:  scheduling retraining with SPAM due to spamtrap$NL"
140       :0 fw
141       |$FORMAIL -A "X-CRM114-Autotrain: spam, due to spamtrap"
142       RETRAIN=spam
143     }
144
145     # retrain as ham
146     :0 E
147     * ? perl -e "$SA_SCORE <= $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM || exit 1"
148     {
149       LOG="spamfilter:  scheduling retraining with HAM (score $SA_SCORE <= $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM)$NL"
150       :0 fw
151       |$FORMAIL -A "X-CRM114-Autotrain: ham, according to SA (score $SA_SCORE <= $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM)"
152       RETRAIN=ham
153     }
154
155     # retrain as spam
156     :0 E
157     * 1^0 ? perl -e "$SA_SCORE > $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM || exit 1"
158     {
159       LOG="spamfilter:  scheduling retraining with SPAM (score $SA_SCORE > $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)$NL"
160       :0 fw
161       |$FORMAIL -A "X-CRM114-Autotrain: spam, according to SA (score $SA_SCORE > $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)"
162       RETRAIN=spam
163     }
164
165     # skip retraining if SA is not convinced
166     :0 E
167     {
168       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"
169       :0 fw
170       |$FORMAIL -A "X-CRM114-Autotrain: SA is unsure ($CRM_UNSURE_SA_AUTOTRAIN_LIMIT_HAM <= $SA_SCORE < $CRM_UNSURE_SA_AUTOTRAIN_LIMIT_SPAM)"
171       SPAM_UNSURE=sa-unsure
172     }
173   }
174
175   ## CASE 1: disagreement, SA sees ham
176   :0 E
177   * CRM_SPAM ?? SPAM
178   * SA_SPAM ?? No
179   {
180     # message was spamtrapped anyway
181     :0
182     * SPAMTRAPPED ?? .
183     {
184       LOG="spamfilter:  resolving crm114/SA disagreement due to spamtrap ($CRM_SCORE/$SA_SCORE)$NL"
185       RETRAIN=spam
186       :0 fw
187       |$FORMAIL -A "X-CRM114-Retrain: spam, due to spamtrap"
188     }
189
190     # SA is convincing, so retrain crm114
191     :0 E
192     * ? perl -e "$SA_SCORE <= $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_HAM || exit 1"
193     {
194       LOG="spamfilter:  crm114 found spam ($CRM_SCORE), but SA is more convincing ($SA_SCORE <= $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_HAM)$NL"
195       RETRAIN=ham
196       :0 fw
197       |$FORMAIL -A "X-CRM114-Retrain: ham, according to SA (score $SA_SCORE <= $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_HAM)"
198     }
199
200     # SA is not convincing, mark as disagreement
201     :0 E
202     {
203       LOG="spamfilter:  crm114 found spam ($CRM_SCORE), but SA thinks it's ham ($SA_SCORE)$NL"
204       SPAM_DISAGREE=sa-ham
205       :0 fw
206       |$FORMAIL -I "X-Spam: disagree (crm114:spam/$CRM_SCORE SA:ham/$SA_SCORE)"
207     }
208   }
209
210   ## CASE 1: disagreement, SA sees spam
211   :0 E
212   * CRM_SPAM ?? GOOD
213   * SA_SPAM ?? Yes
214   {
215     # message was spamtrapped anyway
216     :0
217     * SPAMTRAPPED ?? .
218     {
219       LOG="spamfilter:  resolving crm114/SA disagreement due to spamtrap ($CRM_SCORE/$SA_SCORE)$NL"
220       RETRAIN=spam
221       :0 fw
222       |$FORMAIL -A "X-CRM114-Retrain: spam, due to spamtrap"
223     }
224
225     # SA is convincing, so retrain crm114
226     :0
227     * ? perl -e "$SA_SCORE > $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_SPAM || exit 1"
228     {
229       LOG="spamfilter:  crm114 found ham ($CRM_SCORE), but SA is more convincing ($SA_SCORE > $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_SPAM)$NL"
230       RETRAIN=spam
231       :0 fw
232       |$FORMAIL -A "X-CRM114-Retrain: spam, according to SA (score $SA_SCORE > $CRM_MISCLASSIFY_SA_AUTOTRAIN_LIMIT_SPAM)"
233     }
234
235     # SA is not convincing, mark as disagreement
236     :0 E
237     {
238       LOG="spamfilter:  crm114 found ham ($CRM_SCORE), but SA thinks it's spam ($SA_SCORE)$NL"
239       SPAM_DISAGREE=sa-spam
240       :0 fw
241       |$FORMAIL -I "X-Spam: disagree (crm114:ham/$CRM_SCORE SA:spam/$SA_SCORE)"
242     }
243   }
244
245   :0 E
246   * CRM_SPAM ?? SPAM
247   * SA_SPAM ?? Yes
248   {
249     IS_SPAM=sa+crm
250     :0 fw
251     |$FORMAIL -I"X-Spam: yes (crm114:$CRM_SCORE SA:$SA_SCORE)"
252   }
253
254   :0 Efw
255   |$FORMAIL -I"X-Spam: no (crm114:$CRM_SCORE SA:$SA_SCORE)"
256 }
257
258 # schedule spamtrapped ham for retraining as spam
259 :0
260 * SPAMTRAPPED ?? .
261 * ! SKIP_SPAMCHECKS ?? .
262 * ! IS_SPAM ?? .
263 {
264   LOG="spamfilter:  found spamtrapped ham, retraining...$NL"
265   :0 fw
266   |$FORMAIL -I"X-Spam: spamtrapped ham"
267   IS_SPAM=spamtrapped-ham
268   RETRAIN=spam
269   SPAM_UNSURE
270 }
271
272 #VERBOSE=no