filters.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. /*
  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.
  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. *
  23. * $Id$
  24. *
  25. */
  26. function start_filters() {
  27. global $username, $key, $imapServerAddress, $imapPort, $imap,
  28. $imap_general, $filters, $imap_stream, $imapConnection,
  29. $UseSeparateImapConnection, $AllowSpamFilters;
  30. // Detect if we have already connected to IMAP or not.
  31. // Also check if we are forced to use a separate IMAP connection
  32. if ((!isset($imap_stream) && !isset($imapConnection)) ||
  33. $UseSeparateImapConnection) {
  34. $stream = sqimap_login($username, $key, $imapServerAddress,
  35. $imapPort, 10);
  36. $previously_connected = false;
  37. } elseif (isset($imapConnection)) {
  38. $stream = $imapConnection;
  39. $previously_connected = true;
  40. } else {
  41. $previously_connected = true;
  42. $stream = $imap_stream;
  43. }
  44. if (sqimap_get_num_messages($stream, "INBOX") > 0) {
  45. // Filter spam from inbox before we sort them into folders
  46. if ($AllowSpamFilters)
  47. spam_filters($stream);
  48. // Sort into folders
  49. user_filters($stream);
  50. }
  51. if (!$previously_connected)
  52. sqimap_logout($stream);
  53. }
  54. function user_filters($imap_stream) {
  55. $filters = load_filters();
  56. if (! $filters) return;
  57. sqimap_mailbox_select($imap_stream, 'INBOX');
  58. // For every rule
  59. for ($i=0; $i < count($filters); $i++) {
  60. // If it is the "combo" rule
  61. if ($filters[$i]["where"] == "To or Cc") {
  62. /*
  63. * If it's "TO OR CC", we have to do two searches, one for TO
  64. * and the other for CC.
  65. */
  66. filter_search_and_delete($imap_stream, 'TO',
  67. $filters[$i]['what'], $filters[$i]['folder']);
  68. filter_search_and_delete($imap_stream, 'CC',
  69. $filters[$i]['what'], $filters[$i]['folder']);
  70. } else {
  71. /*
  72. * If it's a normal TO, CC, SUBJECT, or FROM, then handle it
  73. * normally.
  74. */
  75. filter_search_and_delete($imap_stream, $filters[$i]['where'],
  76. $filters[$i]['what'], $filters[$i]['folder']);
  77. }
  78. }
  79. // Clean out the mailbox whether or not auto_expunge is on
  80. // That way it looks like it was redirected properly
  81. sqimap_mailbox_expunge($imap_stream, 'INBOX');
  82. }
  83. function filter_search_and_delete($imap, $where, $what, $where_to) {
  84. fputs ($imap, 'a001 SEARCH ALL ' . $where . ' "' . addslashes($what) .
  85. "\"\r\n");
  86. $read = sqimap_read_data ($imap, 'a001', true, $response, $message);
  87. // This may have problems with EIMS due to it being goofy
  88. for ($r=0; $r < count($read) &&
  89. substr($read[$r], 0, 8) != '* SEARCH'; $r++) {}
  90. if ($response == 'OK') {
  91. $ids = explode(' ', $read[$r]);
  92. if (sqimap_mailbox_exists($imap, $where_to)) {
  93. for ($j=2; $j < count($ids); $j++) {
  94. $id = trim($ids[$j]);
  95. sqimap_messages_copy ($imap, $id, $id, $where_to);
  96. sqimap_messages_flag ($imap, $id, $id, 'Deleted');
  97. }
  98. }
  99. }
  100. }
  101. // These are the spam filters
  102. function spam_filters($imap_stream) {
  103. global $data_dir, $username;
  104. global $SpamFilters_YourHop;
  105. global $SpamFilters_DNScache;
  106. $filters_spam_scan = getPref($data_dir, $username, "filters_spam_scan");
  107. $filters_spam_folder = getPref($data_dir, $username, "filters_spam_folder");
  108. $filters = load_spam_filters();
  109. $run = 0;
  110. foreach ($filters as $Key=> $Value) {
  111. if ($Value['enabled'])
  112. $run ++;
  113. }
  114. // short-circuit
  115. if ($run == 0) {
  116. return;
  117. }
  118. sqimap_mailbox_select($imap_stream, 'INBOX');
  119. // Ask for a big list of all "Received" headers in the inbox with
  120. // flags for each message. Kinda big.
  121. fputs($imap_stream, 'A3999 FETCH 1:* (FLAGS BODY.PEEK[HEADER.FIELDS ' .
  122. "(RECEIVED)])\r\n");
  123. $read = sqimap_read_data ($imap_stream, 'A3999', true, $response, $message);
  124. if ($response != 'OK')
  125. return;
  126. $i = 0;
  127. while ($i < count($read)) {
  128. // EIMS will give funky results
  129. $Chunks = explode(' ', $read[$i]);
  130. if ($Chunks[0] != '*') {
  131. $i ++;
  132. continue;
  133. }
  134. $MsgNum = $Chunks[1];
  135. $IPs = array();
  136. $i ++;
  137. $IsSpam = 0;
  138. $Scan = 1;
  139. // Check for normal IMAP servers
  140. if ($filters_spam_scan == 'new') {
  141. if (is_int(strpos($Chunks[4], '\Seen'))) {
  142. $Scan = 0;
  143. }
  144. }
  145. // Look through all of the Received headers for IP addresses
  146. // Stop when I get ")" on a line
  147. // Stop if I get "*" on a line (don't advance)
  148. // and above all, stop if $i is bigger than the total # of lines
  149. while (($i < count($read)) &&
  150. ($read[$i][0] != ')' && $read[$i][0] != '*' &&
  151. $read[$i][0] != "\n") && (! $IsSpam))
  152. {
  153. // Check to see if this line is the right "Received from" line
  154. // to check
  155. if (is_int(strpos($read[$i], $SpamFilters_YourHop))) {
  156. // short-circuit and skip work if we don't scan this one
  157. if ($Scan) {
  158. $read[$i] = ereg_replace('[^0-9\.]', ' ', $read[$i]);
  159. $elements = explode(' ', $read[$i]);
  160. foreach ($elements as $value) {
  161. if ($value != '' &&
  162. ereg('[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}',
  163. $value, $regs)) {
  164. $Chunks = explode('.', $value);
  165. if ("$SpamFilters_DNScache[$value]" == "") {
  166. $SpamFilters_DNScache[$value] =
  167. filters_spam_check_site($Chunks[0], $Chunks[1],
  168. $Chunks[2], $Chunks[3], $filters);
  169. }
  170. if ($SpamFilters_DNScache[$value]) {
  171. $IsSpam ++;
  172. break; // no sense in checking more IPs
  173. }
  174. }
  175. }
  176. }
  177. }
  178. $i ++;
  179. }
  180. // Lookie! It's spam! Yum!
  181. if ($IsSpam) {
  182. if (sqimap_mailbox_exists ($imap_stream, $filters_spam_folder)) {
  183. sqimap_messages_copy ($imap_stream, $MsgNum, $MsgNum,
  184. $filters_spam_folder);
  185. sqimap_messages_flag ($imap_stream, $MsgNum, $MsgNum,
  186. 'Deleted');
  187. }
  188. }
  189. }
  190. sqimap_mailbox_expunge($imap_stream, 'INBOX');
  191. }
  192. // Does the loop through each enabled filter for the specified IP address.
  193. // IP format: $a.$b.$c.$d
  194. function filters_spam_check_site($a, $b, $c, $d, &$filters) {
  195. foreach ($filters as $key => $value) {
  196. if ($filters[$key]['enabled']) {
  197. if ($filters[$key]['dns']) {
  198. if (checkdnsrr("$d.$c.$b.$a." . $filters[$key]['dns'],
  199. 'ANY')) {
  200. return 1;
  201. }
  202. }
  203. }
  204. }
  205. return 0;
  206. }
  207. function load_filters() {
  208. global $data_dir, $username;
  209. $filters = array();
  210. for ($i=0; $fltr = getPref($data_dir, $username, 'filter' . $i); $i++) {
  211. $ary = explode(',', $fltr);
  212. $filters[$i]['where'] = $ary[0];
  213. $filters[$i]['what'] = $ary[1];
  214. $filters[$i]['folder'] = $ary[2];
  215. }
  216. return $filters;
  217. }
  218. function load_spam_filters() {
  219. global $data_dir, $username;
  220. $filters['MAPS RBL']['prefname'] = 'filters_spam_maps_rbl';
  221. $filters['MAPS RBL']['name'] = 'MAPS Realtime Blackhole List';
  222. $filters['MAPS RBL']['link'] = 'http://www.mail-abuse.org/rbl/';
  223. $filters['MAPS RBL']['dns'] = 'blackholes.mail-abuse.org';
  224. $filters['MAPS RBL']['comment'] =
  225. _("COMMERCIAL - This list contains servers that are verified spam senders. It is a pretty reliable list to scan spam from.");
  226. $filters['MAPS RSS']['prefname'] = 'filters_spam_maps_rss';
  227. $filters['MAPS RSS']['name'] = 'MAPS Relay Spam Stopper';
  228. $filters['MAPS RSS']['link'] = 'http://www.mail-abuse.org/rss/';
  229. $filters['MAPS RSS']['dns'] = 'relays.mail-abuse.org';
  230. $filters['MAPS RSS']['comment'] =
  231. _("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.");
  232. $filters['MAPS DUL']['prefname'] = 'filters_spam_maps_dul';
  233. $filters['MAPS DUL']['name'] = 'MAPS Dial-Up List';
  234. $filters['MAPS DUL']['link'] = 'http://www.mail-abuse.org/dul/';
  235. $filters['MAPS DUL']['dns'] = 'dialups.mail-abuse.org';
  236. $filters['MAPS DUL']['comment'] =
  237. _("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.");
  238. $filters['MAPS RBLplus']['prefname'] = 'filters_spam_maps_rblplus';
  239. $filters['MAPS RBLplus']['name'] = 'MAPS RBL+ List';
  240. $filters['MAPS RBLplus']['link'] = 'http://www.mail-abuse.org/';
  241. $filters['MAPS RBLplus']['dns'] = 'rbl-plus.mail-abuse.org';
  242. $filters['MAPS RBLplus']['comment'] =
  243. _("COMMERCIAL - RBL+ is a combination of RSS, DUL, and RBL.");
  244. $filters['Osirusoft']['prefname'] = 'filters_spam_maps_osirusoft';
  245. $filters['Osirusoft']['name'] = 'Osirusoft List';
  246. $filters['Osirusoft']['link'] = 'http://relays.osirusoft.com/';
  247. $filters['Osirusoft']['dns'] = 'relays.osirusoft.com';
  248. $filters['Osirusoft']['comment'] =
  249. _("FREE - Osirusoft - Very thorough, but also rejects replies from many ISP\'s abuse@domain.name email messages for some reason.");
  250. $filters['ORDB']['prefname'] = 'filters_spam_ordb';
  251. $filters['ORDB']['name'] = 'Open Relay Database List';
  252. $filters['ORDB']['link'] = 'http://www.ordb.org/';
  253. $filters['ORDB']['dns'] = 'relays.ordb.org';
  254. $filters['ORDB']['comment'] =
  255. _("FREE - ORDB was born when ORBS went off the air. It seems to have fewer false positives than ORBS did though.");
  256. $filters['ORBZ']['prefname'] = 'filters_spam_orbz';
  257. $filters['ORBZ']['name'] = 'ORBZ List';
  258. $filters['ORBZ']['link'] = 'http://www.orbz.org/';
  259. $filters['ORBZ']['dns'] = 'inputs.orbz.org';
  260. $filters['ORBZ']['comment'] =
  261. _("FREE - Another ORBS replacement (just the INPUTS database used here).");
  262. $filters['Five-Ten']['prefname'] = 'filters_spam_fiveten';
  263. $filters['Five-Ten']['name'] = 'Five-Ten-sg.com Lists';
  264. $filters['Five-Ten']['link'] = 'http://www.five-ten-sg.com/blackhole.php';
  265. $filters['Five-Ten']['dns'] = 'blackholes.five-ten-sg.com';
  266. $filters['Five-Ten']['comment'] =
  267. _("FREE - Five-Ten-sg.com has SPAM source, OpenRelay, and Dialup IPs.");
  268. $filters['Dorkslayers']['prefname'] = 'filters_spam_dorks';
  269. $filters['Dorkslayers']['name'] = 'Dorkslayers Lists';
  270. $filters['Dorkslayers']['link'] = 'http://www.dorkslayers.com';
  271. $filters['Dorkslayers']['dns'] = 'orbs.dorkslayers.com';
  272. $filters['Dorkslayers']['comment'] =
  273. _("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.");
  274. $filters['ORBL']['prefname'] = 'filters_spam_orbl';
  275. $filters['ORBL']['name'] = 'ORBL Lists';
  276. $filters['ORBL']['link'] = 'http://www.orbl.org';
  277. $filters['ORBL']['dns'] = 'or.orbl.org';
  278. $filters['ORBL']['comment'] =
  279. _("FREE - ORBL is another ORBS spinoff formed after ORBS shut down. May be SLOOOOOOW!");
  280. $filters['ORBZ-UK']['prefname'] = 'filters_spam_orbzuk';
  281. $filters['ORBZ-UK']['name'] = 'ORBZ-UK Lists';
  282. $filters['ORBZ-UK']['link'] = 'http://orbz.gst-group.co.uk';
  283. $filters['ORBZ-UK']['dns'] = 'orbz.gst-group.co.uk';
  284. $filters['ORBZ-UK']['comment'] =
  285. _("FREE - orbz.gst-group.co.uk lists not only open relays, but also mailservers that refuse or bounce email addressed to postmaster@<theirdomain>.");
  286. foreach ($filters as $Key => $Value) {
  287. $filters[$Key]['enabled'] = getPref($data_dir, $username,
  288. $filters[$Key]['prefname']);
  289. }
  290. return $filters;
  291. }
  292. function remove_filter ($id) {
  293. global $data_dir, $username;
  294. while ($nextFilter = getPref($data_dir, $username, 'filter' .
  295. ($id + 1))) {
  296. setPref($data_dir, $username, 'filter' . $id, $nextFilter);
  297. $id ++;
  298. }
  299. removePref($data_dir, $username, 'filter' . $id);
  300. }
  301. function filter_swap($id1, $id2) {
  302. global $data_dir, $username;
  303. $FirstFilter = getPref($data_dir, $username, 'filter' . $id1);
  304. $SecondFilter = getPref($data_dir, $username, 'filter' . $id2);
  305. if ($FirstFilter && $SecondFilter) {
  306. setPref($data_dir, $username, 'filter' . $id2, $FirstFilter);
  307. setPref($data_dir, $username, 'filter' . $id1, $SecondFilter);
  308. }
  309. }
  310. ?>