Source for file filters.php
Documentation is available at filters.php
* Message and Spam Filter Plugin - Filtering Functions
* @copyright © 1999-2006 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id: filters.php,v 1.92 2006/08/05 14:49:48 kink Exp $
* do not allow to call this file directly
if ((isset
($_SERVER['SCRIPT_FILENAME']) &&
$_SERVER['SCRIPT_FILENAME'] == __FILE__
) ||
(isset
($HTTP_SERVER_SERVER['SCRIPT_FILENAME']) &&
$HTTP_SERVER_SERVER['SCRIPT_FILENAME'] == __FILE__
) ) {
header("Location: ../../src/login.php");
global $UseSeparateImapConnection,
$AllowSpamFilters, $SpamFilters_YourHop, $SpamFilters_ShowCommercial,
$SpamFilters_DNScache, $SpamFilters_BulkQuery, $SpamFilters_SharedCache,
* load required functions. Plugin depends on IMAP functions and they are not
* loaded in src/webmail.php
include_once (SM_PATH .
'functions/imap.php');
/** load default config */
include_once (SM_PATH .
'plugins/filters/config_default.php');
// default config was removed.
$UseSeparateImapConnection =
false;
$AllowSpamFilters =
true;
$SpamFilters_YourHop =
' ';
$SpamFilters_ShowCommercial =
false;
$SpamFilters_DNScache =
array();
$SpamFilters_BulkQuery =
'';
$SpamFilters_SharedCache =
true;
$SpamFilters_CacheTTL =
7200;
include_once (SM_PATH .
'config/filters_config.php');
include_once (SM_PATH .
'plugins/filters/config.php');
function filters_optpage_register_block() {
$optpage_blocks[] =
array(
'name' =>
_("Message Filters"),
'url' =>
SM_PATH .
'plugins/filters/options.php',
'desc' =>
_("Filtering enables messages with different criteria to be automatically filtered into different folders for easier organization."),
$optpage_blocks[] =
array(
'name' =>
_("SPAM Filters"),
'url' =>
SM_PATH .
'plugins/filters/spamoptions.php',
'desc' =>
_("SPAM filters allow you to select from various DNS based blacklists to detect junk email in your INBOX and move it to another folder (like Trash)."),
/* Receive the status of the folder and do something with it */
global $filter_inbox_count;
if (empty($filter_inbox_count)) $filter_inbox_count=
0;
if ($statusarr['MAILBOX'] ==
'INBOX')
if (!empty($statusarr['MESSAGES'])) $filter_inbox_count=
$statusarr['MESSAGES'];
* Saves the DNS Cache to disk
function filters_SaveCache () {
$fp =
fopen($data_dir .
'/dnscache', 'r');
$fp =
fopen($data_dir .
'/dnscache', 'w+');
$fp =
fopen($data_dir .
'/dnscache', 'r');
$fp1 =
fopen($data_dir .
'/dnscache', 'w+');
foreach ($SpamFilters_DNScache as $Key=>
$Value) {
$tstr =
$Key .
',' .
$Value['L'] .
',' .
$Value['T'] .
"\n";
* Loads the DNS Cache from disk
function filters_LoadCache () {
$SpamFilters_DNScache =
array();
if ($fp =
fopen ($data_dir .
'/dnscache', 'r')) {
while ($data =
fgetcsv($fp,1024)) {
$SpamFilters_DNScache[$data[0]]['L'] =
$data[1];
$SpamFilters_DNScache[$data[0]]['T'] =
$data[2];
* Uses the BulkQuery executable to query all the RBLs at once
* @param array $filters Array of SPAM Fitlers
* @param array $IPs Array of IP Addresses
function filters_bulkquery($filters, $IPs) {
global $attachment_dir, $username,
foreach ($filters as $key =>
$value) {
if ($filters[$key]['enabled']) {
if ($filters[$key]['dns']) {
$rbls[$filters[$key]['dns']] =
true;
$bqfil =
$attachment_dir .
$username .
'-bq.in';
$fp =
fopen($bqfil, 'w');
fputs ($fp, $SpamFilters_CacheTTL .
"\n");
foreach ($rbls as $key =>
$value) {
fputs ($fp, '.' .
$key .
"\n");
fputs ($fp, "----------\n");
foreach ($IPs as $key =>
$value) {
fputs ($fp, $key .
"\n");
exec ($SpamFilters_BulkQuery .
' < ' .
$bqfil, $bqout);
foreach ($bqout as $value) {
$SpamFilters_DNScache[$Chunks[0]]['L'] =
$Chunks[1];
$SpamFilters_DNScache[$Chunks[0]]['T'] =
$Chunks[2] +
time();
* Starts the filtering process
* @param array $hook_args (since 1.5.2) do hook arguments. Is used to check
* hook name, array key = 0.
function start_filters($hook_args) {
global $imapServerAddress, $imapPort, $imap_stream, $imapConnection,
* check hook that calls filtering. If filters are called by right_main_after_header,
* do filtering only when we are in INBOX folder.
if ($hook_args[0]==
'right_main_after_header' &&
$filters =
load_filters();
// No point running spam filters if there aren't any to run //
$spamfilters =
load_spam_filters();
$AllowSpamFilters =
false;
foreach($spamfilters as $filterskey=>
$value) {
if ($value['enabled'] ==
'yes') {
$AllowSpamFilters =
true;
if (!$AllowSpamFilters &&
empty($filters)) {
// Detect if we have already connected to IMAP or not.
// Also check if we are forced to use a separate IMAP connection
if ((!isset
($imap_stream) &&
!isset
($imapConnection)) ||
$UseSeparateImapConnection ) {
$stream =
sqimap_login($username, false, $imapServerAddress,
$previously_connected =
false;
} else if (isset
($imapConnection)) {
$stream =
$imapConnection;
$previously_connected =
true;
$previously_connected =
true;
if (!isset
($filter_inbox_count)) {
if (!empty($aStatus['MESSAGES'])) {
$filter_inbox_count=
$aStatus['MESSAGES'];
if ($filter_inbox_count >
0) {
// Filter spam from inbox before we sort them into folders
if (!$previously_connected) {
* Does the loop through each filter
* @param stream imap_stream the stream to read from
function user_filters($imap_stream) {
global $data_dir, $username;
$filters =
load_filters();
$filters_user_scan =
getPref($data_dir, $username, 'filters_user_scan');
for ($i=
0, $num =
count($filters); $i <
$num; $i++
) {
// If it is the "combo" rule
if ($filters[$i]['where'] ==
'To or Cc') {
* If it's "TO OR CC", we have to do two searches, one for TO
$expunge =
filter_search_and_delete($imap_stream, 'TO',
$filters[$i]['what'], $filters[$i]['folder'], $filters_user_scan, $expunge);
$expunge =
filter_search_and_delete($imap_stream, 'CC',
$filters[$i]['what'], $filters[$i]['folder'], $filters_user_scan, $expunge);
} else if ($filters[$i]['where'] ==
'Header and Body') {
$expunge =
filter_search_and_delete($imap_stream, 'TEXT',
$filters[$i]['what'], $filters[$i]['folder'], $filters_user_scan, $expunge);
} else if ($filters[$i]['where'] ==
'Message Body') {
$expunge =
filter_search_and_delete($imap_stream, 'BODY',
$filters[$i]['what'], $filters[$i]['folder'], $filters_user_scan, $expunge);
* If it's a normal TO, CC, SUBJECT, or FROM, then handle it
$expunge =
filter_search_and_delete($imap_stream, $filters[$i]['where'],
$filters[$i]['what'], $filters[$i]['folder'], $filters_user_scan, $expunge);
// Clean out the mailbox whether or not auto_expunge is on
// That way it looks like it was redirected properly
* Creates and runs the IMAP command to filter messages
* @param string $where Which part of the message to search (TO, CC, SUBJECT, etc...)
* @param string $what String to search for
* @param string $where_to Folder it will move to
* @param string $user_scan Whether to search all or just unseen
* @param string $should_expunge
* @param boolean $where Which part of location to search
function filter_search_and_delete($imap_stream, $where, $what, $where_to, $user_scan,
global $languages, $squirrelmail_language, $allow_charset_search, $imap_server_type;
//TODO: make use of new mailbox cache. See mailbox_display.phpinfo
if ($user_scan ==
'new') {
$category .=
' UNDELETED';
if ($allow_charset_search &&
isset
($languages[$squirrelmail_language]['CHARSET']) &&
$languages[$squirrelmail_language]['CHARSET']) {
$search_str =
'SEARCH CHARSET '
.
strtoupper($languages[$squirrelmail_language]['CHARSET'])
$search_str =
'SEARCH CHARSET US-ASCII ' .
$category;
if ($where ==
'Header') {
$where =
trim($where .
' ' .
$what[0]);
// see comments in squirrelmail sqimap_search function
if ($imap_server_type ==
'macosx' ||
$imap_server_type ==
'hmailserver') {
$search_str .=
' ' .
$where .
' ' .
$what;
/* read data back from IMAP */
$search_str .=
' ' .
$where .
' {' .
strlen($what) .
"}";
fputs ($imap_stream, $sid .
' ' .
$search_str .
"\r\n");
# server should respond with Ready for argument, then we will send search text
fputs ($imap_stream, "$what\r\n");
list
($rtag,$response,$message)=
explode(' ',$read3,3);
## $read2 = sqimap_retrieve_imap_response($imap_stream, $sid, true,
## $response, $message, $search_str, false, true, false);
#echo "RR2 $read2 / RESPONSE $response<br>";
for ($i =
0, $iCnt =
count($read); $i <
$iCnt; ++
$i) {
if (preg_match("/^\* SEARCH (.+)$/", $read[$i], $regs)) {
if ($response ==
'OK' &&
count($ids)) {
} elseif ($response !=
'OK') {
$query =
$search_str .
"\r\n".
$what .
"\r\n";
if (strpos($message,'BADCHARSET') !==
false ||
strpos($message,'character') !==
false) {
* Loops through all the Received Headers to find IP Addresses
* @param stream imap_stream the stream to read from
function spam_filters($imap_stream) {
global $data_dir, $username;
$filters_spam_scan =
getPref($data_dir, $username, 'filters_spam_scan');
$filters_spam_folder =
getPref($data_dir, $username, 'filters_spam_folder');
$filters =
load_spam_filters();
if ($SpamFilters_SharedCache) {
foreach ($filters as $Key =>
$Value) {
// Ask for a big list of all "Received" headers in the inbox with
// flags for each message. Kinda big.
if ($filters_spam_scan ==
'new') {
$read =
sqimap_run_command($imap_stream, 'SEARCH UNSEEN', true, $response, $message, TRUE);
for ($i =
0, $iCnt =
count($read); $i <
$iCnt; ++
$i) {
if (preg_match("/^\* SEARCH (.+)$/", $read[$i], $regs)) {
if ($filters_spam_scan ==
'new' &&
count($search_array)) {
} else if ($filters_spam_scan !=
'new') {
$bulkquery =
(strlen($SpamFilters_BulkQuery) >
0 ?
true :
false);
foreach ($headers as $id =>
$aValue) {
if (isset
($aValue['UID'])) {
$MsgNum =
$aValue['UID'];
// Look through all of the Received headers for IP addresses
if (isset
($aValue['RECEIVED'])) {
foreach ($aValue['RECEIVED'] as $received) {
// Check to see if this line is the right "Received from" line