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'exp<78>diteur 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 consid<69>re 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();
 | ||
| 
 |