root/alternc-procmail/trunk/m_procmail.php

Revision 1614, 15.7 kB (checked in by benjamin, 2 years ago)

deboguage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /*
3  $Id$
4  ----------------------------------------------------------------------
5  AlternC - Web Hosting System
6  Copyright (C) 2002 by the AlternC Development Team.
7  http://alternc.org/
8  ----------------------------------------------------------------------
9  Based on:
10  Valentin Lacambre's web hosting softwares: http://altern.org/
11  ----------------------------------------------------------------------
12  LICENSE
13
14  This program is free software; you can redistribute it and/or
15  modify it under the terms of the GNU General Public License (GPL)
16  as published by the Free Software Foundation; either version 2
17  of the License, or (at your option) any later version.
18
19  This program is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  GNU General Public License for more details.
23
24  To read the license please visit http://www.gnu.org/copyleft/gpl.html
25  ----------------------------------------------------------------------
26  Original Author of file: Benjamin Sonntag
27  Purpose of file: Build a .procmailrc file for a user.
28      Manage ldap aliases with pipes to procmail for a user.
29  ----------------------------------------------------------------------
30 */
31
32 bindtextdomain("procmail_builder", "/var/alternc/bureau/locales");
33
34 // Every plugin MUST start with that require to be able to access other classes :
35
36 class m_procmail {
37
38 var $clsid="procmail";    /* Every plugin has a distinct CLSID, corresponding to his error messages class. */
39 var $uid=0;         /* Membre actuellement connecté */
40 var $user;        /* pop Login name */
41
42 /*
43 How it works :
44 Normally, a pop mail entry is built as follow in the system db :
45     mail_domain (mail='friend@public.com'  alias='list of aliases+ friend_public.com'
46         uid=$cuid  pop=1 type=0 (standard mail ) )
47     mail_users (pop courier account) : alias = friend@public.com && alias = friend_public.com
48     mail_alias (postfix indirection) : mail = friend_public.com && alias = /var/alternc/mail...
49 with procmail_builder active, the entries are as follow :
50     mail_alias (postfix indirection) : mail = friend_public.com && alias = |/var/alternc/mail...
51 */
52
53 /*****************************************************************************
54 m_procmail() Constructeur de la classe m_procmail
55 *****************************************************************************/
56 function m_procmail($user="") {
57     $this->user=str_replace("@","_",$user);
58 }
59
60 /*****************************************************************************
61 get_status([$user]) retourne l'état de dérivation de la boite par procmail
62 de l'utilisateur $user (ou de l'utilisateur courant)
63 retourne 1 pour une boite dérivée, 0 pour une boite non dérivée, et false si
64 une erreur s'est produite
65 *****************************************************************************/
66 function get_status($user="") {
67     global $db;
68     if (!$user) $user=$this->user;
69
70     $db->query("SELECT alias FROM mail_alias WHERE mail='".$user."';");
71     if ($db->next_record()) {
72         if (substr($db->f("alias"),1,1)=="|") {
73             return 1;
74         }
75     }
76     return 0;
77 }
78
79 /*****************************************************************************
80 disable([$user]) Désactive procmail pour un utilisateur
81 Ne détruit pas le jeu de règles :)
82 Retourne True si tout s'est bien passé, false sinon.
83 *****************************************************************************/
84 function disable($user="") {
85     global $er,$db;
86     if (!$user) $user=$this->user;
87     $u=substr($user,0,1);
88     $db->query("UPDATE mail_alias SET alias='/var/alternc/mail/$u/$user/Maildir/' WHERE mail='$user';");
89     return true;
90 }
91
92 /*****************************************************************************
93 enable([$user]) Active procmail pour un utilisateur
94 Construit le jeu de règles par défaut si besoin :)
95 Retourne True si tout s'est bien passé, false sinon.
96 *****************************************************************************/
97 function enable($user="") {
98     global $er,$db;
99     if (!$user) $user=$this->user;
100     $u=substr($user,0,1);
101     // 1. on vérifie qu'un .procmailrc existe, sinon on crée le .procmailrc par défaut.
102     if (!file_exists("/var/alternc/mail/$u/$user/.procmailrc")) {
103         $f=fopen("/var/alternc/mail/$u/$user/.procmailrc","wb");
104         fputs($f,str_replace("%%HOME%%","/var/alternc/mail/$u/$user",join("",file("/var/alternc/bureau/class/procmail_builder/procmailrc.default"))));
105         fclose($f);
106     }
107     $db->query("UPDATE mail_alias SET alias='\"|/usr/bin/procmail -m /var/alternc/mail/$u/$user/.procmailrc\"' WHERE mail='$user';");
108     return true;
109 }
110
111
112 /*****************************************************************************
113 readrules([$user]) Lit le fichier procmailrc d'un utilisateur et retourne
114 les règles qu'il contient sous la forme d'un tableau ordonné de règle.
115 Chaque règle est un tableau associatif de la forme :
116 $c[$i]["type"]=Type de la règle (numéro)
117 $c[$i]["name"]=Nom de la règle (texte)
118 $c[$i]["count"]=Nombre de lignes dans la regle
119 $c[$i]["rule"][0-n]=Ligne de la règle
120 peut retourner un tableau vide (pas de règles) ou false si le fichier
121 .procmailrc n'existe pas ou est incorrectement formatté.
122     (note : contient un automate de lecture de .procmailrc.)
123 *****************************************************************************/
124 function readrules($user="") {
125     global $er;
126     if (!$user) $user=$this->user;
127     $u=substr($user,0,1);
128     if (!file_exists("/var/alternc/mail/$u/$user/.procmailrc")) {
129         $er->raise($this->clsid,6);
130         return false;
131     }
132     $f=fopen("/var/alternc/mail/$u/$user/.procmailrc","rb");
133     $state=0;    $rulenum=0;    $ligne=0;
134     $res=array();
135     while (!feof($f)) {
136         $found=false; // found permet de savoir si on a trouvé qqchose à chaque tour.
137         $s=fgets($f,1024);
138         $s=trim($s);
139         if ($state==1 && !ereg("^# RuleEnd$",$s)) {
140                         $res[$rulenum]["rule"][$res[$rulenum]["count"]++]=$s;
141                         $found=true;
142                 }
143                 if ($state==1 && ereg("^# RuleEnd$",$s)) { // $
144                         $state=0;
145                         $rulenum++;
146                         $found=true;
147                 }
148         if ($state==0 && ereg("^# RuleType ([0-9][0-9]) -- (.*)?$",$s,$r)) {
149             $state=1;
150             $res[$rulenum]["type"]=$r[1];
151             $res[$rulenum]["name"]=$r[2];
152             $res[$rulenum]["count"]=0;
153             $found=true;
154         }
155         if (!$found && $state!=0) {
156             $er->raise($this->clsid,5,$ligne);
157             return false;
158         }
159         $ligne++;
160     }
161     fclose($f);
162     return $res;
163 }
164
165 /*****************************************************************************
166 writerules($rule,[$user]) Ecrit le fichier procmailrc d'un utilisateur en prenant
167 le tableau de règle en paramètre. Remplit le .procmailrc avec le fichier
168 par défaut, suivi des règles dans l'ordre du tableau.
169 retourne false si le fichier .procmailrc n'existe pas déjà.
170 retourne true si tout va bien.
171 *****************************************************************************/
172 function writerules($res,$user="") {
173     global $er;
174     if (!$user) $user=$this->user;
175     $u=substr($user,0,1);
176     if (!file_exists("/var/alternc/mail/$u/$user/.procmailrc")) {
177         $er->raise($this->clsid,6);
178         return false;
179     }
180     $f=fopen("/var/alternc/mail/$u/$user/.procmailrc","wb");
181     fputs($f,str_replace("%%HOME%%","/var/alternc/mail/$u/$user",join("",file("/var/alternc/bureau/class/procmail_builder/procmailrc.default"))));
182     for($i=0;$i<count($res);$i++) {
183         $res[$i]["name"]=trim(str_replace("\r","",str_replace("\n","",$res[$i]["name"])));
184         fputs($f,"# RuleType ".sprintf("%02d",$res[$i]["type"])." -- ".$res[$i]["name"]."\n");
185         for($j=0;$j<$res[$i]["count"];$j++) {
186             fputs($f,$res[$i]["rule"][$j]."\n");
187         }
188         fputs($f,"# RuleEnd\n\n");
189     }
190     fclose($f);
191     return true;
192 }
193
194 /*****************************************************************************
195 addrule($rule,[$user]) Ajout la regle $rule au fichier procmailrc
196 d'un utilisateur retourne false si le fichier .procmailrc n'existe pas déjà.
197 retourne true si tout va bien.
198 *****************************************************************************/
199 function addrule($rule,$user="") {
200     global $er;
201     if (!$user) $user=$this->user;
202     $u=substr($user,0,1);
203     if (!file_exists("/var/alternc/mail/$u/$user/.procmailrc")) {
204         $er->raise($this->clsid,6);
205         return false;
206     }
207     $f=fopen("/var/alternc/mail/$u/$user/.procmailrc","ab");
208     $rule["name"]=trim(str_replace("\r","",str_replace("\n","",$rule["name"])));
209     fputs($f,"# RuleType ".sprintf("%02d",$rule["type"])." -- ".$rule["name"]."\n");
210     for($j=0;$j<$rule["count"];$j++) {
211         fputs($f,$rule["rule"][$j]."\n");
212     }
213     fputs($f,"# RuleEnd\n\n");
214     fclose($f);
215     return true;
216 }
217
218 /*****************************************************************************
219 buildrule($crit,$crittext,$raction,$foldertogo,$emailto,$autoreplytxt,[$user])
220 Construit la règle basée sur les critères de formulaire passés en paramètre.
221 *****************************************************************************/
222 function buildrule($rulename,$crit,$crittext,$raction,$foldertogo,$emailto,$autoreplytxt,$user="") {
223     global $er;
224     if (!$user) $user=$this->user;
225     $u=substr($user,0,1);
226     $mail=$user;
227     if ($c=strrpos($mail,"_")) {
228         $mail=substr($mail,0,$c)."@".substr($mail,$c+1);
229     }
230     // Vérification de la monovalence de Spam, Forward et AutoReply
231     if ($raction==2 || $raction==4 || $raction==5) {
232         $r=$this->readrules($user);
233         for($a=0;$a<count($r);$a++) {
234             if ($r[$a]["type"]==$raction) {
235                 $er->raise($this->clsid,9);
236                 return false;
237             }
238         }
239     }
240     $r=array();
241     $r["type"]=$raction;
242     $r["name"]=str_replace("\n","",trim($rulename));
243     if (!$r["name"]) $r["name"]="-";
244     $r["count"]=0;
245     switch ($raction) {
246     case 2:
247         $r["rule"][$r["count"]++]=":0 fw";
248         break;
249     case 4:
250         $r["rule"][$r["count"]++]=":0 c";
251         break;
252     case 5:
253         $r["rule"][$r["count"]++]=":0 Whc: /var/alternc/mail/$u/$user/$user.lock";
254         break;
255     default:
256         $r["rule"][$r["count"]++]=":0";
257         break;
258     }
259
260     for($j=0;$j<count($crit);$j++) {
261         $tt=str_replace(array("\n","?",".","*","+"),
262                                 array("","\\?","\\.","\\*", "\\+"),
263                             $crittext[$j]);
264
265         switch ($crit[$j]) {
266         case 0:
267             $s="* ^Subject.*$tt";
268             break;
269         case 1:
270             $s="* ^From.*$tt";
271             break;
272         case 2:
273             $s="* ^TO_$tt";
274             break;
275         case 3:
276             $s="* ^List-Post: $tt";
277             break;
278         case 4:
279             $s="* ^List-Id: $tt";
280             break;
281         case 5:
282             $s="* ^X-Spam-Status: Yes";
283             break;
284         case 6:
285             $s="* ^Delivered-To:.*$tt";
286             break;
287         }
288     $r["rule"][$r["count"]++]=$s;
289     } // for criteria.
290
291
292     switch ($raction) {
293     case 1:
294         //$r["rule"][$r["count"]++]=str_replace(" ","\\ ",substr($foldertogo,5))."/";
295         $r["rule"][$r["count"]++]=".".str_replace(array("\\\\"," "),array("\\","\\ "),addslashes(quotemeta(substr($foldertogo,6))))."/";
296         break;
297     case 2:
298         $r["rule"][$r["count"]++]="| /usr/bin/spamc";
299         break;
300     case 3:
301         $r["rule"][$r["count"]++]="/dev/null";
302         break;
303     case 4:
304         if (checkmail($emailto)) {
305             $er->raise($this->clsid,10);
306             return false;
307         }
308         $r["rule"][$r["count"]++]='|$SENDMAIL -oi '.$emailto;
309         break;
310     case 5:
311         $r["rule"][$r["count"]++]="* !^FROM_DAEMON";
312         $r["rule"][$r["count"]++]="* !^X-Loop: $mail";
313         $r["rule"][$r["count"]++]="| formail -rD 8192 /var/alternc/mail/$u/$user/$user.list";
314         $r["rule"][$r["count"]++]="";
315         $r["rule"][$r["count"]++]=":0 ehc";
316         $r["rule"][$r["count"]++]="| (formail -rtI\"Precedence: junk\" -I\"From: <$mail>\" -A\"X-Loop: $mail\" ; cat /var/alternc/mail/$u/$user/$user.txt) | ".'$'."SENDMAIL -oi -t";
317         $f=fopen("/var/alternc/mail/$u/$user/$user.txt","wb");
318         fputs($f,$autoreplytxt);
319         fclose($f);
320         @unlink("/var/alternc/mail/$u/$user/$user.list");
321         @unlink("/var/alternc/mail/$u/$user/$user.lock");
322     }
323     $r["rule"][$r["count"]++]="";
324     return $r;
325 }
326
327 /*****************************************************************************
328 uprule($rules,$i) Remonte d'un cran la $i-ème règle du tableau de
329 règle $rules retourne true si tout va bien. ($i>0)
330 *****************************************************************************/
331 function uprule($res,$i) {
332     global $er;
333     $i=intval($i);
334     if (count($res)<$i || $i==0) {
335         $er->raise($this->clsid,7);
336         return false;
337     }
338     $t=$res[$i];
339     $res[$i]=$res[$i-1];
340     $res[$i-1]=$t;
341     return $res;
342 }
343
344 /*****************************************************************************
345 downrule($rules,$i) Descend d'un cran la $i-ème règle du tableau de
346 règle $rules retourne true si tout va bien.
347 *****************************************************************************/
348 function downrule($res,$i) {
349     global $er;
350     $i=intval($i);
351     if ((count($res)-1)<$i) {
352         $er->raise($this->clsid,7);
353         return false;
354     }
355     $t=$res[$i];
356     $res[$i]=$res[$i+1];
357     $res[$i+1]=$t;
358     return $res;
359 }
360
361 /*****************************************************************************
362 describe($rule) Retourne un text dans la langue courante décrivant la règle
363 $rule passée en paramètre.
364 *****************************************************************************/
365 function describe($rule) {
366     $s="";
367
368     // Lecture des conditions :
369     $cond=array();
370     switch ($rule["type"]) {
371     case 5:
372         $i=1;
373         while ($rule["rule"][$i]!="* !^FROM_DAEMON" && $rule["rule"][$i]!="") {
374             $cond[]=$rule["rule"][$i];
375             $i++;
376         }
377         break;
378     default:
379         $i=1;
380         while (substr($rule["rule"][$i],0,1)=="*") {
381             $cond[]=$rule["rule"][$i];
382             $i++;
383         }
384         break;
385     }
386     // On a cond, on le parse :)
387     if (count($cond)) {
388         $s.="<small>";
389     }
390     for($i=0;$i<count($cond);$i++) {
391         if ($i) $s.=" et ";
392         if (ereg("^\\* \\^Subject\\.\\*(.*)$",$cond[$i],$t)) {
393             $s.=_("procmail_crit_0")."&nbsp;&nbsp;<code>".str_replace("\\","",$t[1])."</code>";
394         }
395         if (ereg("^\\* \\^From\\.\\*(.*)$",$cond[$i],$t)) {
396             $s.=_("procmail_crit_1")."&nbsp;&nbsp;<code>".str_replace("\\","",$t[1])."</code>";
397         }
398         if (ereg("^\\* \\^TO_(.*)$",$cond[$i],$t)) {
399             $s.=_("procmail_crit_2")."&nbsp;&nbsp;<code>".str_replace("\\","",$t[1])."</code>";
400         }
401         if (ereg("^\\* \\^List-Post: (.*)$",$cond[$i],$t)) {
402             $s.=_("procmail_crit_3")."&nbsp;&nbsp;<code>".str_replace("\\","",$t[1])."</code>";
403         }
404         if (ereg("^\\* \\^List-Id: (.*)$",$cond[$i],$t)) {
405             $s.=_("procmail_crit_4")."&nbsp;&nbsp;<code>".str_replace("\\","",$t[1])."</code>";
406         }
407         if (ereg("^\\* \\^X-Spam-Status: Yes$",$cond[$i])) {
408             $s.=_("procmail_crit_5");
409         }
410         if (ereg("^\\* \\^Delivered-To:\\.\\*(.*)$",$cond[$i],$t)) {
411             $s.=_("procmail_crit_6")."&nbsp;&nbsp;<code>".str_replace("\\","",$t[1])."</code>";
412         }
413         $s.="<br>\n";
414     }
415     if (count($cond)) {
416         $s.="</small>";
417     }
418     $s.="--&gt; ";
419     // Action :
420     switch ($rule["type"]) {
421     case 1:
422         $t=$rule["rule"][count($rule["rule"])-2];
423         $s.=_("Move the message to this folder")." &nbsp; <code>INBOX".substr($t,0,strlen($t)-1)."</code>";
424         break;
425     case 2:
426         $s.=_("Filter the message through SpamAssassin");
427         break;
428     case 3:
429         $s.=_("Discard the message (for good !)");
430         break;
431     case 4:
432         $t=$rule["rule"][count($rule["rule"])-2];
433         $s.=_("Forward the mail to")." &nbsp; <code>".substr($t,15)."</code>";   
434         break;
435     case 5:
436         $s.=_("Auto-reply");
437         break;
438     }
439     return $s;
440 }
441
442
443 } // CLASS
444
445 /*
446
447 Procmail sample rules :
448
449 # PROCMAILRC HEADING
450 VERBOSE=no
451 MAILDIR=$HOME/Maildir/
452 DEFAULT=$HOME/Maildir/
453
454 # RULETYPE 1 Filtrage sur l'expéditeur du mail
455 :0
456 * ^From.*www-data@sinerj.org
457 .Globenet.No-Log/
458
459 # RULETYPE 2 Filtrage sur le destinataire du mail
460 :0
461 * ^TO_frnog@frnog.org
462 .Listes.frnog/
463
464 # RULETYPE 3 Filtrage sur un List-Id
465 :0
466 * List-Id: <interne_lafil.org@lafil.org>
467 .Listes.interne_lafil/
468
469 # RULETYPE 4 Filtrage sur un List-Post
470 :0
471 * List-Post: <mailto:rv-sources@rezo.net>
472 .Listes.voltaire/
473
474 # RULETYPE 5 Filtrage sur l'expéditeur ET le destinataire
<