(c) stuff
[squirrelmail.git] / plugins / filters / filters.php
CommitLineData
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?>