371 lines
12 KiB
PHP
Executable File
371 lines
12 KiB
PHP
Executable File
<?php
|
|
/*
|
|
AlternC - Web Hosting System
|
|
Copyright (C) 2002 by the AlternC Development Team.
|
|
http://alternc.org/
|
|
----------------------------------------------------------------------
|
|
LICENSE
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License (GPL)
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
To read the license please visit http://www.gnu.org/copyleft/gpl.html
|
|
----------------------------------------------------------------------
|
|
Purpose of file: Based on procmail-builder module, converts
|
|
the procmail generated by AlternC<=1.0.3 to AlternC>=3.0
|
|
----------------------------------------------------------------------
|
|
*/
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/**
|
|
MAIN FUNCTION
|
|
Read all the mail folders and search for .procmailrc's
|
|
*/
|
|
function procmail2sieve() {
|
|
global $ROOT;
|
|
$d=@opendir($ROOT);
|
|
if ($d) {
|
|
while ($c=readdir($d)) {
|
|
if (substr($c,0,1)==".") continue; // skip hidden files
|
|
if (is_dir($ROOT."/".$c)) {
|
|
// Go to level 2.
|
|
$e=@opendir($ROOT."/".$c);
|
|
if ($e) {
|
|
while ($f=readdir($e)) {
|
|
if (substr($f,0,1)==".") continue; // skip hidden files
|
|
if (is_file($ROOT."/".$c."/".$f."/.procmailrc")) {
|
|
// We found one .procmailrc, let's parse it on behalf of his user...
|
|
parseOneProcmail($f); /* ################## SUB FUNCTION ###################### */
|
|
}
|
|
}
|
|
closedir($e);
|
|
} else {
|
|
echo "ERROR: Cannot open ".$ROOT."/".$c."\n";
|
|
}
|
|
|
|
}
|
|
}
|
|
closedir($d);
|
|
} else {
|
|
echo "FATAL: cannot open ".$ROOT."\n";
|
|
exit();
|
|
}
|
|
} /* procmail2sieve */
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Parse ONE procmailrc, and write its sieve rules
|
|
*/
|
|
function parseOneProcmail($user) {
|
|
global $SIEVEROOT;
|
|
$email=preg_replace("#_([^_]*)$#","@$1",$user);
|
|
if ($rules=readrules($user)) { /* ################## SUB FUNCTION ###################### */
|
|
for($i=0; $i<count($rules); $i++) {
|
|
list($rules[$i]["conds"],$rules[$i]["actionparam"])=describe($rules[$i]); /* ################## SUB FUNCTION ###################### */
|
|
}
|
|
|
|
// Now we have $rule["type"] = the ACTION to accomplish + (if 1 or 4) $actionparam
|
|
// and a list of $rule["conds"][0]=condition type & $rule["conds"][1]=condition parameter (if not 5)
|
|
// Let's write a sieve script :)
|
|
$u=substr($u,0,1);
|
|
@mkdir($SIEVEROOT."/".$u."/".$user."/sieve");
|
|
@mkdir($SIEVEROOT."/".$u."/".$user."/sieve/tmp");
|
|
$uid=fileowner($SIEVEROOT."/".$u."/".$user);
|
|
chown($SIEVEROOT."/".$u."/".$user."/sieve",$uid);
|
|
chgrp($SIEVEROOT."/".$u."/".$user."/sieve","vmail");
|
|
chown($SIEVEROOT."/".$u."/".$user."/sieve/tmp",$uid);
|
|
chgrp($SIEVEROOT."/".$u."/".$user."/sieve/tmp","vmail");
|
|
|
|
$f=fopen($SIEVEROOT."/".$u."/".$user."/sieve/tmp/phpscript.sieve","wb");
|
|
if (!$f) {
|
|
echo "ERROR: Can't open '$user' in '$SIEVEROOT' for writing\n";
|
|
} else {
|
|
echo "OK: writing sieve script for $user (".count($rules)." rules)\n";
|
|
|
|
$avelsieveversion=array("major" => 1, "minor"=>9, "release" => 9, "string" => "1.9.9");
|
|
fputs($f,'# This script has been automatically generated by avelsieve
|
|
# (Sieve Mail Filters Plugin for Squirrelmail)
|
|
# Warning: If you edit this manually, then the changes will not
|
|
# be reflected in the users\' front-end!
|
|
#AVELSIEVE_VERSION'.urlencode(base64_encode(serialize($avelsieveversion))).'
|
|
#AVELSIEVE_CREATED'.time().'
|
|
#AVELSIEVE_MODIFIED'.time().'
|
|
require ["fileinto","envelope","reject","vacation","imap4flags","relational","comparator-i;ascii-numeric","regex","body","date"];
|
|
');
|
|
foreach($rules as $rule) {
|
|
if ($rule["type"]==2) continue; // IGNORE "Filter the message through SpamAssassin"
|
|
|
|
// Create the avelsieve array:
|
|
$avelrule=array();
|
|
// And sieve script:
|
|
$script="if ";
|
|
$avelrule["condition"]="and";
|
|
$avelrule["type"]=1;
|
|
if (!count($rule["conds"])) {
|
|
// no conditions
|
|
$script.="true\n";
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "all");
|
|
} else { // have conditions
|
|
$script.="allof (";
|
|
$first=true;
|
|
foreach($conds as $cond) {
|
|
if (!$first) $script.=",\n";
|
|
$first=false;
|
|
// What kind of condition?
|
|
switch($cond[0]) {
|
|
case 0: // subject
|
|
$script.='header :contains "Subject" "'.str_replace('"','\\"',$cond[1]).'"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "header", "header" => "Subject", "matchtype" => "contains", "headermatch" => $cond[1] );
|
|
break;
|
|
case 1: // sender
|
|
$script.='header :contains "From" "'.str_replace('"','\\"',$cond[1]).'"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "header", "header" => "From", "matchtype" => "contains", "headermatch" => $cond[1] );
|
|
break;
|
|
case 2: // recipient
|
|
$script.='address :contains ["to", "cc"] "'.str_replace('"','\\"',$cond[1]).'"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "address", "address" => "toorcc", "matchtype" => "contains", "addressmatch" => $cond[1] );
|
|
break;
|
|
case 3: // List-Post
|
|
$script.='header :contains "List-Post" "'.str_replace('"','\\"',$cond[1]).'"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "header", "header" => "List-Post", "matchtype" => "contains", "headermatch" => $cond[1] );
|
|
break;
|
|
case 4: // List-Id
|
|
$script.='header :contains "List-Id" "'.str_replace('"','\\"',$cond[1]).'"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "header", "header" => "List-Id", "matchtype" => "contains", "headermatch" => $cond[1] );
|
|
break;
|
|
case 5: // Spamassassin
|
|
$script.='header :contains "X-Spam-Status" "Yes"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "header", "header" => "X-Spam-Status", "matchtype" => "contains", "headermatch" => "Yes" );
|
|
break;
|
|
case 6: // Delivered-To
|
|
$script.='envelope :contains "to" "'.str_replace('"','\\"',$cond[1]).'"';
|
|
$avelrule["cond"][]=array("kind" => "message", "type" => "envelope", "envelope" => "to", "matchtype" => "contains", "envelopematch" => $cond[1] );
|
|
break;
|
|
|
|
}
|
|
}
|
|
$script.=")\n{\n";
|
|
}
|
|
// Now the ACTION:
|
|
switch($rule["type"]) {
|
|
case 1: // move to
|
|
$script.='fileinto "'.str_replace('"','\\"',$rule["actionparam"]).'";
|
|
stop;
|
|
';
|
|
$avelrule["action"] = 5;
|
|
$avelrule["folder"] = $rule["actionparam"];
|
|
$avelrule["stop"] = "on";
|
|
break;
|
|
case 3: // Discard (for good)
|
|
$script.='discard;
|
|
stop;
|
|
';
|
|
$avelrule["action"] = 2;
|
|
$avelrule["stop"] = "on";
|
|
break;
|
|
case 4: // Forward To (copy)
|
|
$script.='redirect "'.str_replace('"','\\"',$rule["actionparam"]).'";
|
|
';
|
|
$avelrule["action"] = 4;
|
|
$avelrule["redirectemail"] = $rule["actionparam"];
|
|
break;
|
|
case 5: // Auto-Reply
|
|
$script.='vacation :days 7 :addresses ["'.$email.'"@ :subject "Auto Reply" text:
|
|
'.str_replace("\\'","'",@file_get_contents($ROOT."/".$u."/".$user."/".$user.".txt")).'
|
|
.
|
|
;
|
|
';
|
|
$avelrule["action"] = 6;
|
|
$avelrule["vac_addresses"] = $email;
|
|
$avelrule["vac_subject"] = "Auto Reply";
|
|
$avelrule["vac_days"] = 7;
|
|
$avelrule["vac_message"] = @file_get_contents($ROOT."/".$u."/".$user."/".$user.".txt");
|
|
break;
|
|
}
|
|
$script.="}\n";
|
|
// Now put it into the script file :
|
|
fputs($f,"#START_SIEVE_RULE".urlencode(base64_encode(serialize($avelrule)))."END_SIEVE_RULE\n");
|
|
fputs($f,$script);
|
|
/*
|
|
if allof (header :contains "From" "expediteur@coin.pan",
|
|
header :contains "To" "destinataire@coin.pan")
|
|
{
|
|
fileinto "INBOX.test";
|
|
stop;
|
|
}
|
|
*/
|
|
} /* for each rule */
|
|
|
|
fclose($f);
|
|
|
|
// Then Move it to the right place
|
|
@unlink($SIEVEROOT."/".$u."/".$user."/sieve/phpscript.sieve");
|
|
rename(
|
|
$SIEVEROOT."/".$u."/".$user."/sieve/tmp/phpscript.sieve",
|
|
$SIEVEROOT."/".$u."/".$user."/sieve/phpscript.sieve"
|
|
);
|
|
chown($SIEVEROOT."/".$u."/".$user."/sieve/phpscript.sieve",$uid);
|
|
chgrp($SIEVEROOT."/".$u."/".$user."/sieve/phpscript.sieve","vmail");
|
|
}
|
|
} else {
|
|
echo "ERROR: can't read rules for $user\n";
|
|
}
|
|
|
|
} /* parseOneProcmauil */
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Read rules, fill an array
|
|
from m_procmail.php original file
|
|
yeah I know, ereg() is deprecated ;)
|
|
*/
|
|
function readrules($user="") {
|
|
if (!$user) $user=$this->user;
|
|
$u=substr($user,0,1);
|
|
if (!file_exists("/var/alternc/mail/$u/$user/.procmailrc")) {
|
|
return false;
|
|
}
|
|
$f=fopen("/var/alternc/mail/$u/$user/.procmailrc","rb");
|
|
$state=0; $rulenum=0; $ligne=0;
|
|
$res=array();
|
|
while (!feof($f)) {
|
|
$found=false; // found allow us to know if we found something for each loop
|
|
$s=fgets($f,1024);
|
|
$s=trim($s);
|
|
if ($state==1 && !ereg("^# RuleEnd$",$s)) {
|
|
$res[$rulenum]["rule"][$res[$rulenum]["count"]++]=$s;
|
|
$found=true;
|
|
}
|
|
if ($state==1 && ereg("^# RuleEnd$",$s)) {
|
|
$state=0;
|
|
$rulenum++;
|
|
$found=true;
|
|
}
|
|
if ($state==0 && ereg("^# RuleType ([0-9][0-9]) -- (.*)?$",$s,$r)) {
|
|
$state=1;
|
|
$res[$rulenum]["type"]=$r[1];
|
|
$res[$rulenum]["name"]=$r[2];
|
|
$res[$rulenum]["count"]=0;
|
|
$found=true;
|
|
}
|
|
if (!$found && $state!=0) {
|
|
return false;
|
|
}
|
|
$ligne++;
|
|
}
|
|
fclose($f);
|
|
return $res;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
/** Take ONE rule array, extract properly
|
|
returns one array with the conditions (which are arrays with Condition Type and Value)
|
|
and the action parameter
|
|
*/
|
|
function describe($rule) {
|
|
|
|
// Lecture des conditions :
|
|
$cond=array();
|
|
switch ($rule["type"]) {
|
|
case 5:
|
|
$i=1;
|
|
while ($rule["rule"][$i]!="* !^FROM_DAEMON" && $rule["rule"][$i]!="") {
|
|
$cond[]=$rule["rule"][$i];
|
|
$i++;
|
|
}
|
|
break;
|
|
default:
|
|
$i=1;
|
|
while (substr($rule["rule"][$i],0,1)=="*") {
|
|
$cond[]=$rule["rule"][$i];
|
|
$i++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// $cond is an array of conditions
|
|
// let's parse the condition : (see arrays at the top of this file)
|
|
$conds=array();
|
|
|
|
for($i=0;$i<count($cond);$i++) {
|
|
if (ereg("^\\* \\^Subject\\.\\*(.*)$",$cond[$i],$t)) {
|
|
$conds[]=array( 0, $t[1] );
|
|
}
|
|
if (ereg("^\\* \\^From\\.\\*(.*)$",$cond[$i],$t)) {
|
|
$conds[]=array( 1, $t[1] );
|
|
}
|
|
if (ereg("^\\* \\^TO_(.*)$",$cond[$i],$t)) {
|
|
$conds[]=array( 2, $t[1] );
|
|
}
|
|
if (ereg("^\\* \\^List-Post: (.*)$",$cond[$i],$t)) {
|
|
$conds[]=array( 3, $t[1] );
|
|
}
|
|
if (ereg("^\\* \\^List-Id: (.*)$",$cond[$i],$t)) {
|
|
$conds[]=array( 4, $t[1] );
|
|
}
|
|
if (ereg("^\\* \\^X-Spam-Status: Yes$",$cond[$i])) {
|
|
$conds[]=array( 5 );
|
|
}
|
|
if (ereg("^\\* \\^Delivered-To:\\.\\*(.*)$",$cond[$i],$t)) {
|
|
$conds[]=array( 6, $t[1] );
|
|
}
|
|
}
|
|
|
|
// Action :
|
|
$actionparam=false;
|
|
switch ($rule["type"]) {
|
|
case 1:
|
|
$actionparam=$rule["rule"][count($rule["rule"])-2]; /* Folder */
|
|
break;
|
|
case 4:
|
|
$actionparam = substr($rule["rule"][count($rule["rule"])-2],0,15); /* Recipient */
|
|
break;
|
|
}
|
|
return array($conds,$actionparam);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Help for humans ... */
|
|
|
|
$acriteria=array(
|
|
0 => "Le sujet du message contient ...",
|
|
1 => "L'expediteur du message est contient ...",
|
|
2 => "L'un des destinataires du message contient ...",
|
|
3 => "L'en-tete 'List-Post' du message est ...",
|
|
4 => "L'en-tete 'List-Id' du message est ...",
|
|
5 => "SpamAssassin considere qu'il s'agit d'un Spam",
|
|
6 => "L'en-tete 'Delivered-To' du message contient ...",
|
|
);
|
|
$aactions=array(
|
|
1 => "Move the message to this folder",
|
|
2 => "Filter the message through SpamAssassin",
|
|
3 => "Discard the message (for good !)",
|
|
4 => "Forward the mail to",
|
|
5 => "Auto-reply",
|
|
);
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
// CONFIGURATION :
|
|
$ROOT="/var/alternc/mail";
|
|
$SIEVEROOT="/var/lib/dovecot/sieve";
|
|
// GO !
|
|
procmail2sieve();
|
|
|