1#!/usr/bin/perl
2
3require '/var/www/cgi-bin/auth.pl';
4
5my $version="0.61i";
6my $adminuid="admin";
7my $adminpass="secret";
8$LDAP_SERVER='imap1';
9$LDAP_BASEDN='o=your org,c=ca';
10my $maildomain="toshiba.ca";
11my $vacationfile="/var/imap/procmail/vacationmsg";
12my $replyfile="/var/imap/procmail/reply";
13my $vacationdb="/var/imap/procmail/vacationdb";
14my $rulefile="/var/imap/procmail/procmailrc";
15my $rejectfile="/var/imap/procmail/rejectfile";
16my $header="X-Customfilter:";
17
18
19sub updateprocmail {
20        my ($filterval,$uid) =@_;
21	my (@mbxlist,$rulesyes,$vacationyes,$usereject);
22%fields=(
23	"subject",'^Subject:',
24	"to2",'(^Cc:|^CC:|^To:|^TO:|^Sender:)',
25	"to",'^TO_',
26	"contain",'* ',
27	"not contain",'* !',
28	"from",'^From:',
29	"address","* !^X-Loop: \$CYUSER\@$maildomain\n| \$FORMAIL -A\"X-Loop: \$CYUSER\@$maildomain\" | \$SENDMAIL ",
30	"folder",'| $DELIVERTO $USERINBOX.',
31	"nocopy",':0',
32	"copy",':0 ic',
33	"reply",':0 hc',
34	"vacation",':0 Whc: locfile'
35	);
36
37$copybit=1;
38$sizebit=2;
39$searchbit=4;
40$keepbit=8;
41$regexbit=128;
42	my %matchtype=(
43		"0","allof",
44		$searchbit,"anyof"
45		);
46
47        my (@lrules)=split('\n',$filterval);
48	my ($keep,$copystat,$procr,$extradefs) = "";
49	my $proc="";
50	my $not="";
51	$copystat="";
52	$procr="";
53	$rulesyes=0;
54	$vacationyes=0;
55	my ($fieldn,$field,$wc);
56	my $regexused;
57	my %vacation;
58	#remove old files;
59	my @remove=glob("$replyfile.*.$uid");
60	while ($_=shift(@remove)) {
61		unlink $_;
62	}
63	unlink "$vacationdb.$uid";
64	unlink "$vacationfile.$uid";
65
66        while (@lrules) {
67		my $tmp='';
68                $line=shift(@lrules);
69                if ($line=~/^ *#vacation&&(.*)&&(.*)&&(.*)&&(.*)/i) {
70			$vacation{'days'}=$1;
71			$vacation{'addresses'}="$2";
72			$vacation{'text'}=$3;
73			$vacation{'mode'}=$4;
74			$vacation{'addresses'}=~s/\\@/\@/g;
75			$vacation{'addresses'}=~s/\"//g;
76			$usevacation=1;
77			next;
78
79		}
80
81		chomp($line);
82		my ($tag,$priority,$ruletype,$from,$to,$subject,$desttype,$dest,$flg,$fieldname,$fieldval,$size) = split("&&",$line);
83		next if !$desttype;
84		next if $tag=~/mode/i;
85		$priority=~s/^ +//;
86		$priority=~s/ +$//;
87		$dest=~s/\r//g;
88		$dest=~s/\\n/\r\n/g;
89		if ($flg=~/copy/i) {
90			$copyflg='copy';
91		}
92		else {
93			$copyflg= ($flg & $copybit);
94		}
95		if ($copyflg) {
96			$copyflg='copy';
97		}
98		else {
99			$copyflg='nocopy';
100		}
101		$matchflg=($flg & $searchbit);
102		$keepflg=($flg & $keepbit);
103		$keepflg=0 if (!$keepflg);
104		$matchflg=0 if (!$matchflg);
105		$sizeflg=($flg & $sizebit);
106		$sizeflg=0 if (!$sizeflg);
107		$regexflg=($flg & $regexbit);
108		$regexused ||=$regexflg;
109		if ($ruletype !~/ENABLED|\d/i) {next};
110	     	if ($desttype=~/folder/i) {
111			next if !$dest;
112			$dest=~s/^INBOX.INBOX/INBOX/;
113			if (($dest =~s/^INBOX\.(.+)/$1/)||($alt_namespace)) {
114				$msgdest=$dest;
115			}
116			else   {
117				$msgdest="$dest";
118			}
119			# check if folder is in an addtional namespace
120			foreach $namespace (@namespaces) {
121				if ($dest=~/^$namespace./i) {
122					$msgdest="$dest";
123					last; # stop checking
124				}
125			}
126		}
127		elsif ($desttype=~/discard/) {
128			$msgdest="/dev/null";
129		}
130		elsif ($desttype=~/address/i) {
131		    if ($dest =~/\w+\@\w+\.\w+/) {
132			$msgdest=$dest;
133		    }
134		    else {
135		    	next;
136		    }
137			next if !$dest;
138
139		}
140
141		else {$msgdest='';}
142		$rulesyes=1;
143
144		$fieldn='0';
145		$field='';
146		$not='';
147
148		if ($to) {
149
150			$not="!" if $to=~s/^\s*!//;
151			$to=".*$to.*";
152			$field.=$not.$fields{'contain'}.$fields{'to'}."$to\n";
153			$fieldn++;
154		}
155		$not='';
156		if ($from) {
157			$not="!" if $from=~s/^\s*!//;
158			$from=".*$from.*";
159			$field.=$not.$fields{'contain'}.$fields{'from'}."$from\n";
160			$fieldn++;
161		}
162		$not='';
163		if ($subject) {
164			$not="!" if $subject=~s/^\s*!//;
165			$subject=".*$subject.*";
166			$field.=$not.$fields{'contain'}.$fields{'subject'}."$subject\n";
167			$fieldn++;
168
169		}
170		$not='';
171		if ($size) {
172		    	$contains='< ';
173		    	$contains='> ' if $sizeflg;
174			$not="!" if $size=~s/^\s*!//;
175			$size=~/([0-9]+)/;
176			$kb='';
177			$size=$1;
178			$size='' if !$size;
179			$field.=$not.$contains.$size."$kb\n";
180			$fieldn++;
181		}
182
183		$not='';
184		if ($fieldname && $fieldval) {
185			$not="!" if $fieldval=~s/^\s*!//;
186			$fieldval=".*$fieldval.*";
187			$field.=$not.$fields{'contain'}."^".$fieldname.": "."$fieldval\n";
188			$fieldn++;
189
190		}
191
192
193		if (!($to || $from || $subject || $size || $fieldname || $fieldval ) && $desttype ne 'custom') {
194			$tmp=''; # for now
195			$copystat='';
196		}
197		elsif ($desttype=~/reject/) {
198			$msgdest="* !^X-Loop: $uid\@$maildomain\n* !^FROM_DAEMON\n";
199			$msgdest.="| (\$FORMAIL -r -I\"Precedeence: junk\" -A\"";
200			$msgdest.="X-Loop: $uid\@$maildomain\";/bin/cat $rejectfile; /bin/echo \"-- \";) | \$SENDMAIL ;";
201			$tmp=":0 h"."\n".$field."$msgdest\n\n";
202
203		}
204		elsif ($desttype=~/reply/i) {
205			$msgdest="* !^X-Loop: $uid\@$maildomain\n* !^FROM_DAEMON\n";
206			$msgdest.="| (\$FORMAIL -r -I\"Precedeence: junk\" -A \"";
207			$msgdest.="X-Loop: $uid\@$maildomain\";/bin/cat $replyfile.$priority.$uid ; /bin/echo \"-- \";) | \$SENDMAIL ;";
208			$tmp=$fields{$copyflg}."\n".$field."$msgdest\n\n";
209			open (REP,">$replyfile.$priority.$uid");
210			print REP "$dest\n";
211			close REP;
212			next if !$dest;
213		}
214
215		elsif ($desttype eq 'custom') {
216			$tmp=$dest."\n\n";
217			 next if $tmp!~/^\s*:0/;
218		}
219		else {
220			$tmp=$fields{$copyflg}."\n".$field.$fields{lc($desttype)}."\'$msgdest\'\n\n";
221		}
222		$proc.=$tmp;
223		$change=1;
224	} #while @lrules
225	$vacationyes=1 if ($vacation{'mode'}=~/on|active|yes|1/i);
226	$proch="# Mail rules for user $uid\n# Created by Websieve version $version\n\n";
227
228	$proc=$proch.$proc;
229
230	if($vacation{'mode'}=~/on|active|yes|1/i) {
231		$vacation{'text'}=~s/\\n/\r\n/g;
232		 if ($vacation{'text'}) {
233			$msgdest="* !^X-Loop: $uid\@$maildomain\n* !^FROM_DAEMON\n";
234			$msgdest.="| \$FORMAIL -rD 8192 $vacationdb.$uid\n\n";
235			$msgdest.=":0 ehc\n| (\$FORMAIL -r -I\"Precedence: junk\" -A\"X-Loop: $uid\@$maildomain\" ; /bin/cat $vacationfile.$uid; ) | \$SENDMAIL; ";
236			$proc.=":0 Whc: $vacationdb.$uid.lock"."\n"."$msgdest\n\n";
237			open (VAC,">$vacationfile.$uid");
238			print VAC $vacation{'text'}."\n";
239			close VAC;
240			open (VACDB,">$vacationdb.$uid");
241			close VACDB;
242			$rulesyes=1;
243   		}
244		else {
245			$vacation{'mode'}='off';
246		}
247
248	}
249	else {
250			unlink "$vacationfile.$uid";
251			unlink "$vacationdb.$uid";
252	}
253#	if (!$rulesyes ) {
254#                $proc=$proch;
255#		$rulesyes=1;
256#        }
257
258
259	$change=1;
260	if ($rulesyes) {
261#		print "proc=\n$proc\npseudo=\n$pseudo\n";
262		open (OUT,">$rulefile.$uid");
263		print OUT "$proc\n";
264		close OUT;
265	       return;
266        } # if rulesyes
267	else {
268		unlink "$rulefile.$uid";
269	}
270
271}
272sub parseinput {
273	while (<>) {
274	  print $_;
275	  if (/^$header +(\w+) (\S+)/) {
276		  	($uid, $adminsecret)=($1,$2);
277			last;
278	  }
279
280	}
281	return $uid;
282}
283
284#main
285
286$uid=&parseinput;
287$uid= $ARGV[0] if $ARGV[0];
288$ld=&auth_connect($adminuid,$adminpass);
289$dn=&auth_getdn($ld,$uid);
290$rules=&auth_getatt($ld,$dn,'matchingrules');
291&updateprocmail($rules,$uid) if $rules;
292
293