849bdf42 |
1 | <?php |
2 | /* |
b78c2231 |
3 | * Message and Spam Filter Plugin |
4 | * Copyright (c) 1999-2001 The Squirrelmail Development Team |
5 | * Licensed under the GNU GPL. For full terms see the file COPYING. |
849bdf42 |
6 | * |
7 | * This plugin filters your inbox into different folders based upon given |
8 | * criteria. It is most useful for people who are subscibed to mailing lists |
9 | * to help organize their messages. The argument stands that filtering is |
10 | * not the place of the client, which is why this has been made a plugin for |
11 | * SquirrelMail. You may be better off using products such as Sieve or |
12 | * Procmail to do your filtering so it happens even when SquirrelMail isn't |
13 | * running. |
14 | * |
15 | * If you need help with this, or see improvements that can be made, please |
16 | * email me directly at the address above. I definately welcome suggestions |
17 | * and comments. This plugin, as is the case with all SquirrelMail plugins, |
18 | * is not directly supported by the developers. Please come to me off the |
19 | * mailing list if you have trouble with it. |
20 | * |
21 | * Also view plugins/README.plugins for more information. |
22 | * |
b78c2231 |
23 | * $Id$ |
24 | * |
849bdf42 |
25 | */ |
26 | |
27 | function start_filters() { |
28 | global $username, $key, $imapServerAddress, $imapPort, $imap, |
29 | $imap_general, $filters, $imap_stream, $imapConnection, |
30 | $UseSeparateImapConnection, $AllowSpamFilters; |
31 | |
32 | // Detect if we have already connected to IMAP or not. |
33 | // Also check if we are forced to use a separate IMAP connection |
34 | if ((!isset($imap_stream) && !isset($imapConnection)) || |
35 | $UseSeparateImapConnection) { |
36 | $stream = sqimap_login($username, $key, $imapServerAddress, |
37 | $imapPort, 10); |
38 | $previously_connected = false; |
39 | } elseif (isset($imapConnection)) { |
40 | $stream = $imapConnection; |
41 | $previously_connected = true; |
42 | } else { |
43 | $previously_connected = true; |
44 | $stream = $imap_stream; |
45 | } |
46 | |
47 | if (sqimap_get_num_messages($stream, "INBOX") > 0) { |
48 | // Filter spam from inbox before we sort them into folders |
49 | if ($AllowSpamFilters) |
50 | spam_filters($stream); |
51 | |
52 | // Sort into folders |
53 | user_filters($stream); |
54 | } |
55 | |
56 | if (!$previously_connected) |
57 | sqimap_logout($stream); |
58 | } |
59 | |
60 | |
61 | function user_filters($imap_stream) { |
62 | $filters = load_filters(); |
63 | if (! $filters) return; |
64 | |
65 | sqimap_mailbox_select($imap_stream, 'INBOX'); |
66 | |
67 | // For every rule |
68 | for ($i=0; $i < count($filters); $i++) { |
69 | // If it is the "combo" rule |
70 | if ($filters[$i]["where"] == "To or Cc") { |
71 | /* |
72 | * If it's "TO OR CC", we have to do two searches, one for TO |
73 | * and the other for CC. |
74 | */ |
75 | filter_search_and_delete($imap_stream, 'TO', |
76 | $filters[$i]['what'], $filters[$i]['folder']); |
77 | filter_search_and_delete($imap_stream, 'CC', |
78 | $filters[$i]['what'], $filters[$i]['folder']); |
79 | } else { |
80 | /* |
81 | * If it's a normal TO, CC, SUBJECT, or FROM, then handle it |
82 | * normally. |
83 | */ |
84 | filter_search_and_delete($imap_stream, $filters[$i]['where'], |
85 | $filters[$i]['what'], $filters[$i]['folder']); |
86 | } |
87 | } |
88 | // Clean out the mailbox whether or not auto_expunge is on |
89 | // That way it looks like it was redirected properly |
90 | sqimap_mailbox_expunge($imap_stream, 'INBOX'); |
91 | } |
92 | |
93 | function filter_search_and_delete($imap, $where, $what, $where_to) { |
94 | fputs ($imap, 'a001 SEARCH ALL ' . $where . ' "' . addslashes($what) . |
95 | "\"\r\n"); |
96 | $read = sqimap_read_data ($imap, 'a001', true, $response, $message); |
97 | |
98 | // This may have problems with EIMS due to it being goofy |
99 | |
100 | for ($r=0; $r < count($read) && |
101 | substr($read[$r], 0, 8) != '* SEARCH'; $r++) {} |
102 | if ($response == 'OK') { |
103 | $ids = explode(' ', $read[$r]); |
104 | if (sqimap_mailbox_exists($imap, $where_to)) { |
105 | for ($j=2; $j < count($ids); $j++) { |
106 | $id = trim($ids[$j]); |
107 | sqimap_messages_copy ($imap, $id, $id, $where_to); |
108 | sqimap_messages_flag ($imap, $id, $id, 'Deleted'); |
109 | } |
110 | } |
111 | } |
112 | } |
113 | |
114 | // These are the spam filters |
115 | function spam_filters($imap_stream) { |
116 | global $data_dir, $username; |
117 | global $SpamFilters_YourHop; |
118 | global $SpamFilters_DNScache; |
119 | |
120 | $filters_spam_scan = getPref($data_dir, $username, "filters_spam_scan"); |
121 | $filters_spam_folder = getPref($data_dir, $username, "filters_spam_folder"); |
122 | $filters = load_spam_filters(); |
123 | |
124 | $run = 0; |
125 | |
126 | foreach ($filters as $Key=> $Value) { |
127 | if ($Value['enabled']) |
128 | $run ++; |
129 | } |
a9aa7ab7 |
130 | |
849bdf42 |
131 | // short-circuit |
132 | if ($run == 0) { |
133 | return; |
134 | } |
a9aa7ab7 |
135 | |
849bdf42 |
136 | sqimap_mailbox_select($imap_stream, 'INBOX'); |
a9aa7ab7 |
137 | |
138 | // Ask for a big list of all "Received" headers in the inbox with |
849bdf42 |
139 | // flags for each message. Kinda big. |
140 | fputs($imap_stream, 'A3999 FETCH 1:* (FLAGS BODY.PEEK[HEADER.FIELDS ' . |
141 | "(RECEIVED)])\r\n"); |
a9aa7ab7 |
142 | |
849bdf42 |
143 | $read = sqimap_read_data ($imap_stream, 'A3999', true, $response, $message); |
a9aa7ab7 |
144 | |
849bdf42 |
145 | if ($response != 'OK') |
146 | return; |
147 | |
148 | $i = 0; |
149 | while ($i < count($read)) { |
150 | // EIMS will give funky results |
151 | $Chunks = explode(' ', $read[$i]); |
152 | if ($Chunks[0] != '*') { |
153 | $i ++; |
154 | continue; |
155 | } |
156 | $MsgNum = $Chunks[1]; |
157 | |
158 | $IPs = array(); |
159 | $i ++; |
160 | $IsSpam = 0; |
161 | $Scan = 1; |
a9aa7ab7 |
162 | |
163 | // Check for normal IMAP servers |
849bdf42 |
164 | if ($filters_spam_scan == 'new') { |
165 | if (is_int(strpos($Chunks[4], '\Seen'))) { |
166 | $Scan = 0; |
167 | } |
168 | } |
a9aa7ab7 |
169 | |
170 | // Look through all of the Received headers for IP addresses |
171 | // Stop when I get ")" on a line |
172 | // Stop if I get "*" on a line (don't advance) |
849bdf42 |
173 | // and above all, stop if $i is bigger than the total # of lines |
174 | while (($i < count($read)) && |
175 | ($read[$i][0] != ')' && $read[$i][0] != '*' && |
a9aa7ab7 |
176 | $read[$i][0] != "\n") && (! $IsSpam)) |
177 | { |
849bdf42 |
178 | // Check to see if this line is the right "Received from" line |
179 | // to check |
180 | if (is_int(strpos($read[$i], $SpamFilters_YourHop))) { |
181 | |
a9aa7ab7 |
182 | // short-circuit and skip work if we don't scan this one |
849bdf42 |
183 | if ($Scan) { |
184 | $read[$i] = ereg_replace('[^0-9\.]', ' ', $read[$i]); |
185 | $elements = explode(' ', $read[$i]); |
186 | foreach ($elements as $value) { |
a9aa7ab7 |
187 | if ($value != '' && |
849bdf42 |
188 | ereg('[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}', |
a9aa7ab7 |
189 | $value, $regs)) { |
190 | $Chunks = explode('.', $value); |
191 | if ("$SpamFilters_DNScache[$value]" == "") { |
849bdf42 |
192 | $SpamFilters_DNScache[$value] = |
193 | filters_spam_check_site($Chunks[0], $Chunks[1], |
a9aa7ab7 |
194 | $Chunks[2], $Chunks[3], $filters); |
195 | } |
196 | if ($SpamFilters_DNScache[$value]) { |
197 | $IsSpam ++; |
849bdf42 |
198 | break; // no sense in checking more IPs |
a9aa7ab7 |
199 | } |
849bdf42 |
200 | } |
a9aa7ab7 |
201 | } |
849bdf42 |
202 | } |
203 | } |
204 | $i ++; |
205 | } |
38a7b6a0 |
206 | |
207 | // Lookie! It's spam! Yum! |
849bdf42 |
208 | if ($IsSpam) { |
209 | if (sqimap_mailbox_exists ($imap_stream, $filters_spam_folder)) { |
38a7b6a0 |
210 | sqimap_messages_copy ($imap_stream, $MsgNum, $MsgNum, |
211 | $filters_spam_folder); |
a9aa7ab7 |
212 | sqimap_messages_flag ($imap_stream, $MsgNum, $MsgNum, |
38a7b6a0 |
213 | 'Deleted'); |
849bdf42 |
214 | } |
215 | } |
216 | } |
a9aa7ab7 |
217 | |
849bdf42 |
218 | sqimap_mailbox_expunge($imap_stream, 'INBOX'); |
219 | } |
220 | |
221 | |
222 | // Does the loop through each enabled filter for the specified IP address. |
223 | // IP format: $a.$b.$c.$d |
224 | function filters_spam_check_site($a, $b, $c, $d, &$filters) { |
225 | foreach ($filters as $key => $value) { |
226 | if ($filters[$key]['enabled']) { |
227 | if ($filters[$key]['dns']) { |
228 | if (checkdnsrr("$d.$c.$b.$a." . $filters[$key]['dns'], |
229 | 'ANY')) { |
230 | return 1; |
231 | } |
232 | } |
233 | } |
234 | } |
235 | return 0; |
236 | } |
237 | |
238 | function load_filters() { |
239 | global $data_dir, $username; |
240 | $filters = array(); |
241 | for ($i=0; $fltr = getPref($data_dir, $username, 'filter' . $i); $i++) { |
242 | $ary = explode(',', $fltr); |
243 | $filters[$i]['where'] = $ary[0]; |
244 | $filters[$i]['what'] = $ary[1]; |
245 | $filters[$i]['folder'] = $ary[2]; |
246 | } |
247 | return $filters; |
248 | } |
249 | |
250 | function load_spam_filters() { |
251 | global $data_dir, $username; |
252 | |
253 | $filters['MAPS RBL']['prefname'] = 'filters_spam_maps_rbl'; |
254 | $filters['MAPS RBL']['name'] = 'MAPS Realtime Blackhole List'; |
255 | $filters['MAPS RBL']['link'] = 'http://www.mail-abuse.org/rbl/'; |
256 | $filters['MAPS RBL']['dns'] = 'blackholes.mail-abuse.org'; |
257 | $filters['MAPS RBL']['comment'] = |
3fd1252d |
258 | _("COMMERCIAL - This list contains servers that are verified spam senders. It is a pretty reliable list to scan spam from."); |
849bdf42 |
259 | |
260 | $filters['MAPS RSS']['prefname'] = 'filters_spam_maps_rss'; |
261 | $filters['MAPS RSS']['name'] = 'MAPS Relay Spam Stopper'; |
262 | $filters['MAPS RSS']['link'] = 'http://www.mail-abuse.org/rss/'; |
263 | $filters['MAPS RSS']['dns'] = 'relays.mail-abuse.org'; |
264 | $filters['MAPS RSS']['comment'] = |
3fd1252d |
265 | _("COMMERCIAL - Servers that are configured (or misconfigured) to allow spam to be relayed through their system will be banned with this. Another good one to use."); |
849bdf42 |
266 | |
267 | $filters['MAPS DUL']['prefname'] = 'filters_spam_maps_dul'; |
268 | $filters['MAPS DUL']['name'] = 'MAPS Dial-Up List'; |
269 | $filters['MAPS DUL']['link'] = 'http://www.mail-abuse.org/dul/'; |
270 | $filters['MAPS DUL']['dns'] = 'dialups.mail-abuse.org'; |
271 | $filters['MAPS DUL']['comment'] = |
48a8f454 |
272 | _("COMMERCIAL - Dial-up users are often filtered out since they should use their ISP's mail servers to send mail. Spammers typically get a dial-up account and send spam directly from there."); |
849bdf42 |
273 | |
274 | $filters['MAPS RBLplus']['prefname'] = 'filters_spam_maps_rblplus'; |
275 | $filters['MAPS RBLplus']['name'] = 'MAPS RBL+ List'; |
276 | $filters['MAPS RBLplus']['link'] = 'http://www.mail-abuse.org/'; |
277 | $filters['MAPS RBLplus']['dns'] = 'rbl-plus.mail-abuse.org'; |
278 | $filters['MAPS RBLplus']['comment'] = |
3fd1252d |
279 | _("COMMERCIAL - RBL+ is a combination of RSS, DUL, and RBL."); |
849bdf42 |
280 | |
281 | $filters['Osirusoft']['prefname'] = 'filters_spam_maps_osirusoft'; |
282 | $filters['Osirusoft']['name'] = 'Osirusoft List'; |
283 | $filters['Osirusoft']['link'] = 'http://relays.osirusoft.com/'; |
284 | $filters['Osirusoft']['dns'] = 'relays.osirusoft.com'; |
285 | $filters['Osirusoft']['comment'] = |
48a8f454 |
286 | _("FREE - Osirusoft - Very thorough, but also rejects replies from many ISP's abuse@domain.name email messages for some reason."); |
849bdf42 |
287 | |
288 | $filters['ORDB']['prefname'] = 'filters_spam_ordb'; |
289 | $filters['ORDB']['name'] = 'Open Relay Database List'; |
290 | $filters['ORDB']['link'] = 'http://www.ordb.org/'; |
291 | $filters['ORDB']['dns'] = 'relays.ordb.org'; |
292 | $filters['ORDB']['comment'] = |
3fd1252d |
293 | _("FREE - ORDB was born when ORBS went off the air. It seems to have fewer false positives than ORBS did though."); |
849bdf42 |
294 | |
295 | $filters['ORBZ']['prefname'] = 'filters_spam_orbz'; |
296 | $filters['ORBZ']['name'] = 'ORBZ List'; |
297 | $filters['ORBZ']['link'] = 'http://www.orbz.org/'; |
298 | $filters['ORBZ']['dns'] = 'inputs.orbz.org'; |
299 | $filters['ORBZ']['comment'] = |
3fd1252d |
300 | _("FREE - Another ORBS replacement (just the INPUTS database used here)."); |
849bdf42 |
301 | |
302 | $filters['Five-Ten']['prefname'] = 'filters_spam_fiveten'; |
303 | $filters['Five-Ten']['name'] = 'Five-Ten-sg.com Lists'; |
304 | $filters['Five-Ten']['link'] = 'http://www.five-ten-sg.com/blackhole.php'; |
305 | $filters['Five-Ten']['dns'] = 'blackholes.five-ten-sg.com'; |
306 | $filters['Five-Ten']['comment'] = |
38a7b6a0 |
307 | _("FREE - Five-Ten-sg.com has SPAM source, OpenRelay, and Dialup IPs."); |
849bdf42 |
308 | |
309 | $filters['Dorkslayers']['prefname'] = 'filters_spam_dorks'; |
310 | $filters['Dorkslayers']['name'] = 'Dorkslayers Lists'; |
311 | $filters['Dorkslayers']['link'] = 'http://www.dorkslayers.com'; |
312 | $filters['Dorkslayers']['dns'] = 'orbs.dorkslayers.com'; |
313 | $filters['Dorkslayers']['comment'] = |
3fd1252d |
314 | _("FREE - Dorkslayers appears to include only really bad open relays outside the US to avoid being sued. Interestingly enough, their website recommends you NOT use their service."); |
849bdf42 |
315 | |
316 | $filters['ORBL']['prefname'] = 'filters_spam_orbl'; |
317 | $filters['ORBL']['name'] = 'ORBL Lists'; |
318 | $filters['ORBL']['link'] = 'http://www.orbl.org'; |
319 | $filters['ORBL']['dns'] = 'or.orbl.org'; |
320 | $filters['ORBL']['comment'] = |
38a7b6a0 |
321 | _("FREE - ORBL is another ORBS spinoff formed after ORBS shut down. May be SLOOOOOOW!"); |
849bdf42 |
322 | |
323 | $filters['ORBZ-UK']['prefname'] = 'filters_spam_orbzuk'; |
324 | $filters['ORBZ-UK']['name'] = 'ORBZ-UK Lists'; |
325 | $filters['ORBZ-UK']['link'] = 'http://orbz.gst-group.co.uk'; |
326 | $filters['ORBZ-UK']['dns'] = 'orbz.gst-group.co.uk'; |
327 | $filters['ORBZ-UK']['comment'] = |
3fd1252d |
328 | _("FREE - orbz.gst-group.co.uk lists not only open relays, but also mailservers that refuse or bounce email addressed to postmaster@<theirdomain>."); |
849bdf42 |
329 | |
330 | foreach ($filters as $Key => $Value) { |
331 | $filters[$Key]['enabled'] = getPref($data_dir, $username, |
332 | $filters[$Key]['prefname']); |
333 | } |
334 | |
335 | return $filters; |
336 | } |
337 | |
338 | function remove_filter ($id) { |
339 | global $data_dir, $username; |
340 | |
341 | while ($nextFilter = getPref($data_dir, $username, 'filter' . |
342 | ($id + 1))) { |
343 | setPref($data_dir, $username, 'filter' . $id, $nextFilter); |
344 | $id ++; |
345 | } |
346 | |
347 | removePref($data_dir, $username, 'filter' . $id); |
348 | } |
349 | |
350 | function filter_swap($id1, $id2) { |
351 | global $data_dir, $username; |
352 | |
353 | $FirstFilter = getPref($data_dir, $username, 'filter' . $id1); |
354 | $SecondFilter = getPref($data_dir, $username, 'filter' . $id2); |
355 | |
356 | if ($FirstFilter && $SecondFilter) { |
357 | setPref($data_dir, $username, 'filter' . $id2, $FirstFilter); |
358 | setPref($data_dir, $username, 'filter' . $id1, $SecondFilter); |
359 | } |
360 | } |
361 | ?> |