#!/usr/bin/perl -w
# Websieve Cyrus Mail Account Management Tool by Alain Turbide
#
$version="0.63a";
use CGI qw(:standard :html3);
use CGI::Carp qw(fatalsToBrowser set_message);
#predeclare variables from websieve.conf
use vars qw($sieveport $imapport $defaultscript $allowadvanced $header1);
use vars qw($maildomain $mailhostappend $problem_email @namespaces $includepublic);
use vars qw($usereply $usereject $useacl $usediscard $usevariablefield);
use vars qw($useregex $usevacation $usereply $shortacl $usemulti $usematches);
use vars qw($usesearchflg $usecustom $keepredirect $quotemailbox $tb $cb $bg);
use vars qw($showmenu $showhome $showserver $nobyline $expires $OLDMODIFY);
use vars qw($LOGOUTURL $HOMEURL $HELPURL $VIEWRULESURL $SETVACATIONURL);
use vars qw($SETACLURL $ADDRULEURL $SETPASSWORDURL $ADVANCEDURL $ADMINMENUURL);
use vars qw($FORWARDALLURL $useforwardall $IMAPERROR $SIEVEERROR $imap);
use vars qw($server_hosts $useserverselect $useimapSSL $usesieveSSL);
use vars qw($returntoview $usesize $err @list %vacation %modevals @serverlist);
use vars qw($uid $res $scriptname $scriptdef $pseudo $mode $sieve);
use vars qw($imapserver $pass $op $msgdest $namespace $regexflg $regexbit);
use vars qw($sizeflg $copyflg $copybit $searchbit $tmp $matchflg $version);
use vars qw($sizebit $change $line $script $oldscript $oldmode $rules);
use vars qw($useauth %scripts $rulelist $rulesorig $delimiter $skey);
use vars qw($useservercookie $alt_namespace $vacation_prelude $userc4 $maxrules);
use vars qw($useldapextras $gomodifyit $ldappassattr $LDAP_SERVER);
use vars qw($LDAP_BASEDN $ENCRYPT_PASS $selectbyacl $partition);
use vars qw($keepbit $keepflg $ismanager $cyrusadminuid $unixhiersep);
use vars qw($sendcmd $touser $fromuser $useprocmail );
$unixhiersep="\." if !$unixhiersep;
if( $useldapextras ) {
use vars qw($NEWUSERURL $NEWGROUPURL $LDAPSEARCHURL $manageruid);
use vars qw(%ldapdefgroupatts %ldapdefpersonatts @ldappersonatts);
use vars qw($ldapmemberatt $ldapgroup_ou $ldapperson_ou $mgrrecmail);
use vars qw(%donotdisplay $suggestpass $allowchghost $mailhostatt);
}
#default to using RC4 encryption for cookies of $userc4 not defined
$userc4=1 if !defined $userc4;
$maxrules=400;
BEGIN {
sub handle_errors {
my $msg =shift;
if ($msg=~/login|unknown/i) {
&incorrect_login;
}
else {
print"
Received a program error!
Error: $msg";
}
}
set_message(\&handle_errors);
$program_url= url(-absolute=>1) if !$program_url;
require '/usr/local/etc/websieve/funclib.pl';
require '/usr/local/etc/websieve/websieve.conf';
# get the list of available imap servers
@serverlist=keys %server_hosts;
if ($useauth) { require '/usr/local/etc/websieve/auth.pl';}
if ($useldapextras) {
require '/usr/local/etc/websieve/ldapextras.conf';
require '/usr/local/etc/websieve/ldapextras.pl';
}
}
if ($useprocmail) {
$allowadvanced=0;
$useregex=0;
$usesearchflg=0;
$usemulti=0;
}
$remote_host=remote_host();
if (!$skey) {
print header,"
Variable \$skey in websieve.conf NOT set! You MUST set this variable to a random string of characters for encryption of Cookie data" ;
exit;
}
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$skey=$yday.$skey.$yday;
$session_exp='1800' if !$session_exp;
$notflghash='';
$copybit=1;
$sizebit=2;
$searchbit=4;
$keepbit=8;
$regexbit=128;
$error='';
$sencode_params='';
%modevals = (
"on","Yes",
"off","No");
$op='' if !$op;
if (param('op')) {
if (param('op') eq 'logout' || param('op') eq 'login') {
$auth_params{'uid'}='clear';
$auth_params{'pass'}='clear';
$encode_params=&encode_list(%auth_params);
$encode_params=&Encrypt($encode_params,$skey) if !$userc4;
$encode_params=&encrypt_rc4($skey,$encode_params) if $userc4;
$encode_params=&encode_base64($encode_params) if $userc4;
$auth_cookie=cookie(-name => 'websieve',
-value=>$encode_params,
-path=>"$program_url",
-expires => 'now');
print header(-cookie=> $auth_cookie);
param('op','');
print hidden('op');
&web_authenticate;
&byline;
&closeimap;
&closesieve;
exit;
}
}
$gotcookie='';
$encode_params=cookie('websieve');
if (!$encode_params) {
$encode_params=param('s') if param('s');
}
if (!$encode_params && !param('login') )
{
print header;
&web_authenticate;
&byline;
exit;
} else {
if (param('login')) {
$uid = param('login');
$pass = param('password');
}
else {
$gotcookie=1;
$encode_params=&Decrypt($encode_params,$skey) if !$userc4;
$encode_params=&decode_base64($encode_params) if $userc4;
$encode_params=&encrypt_rc4($skey,$encode_params) if $userc4;
%auth_params=&decode_list($encode_params);
$uid=$auth_params{'uid'};
$pass=$auth_params{'pass'};
if ($uid eq 'clear') {
print header;
&web_authenticate;
&byline;
exit;
}
my $authhost=$auth_params{'remotehost'} if $auth_params{'remotehost'};
my $etime=$auth_params{'exp'} if $auth_params{'exp'};
if ((time - $etime) > $session_exp) {
print header,"
Your Session has expired!
";
&web_authenticate;
&byline;
exit;
}
if ($authhost && $authhost ne $remote_host) {
print header,"
Remote host does not match Session host!
";
&web_authenticate;
&byline;
exit;
}
} # else param('login')
if (param('viewscript')) {
$viewscript=param('viewscript');
$gotcookie='';
}
else {
$viewscript=$auth_params{'script'};
}
param('viewscript',$viewscript);
if (param('server') ) {
$userserver=param('server');
$gotcookie='';
}
else {
$userserver=$auth_params{'server'} if $auth_params{'server'};
}
if ($useauth && !$userserver) {
# get imapserver address from auth database
$userserver=&auth_getuserserver;
}
$userserver=&getserverdata($userserver);
$auth_params{'uid'}=$uid;
$auth_params{'pass'}=$pass;
$auth_params{'server'}=$userserver;
$auth_params{'script'}=$viewscript;
$auth_params{'remotehost'}=$remote_host;
$auth_params{'exp'}=time;
$encode_params=&encode_list(%auth_params);
$encode_params=&Encrypt($encode_params,$skey) if !$userc4;
$encode_params=&encrypt_rc4($skey,$encode_params) if $userc4;
$encode_params=&encode_base64($encode_params) if $userc4;
$auth_cookie=cookie(-name => 'websieve',
-value=>$encode_params,
-path=>"$program_url",
-expires => $expires);
if ($uid ne "" && $pass ne "")
{
if (&bind < 0)
{
print header;
&incorrect_login;
}
} else {
print header;
&incorrect_login;
}
if (!$allowadvanced) {
foreach $advanceduser (@advanceduser) {
$allowadvanced=1 if $uid=~/^$advanceduser/i;
}
}
$sencode_params=&URLEncode($encode_params) if $useservercookie;
# $sencode_params=&URLEncode($encode_params) if !$gotcookie;
&addservercookie($sencode_params) if !$gotcookie;
# $useservercookie=1 if !$gotcookie;
if (!$gotcookie && !$useservercookie) {
print header(-cookie=> $auth_cookie);
}
else {
print header;
}
$ismanager=1 if (($uid eq $manageruid) || ($uid eq $cyrusadminuid));
undef $gotcookie;
&modify_screen;
&closeimap;
&closesieve;
print hr if $op ;
&byline if ($op ne 'ldapsearch');
exit;
}
sub addservercookie {
my ($cookie) =@_;
$VIEWRULESURL=~s/>/&s=$cookie>/;
$FORWARDALLURL=~s/>/&s=$cookie>/;
$SETVACATIONURL=~s/>/&s=$cookie>/;
$SETACLURL=~s/>/&s=$cookie>/;
$ADDRULEURL=~s/>/&s=$cookie>/;
$SETPASSWORDURL=~s/>/&s=$cookie>/;
$ADVANCEDURL=~s/>/&s=$cookie>/;
$ADMINMENUURL=~s/>/&s=$cookie>/;
}
sub initscripts {
my ($scriptname,$scriptdef,$mode,$viewscript,$scriptsave,$deletescript,$scriptlist);
my (%scripts)=@_;
$scriptdef=$scripts{'scriptdef'};
$mode=$scripts{'mode'};
$scriptlist=$scripts{'scriptlist'};
$viewscript=$scripts{'viewscript'};
$scriptname=$viewscript;
$deletescript='';
my @scriptlist;
@scriptlist=split (/ /,$scriptlist);
if ($scripts{'active'} && $viewscript eq $scripts{'active'}) {
$scriptdef='on';
}
$scriptdef='on' if !$usemulti;
param("lastviewscr",$viewscript);
print hidden("lastviewscr",$viewscript);
param("viewscript",$viewscript);
param("scriptname",$scriptname);
param("deletescript",$deletescript);
if ($op eq 'advanced') {
print "";
print "
";
print "NOTE: You will lose ALL changes made to a script in advanced mode if you switch back to basic mode." if ($mode eq 'advanced' && $op eq 'advanced');
}
sub printpass {
print "
";
print "
Change Password","
";
print "
";
print "
User ID:
",textfield('authuser'),"
\n" if ($ismanager && $useauth);
print "
New Password:
",password_field('pass1'),"
\n";
print "
New Password (again):
",password_field('pass2'),"
\n";
print "
\n";
print "
";
}
sub modifyacl {
my $mbx="";
my $err="";
return if (defined param('Select'));
return if (defined param('Save Changes'));
return if (param('action') && param('action') eq 'confirmmbxdel');
$mbx=param("mbx") if defined param("mbx");
my $partition = param('partition') if param('partition');
my $acl='';
my $generalrights='';
$generalrights=param('rights') if defined param('rights');
$acl=join('',param('acl')) if defined param("acl");
$acl=$generalrights.$acl;
my ($useracl)="";
$useracl=param('acluser') if defined param('acluser');
my $maxquota;
$maxquota=param('aclmaxquota') if defined param('aclmaxquota');
my ($newmbx)="";
$newmbx=param('newmbx') if defined param('newmbx');
$mbx=~s/^ +//g;
$mbx=~s/ +$//g;
my $mbxorig=$mbx;
$userspace=1;
# check if folder is in an additional namespace
if (param('Select Folder')) {
my $selected=param('selectedmbx');
$selected=~/^\[([^\]^\[]*)\]/;
$selected=$1;
param('mbx',$selected.'*');
return;
}
if (param('Select Server')) {
my $imapserver=param('server');
return;
}
if (param('Up One Level')) {
my $selected=param('selectedmbx');
$selected=~/^\[(.*?)\]/;
$selected=$1;
$selected=~s/$unixhiersep?[^.]+$//;
param('mbx',$selected.'*');
param('selectedmbx','');
return;
}
foreach $namespace (@namespaces) {
if ($newmbx) {
if ($newmbx=~/^$namespace./i) {
$mbx="$newmbx";
$userspace=0;
last; # stop checking
}
}
elsif ($mbx=~/^$namespace./i) {
$userspace=0;
last; # stop checking
}
}
if ($userspace) {
if ($alt_namespace) {
if ($mbx) {
$newmbx=$unixhiersep.$newmbx if $newmbx;
}
$mbx="".$mbx.$newmbx."";
}
else {
## $mbx=~s/^INBOX/user$unixhiersep$uid/i;
$newmbx=$unixhiersep.$newmbx if $newmbx;
$mbx="".$mbx.$newmbx."";
}
}
if ($ismanager && !$newmbx) {
$mbx=$mbxorig;
}
elsif ($ismanager) {
$mbx=$newmbx;
$mbx=~s/^$unixhiersep//;
}
my $change;
#print br,"mbx=$mbx, newmbx=$newmbx",br;return;
if ($newmbx && param('Create Mailbox')) {
$err=&createmailfolder($mbx,$partition);
if ($err) {
print hr,"Createmailbox Error: $err ";
return;
}
else {
$change=1 ;
if ($ismanager) {
param('mbx',$mbx);
print hidden('mbx');
}
}
}
if (!$mbx || !(( $acl && $useracl) || $maxquota)) {
return;
}
if (param('Set Acl')) {
$mbx="\"$mbx\"" if ($quotemailbox==1);
if ( $mbx && !&listmailbox($mbx)) {
$err="Mailbox does not exist!";
}
else {
$err=&setacl($mbx,$useracl,$acl);
$change=1;
}
}
if ($maxquota && param('Set Quota')) {
$err=&setquota($mbx,$maxquota);
$change=1;
}
if ($err) {
print hr,"Error modifying $mbx, Err: $err\n",br;
return;
}
print hr,"Mailbox modification successful.. " if $change;
return;
}
#### View ACL's
sub viewacl
{
my ($tmp,@acl);
my (%aclhash) =(
"l"=>"[l]ook",
"r"=>"[r]ead",
"s"=>"[s]een",
"w"=>"[w]rite",
"i"=>"[i]nsert",
"p"=>"[p]ost",
"c"=>"[c]reate",
"d"=>"[d]elete",
"a"=>"[a]dmin",
#"none"=>"No Access"
);
my $mbx;
$mbx=param('mbx') if param('mbx');
if ($ismanager) {
#$mbx="INBOX*" if !$mbx;
$mbx="user".$unixhiersep.$uid.$unixhiersep."*" if !$mbx;
@mailboxes=&listmailbox($mbx) ;
}
if (param('Delete This Mailbox') && param('delmailbox')) {
param('Delete This Mailbox','');
param('action','confirmmbxdel');
&confirmmbxdelete;
print hidden('action');
print end_form;
print end_html;
exit;
}
my $subtext="Folder";
$subtext="Mailbox" if $ismanager;
my (%rightshash)=(
"lrs"=>"Read (lrs)",
"lrsp"=>"Post (lrsp)",
"lrswipcd"=>"Write (lrswipcd)",
"lrsip"=>"Append (lrsip)",
"lrswipcda"=>"All (lrswipcda)",
"lrswipd"=>"Write-no create(lrswipd)",
"none"=>"Remove access (none)"
);
my (@rights)=("lrs","lrsp","lrswipcd","lrsip","lrswipcda","lrswipd","none");
my (@acls)=("l","r","s","w","i","p","c","d","a","none");
print "",hr;
print "
";
my (@tmpmbx,$eachmbx,$eachfolder);
my ($user,$useracl);
print "
ACL View for user mailbox","
";
print "
";
print "
";
if ($shortacl ) {
print "
[$subtext]-->UserID [acl]
";
}
else
{
print "
Folder Name
UserID [acl]
";
}
@tmpmbx=@mailboxes;
undef @acl;
my (@tmp,$acl_tmp,$user_tmp);
while (@tmpmbx) {
$eachmbx=shift(@tmpmbx);
next if ($eachmbx!~/\S/);
$eachfolder="$eachmbx";
# check if folder is in an additional namespace
foreach $namespace (@namespaces) {
if ($eachmbx=~/^$namespace./i) {
$eachfolder="$eachmbx";
last; # stop checking
}
}
$eachfolder="\"$eachfolder\"" if ($quotemailbox==1);
@tmpacl=&getacl($eachfolder) if $eachfolder;
# print "tmpacl=$eachfolder==@tmpacl ";
$tmp=join(' ',@tmpacl);
#remove stray mailbox names that have spaces
$tmp=~s/^.*?" *//;
@tmp=split(/ /,$tmp);
# print "tmp2acl=$tmp ";
$tmp='';
while (@tmp) {
$user_tmp=shift(@tmp);
next if !$user_tmp;
$acl_tmp="[".shift(@tmp)."]" if @tmp;
$tmp.=", " if $tmp;
$tmp.="$user_tmp=$acl_tmp";
}
if ($shortacl) {
if (!$tmp) {
$tmp='';
}
$tmp="[$eachmbx]---->".$tmp;
push (@aclview,$tmp);
}
else {
print "
";
if ($ismanager) {
my @imapquota=&getquota($mbx) if ($havequota || !$useprocmail);
param('aclmaxquota','');
param('aclmaxquota',$imapquota[2]);
print "
<$cb>Disk Quota Limit (KB):
";
print textfield('aclmaxquota',$imapquota[2],20,40);
print " Disk Quota Used (KB): ".$imapquota[1]." ".submit("Set Quota")."
";
}
sub getuserinfo {
my ($res,$script,$mode,$pseudo,$oldmode);
my (@tmpboxes,@tmprules,@tmpscr);
my (@scriptlist,$scriptlist,$scriptname,$scriptdef);
undef @rules;
undef @mailboxes;
undef @quota;
undef %vacation;
undef %scripts;
#creates global variables $mode,@rules,@mailboxes,@quota and %vacation;
# get quota
@quota=&getquota("INBOX") if ($havequota || !$useprocmail);
if ($IMAPERROR !~ /no errors/i && !$ismanager && $IMAPERROR) {
$error=$IMAPERROR;
&closeimap;
&closesieve;
&incorrect_login;
exit;
}
#print "quota=@quota";
# get mailboxes
@tmpboxes=&listmailbox("*") if (!$ismanager);
# remove "user.userid" prefix
#place empty element in @mailboxes for display purposes
push (@mailboxes,' ');
while (@tmpboxes) {
$tmpline=shift(@tmpboxes);
chomp($tmpline);
$tmpline=~s/\r//g;
if ($alt_namespace) {
$tmpline=~s/^ *user$unixhiersep$uid$unixhiersep* * /INBOX$unixhiersep/i;
}
else {
$tmpline=~s/^ *user$unixhiersep$uid$unixhiersep* *//i;
}
#thiswill be set true if "anyone" identifier has any privs
# for the folder defined by $tmpline
my $public=1;
#this will be set true if this user has admin privs for
#this folder
my $ownedbyuser = 0;
#Display all folders if Manager is user
$includepublic=1 if $ismanager;
if ($selectbyacl) {
my @tmpacl = &getacl($tmpline);
#following 5 lines fix returned acl values when folders contain
# spaces when using IMAP::Admin
$tmp=join(' ',@tmpacl);
#remove stray mailbox names that have spaces
$tmp=~s/^.*?" *//;
@acl=split(/ /,$tmp);
$tmp='';
while(@acl) {
my $line=shift(@acl);
$public = 1 if ($line=~ /anyone/i);
if ($line=~/$uid/i) {
my $useracl=shift(@acl);
$ownedbyuser=1 if ($useracl=~/a/i);
}
}
$tmpline = "" if (($public)&&(!$ownedbyuser)&&(!$includepublic));
}
else {
if (($tmpline!~/^INBOX|$uid/i) && (!$includepublic)) {
$tmpline="";
}
}
push (@mailboxes,$tmpline) if ($tmpline=~/\S/);
}
# get mailboxes from other namespaces
foreach $namespace(@namespaces) {
push (@mailboxes,&listmailbox("$namespace.*"));
}
#get scriptlists
if (!$useprocmail) {
&opensieve($uid,$pass,$sieveport,$imapserver) if (!$sieve);
if (!$sieve) {
print start_html(-title=>'Error login in to Sieve Server',-BGCOLOR=>'red'),
h2("Error login in to Sieve Server: $imapserver "),
"There is a problem accessing the Sieve Server, click HERE and try again.\n";
&closesieve;
&closeimap;
exit;
}
@scriptlist=&listscripts;
while (@scriptlist) {
$_=shift(@scriptlist);
if (/\*|ACTIVE/) {
$defaultscript=$_;
$defaultscript=~s/\*| *ACTIVE//g;
$_="".$defaultscript."*";
$scripts{'active'}=$defaultscript;
}
if ($scriptlist) {$scriptlist.=', ';}
$scriptlist.=$_;
}
if (!param('viewscript')) {
$scriptname=$defaultscript;
$viewscript=$defaultscript;
$scriptdef='off';
}
else {
$scriptname=param('scriptname');
$viewscript=param('viewscript');
$scriptdef=param('scriptdef');
}
} # if not useprocmail
# get sieve scripts
if (!$useprocmail) {
$pseudo=&getscript($viewscript."_pseudo");
$script=&getscript($viewscript);
$script=$script.$pseudo;
}
else {
$script=&auth_getattrib($matchingrules);
}
if ( $SIEVEERROR && $SIEVEERROR !~ /No Error/i && $SIEVEERROR !~ /doesn.t exist/i) {
print "Error: getscript->".$SIEVEERROR." ";
}
#combined script and pseudo files to enable easy compatibility with old method
#of having rules in same file as script
@tmprules=split(/\n/,$script) if ($script);
@tmpscr=grep !/#rule|#mode|#vacation|##pseudo/i,@tmprules;
#remove pseudo rules and CR's from main script
$script=join("\n",@tmpscr);
@tmprules=grep /^ *\#\#pseudo|^ *#rule|^ *#mode|^ *#vacation/i, @tmprules;
$pseudo=join("\n",@tmprules);
while (@tmprules) {
$_=shift(@tmprules);
if (s/^ *#rule&& *//i) {
s/\r//g;
push(@rules,$_);
}
elsif (/^ *#vacation&&(.*)&&(.*)&&(.*)&&(.*)/i) {
$vacation{'days'}=$1;
$vacation{'addresses'}="$2";
$vacation{'text'}=$3;
$vacation{'mode'}=$4;
$vacation{'addresses'}=~s/\\@/\@/g;
$vacation{'addresses'}=~s/\"//g;
}
elsif (/^ *#mode&&(.*)/) {
$mode=$1;
$oldmode=$mode;
}
}
if ( !defined %vacation) {
$vacation{'mode'}='off';
$vacation{'days'}='1';
$vacation{'text'}='On vacation for the next week';
}
if (!$vacation{'addresses'}) {
$vacation{'addresses'}="$uid\@$maildomain $uid\@$mailhostappend";
}
if ($allowadvanced && param('mode') && (param('viewscript') eq param('scriptname'))) {
$mode=param('mode');
}
elsif (!$allowadvanced || !$mode) {
$mode='basic';
}
$scripts{'script'}=$script if $script;
$scripts{'pseudo'}=$pseudo;
$scripts{'mode'}=$mode;
$scripts{'oldmode'}=$oldmode;
$scripts{'scriptname'}=$scriptname;
$scripts{'viewscript'}=$viewscript;
$scripts{'scriptlist'}=$scriptlist;
$scripts{'scriptdef'}=$scriptdef;
$scripts{'deletescript'}=param('deletescript');
return %scripts;
}
sub printscript {
my ($script)=@_;
param("script",$script);
print "
";
}
# print web form and display all current rules
# also display form to accept a new rule
sub printrules {
# my (@fieldlist)=("subject","from","to");
my (%actions,%contain);
my (@ruletype)=('DISABLED','ENABLED','DELETE','MODIFY');
my (@desttype)=("folder","address");
my ($fieldname,$fieldval,$sdest,$sdest1,$sto,$sfrom,$ssubject,$destt,$sdest2,$sdest3,$check1,$check2,$check3,$check4,$check5,$joinop,$size);
my ($applyall,$searchflg);
my ($sfield,$svalues,$scopyflg,$sregexflg,$sfieldname,$sfieldval,$ssize,$skeepflg);
$ssize=$sfieldname=$sfieldval=$sfrom=$sto=$ssubject=$sdest=$sdest0=$sdest1=$sdest3=$check3=$check4='';
$sflg=$ssizeflg=0;
push (@desttype,' ');
# retrieve rules string from global hash %record where key is matchingrules
#convert rules string to an array
$sdest=$svalues=$sfield;
$scopyflg='';
$sregexflg='';
$skeepflg='';
my ($sdestt)='folder';
%actions = (
"folder","File Into",
"address","Forward To",
"reply","Reply with",
"reject","Reject",
"discard","Discard"
);
my (@flgsts)=(0,1);
%notflghash=(
0,"contains",
1,"does not contain",
);
%searchflghash = (
0," all of ",
1," any of "
);
%sizeflghash = (
0," less ",
2," greater "
);
%copyhash = (
'keep',"Keep a copy in your Inbox",
'copy',"Continue checking other rules after applying this rule",
'regex',"Use regular expressions"
);
my ($toggle,$priority,$line,$dest,$field,$flg,$copyflg,$sizeflg,$keepflg);
my ($rulecount)=0;
my ($pcount)=1;
# insert view rules here..
if ($op eq 'viewrules' ) {
print hr,"
";
print "
Viewing Rules for: $uid","
";
print "
";
print "
[Rule#] Priority - Status
Current Rules
";
# only print if viewing...
} # if viewrules
@tmprules=@rules;
$modrule="";
while (@tmprules) {
$line=shift(@tmprules);
chomp($line);
$line=~s/\s*//;
$line=~s/\s$//;
$line=~s/\r//g;
($priority,$ruletype,$from,$to,$subject,$destt,$dest,$flg,$fieldname,$fieldval,$size)=split('&&',$line);
if ((!($from || $to || $subject || $size || ($fieldname&&$fieldval)) || !$ruletype) && !$dest) {
next;
}
#this line to support old version of websieve scripts
if ($flg=~/copy/i) {
$flg=$copybit;
}
$flg=0 if !$flg;
$copyflg= ($flg & $copybit);
$searchflg=($flg & $searchbit);
$searchflg=0 if !$searchflg;
$sizeflg=($flg & $sizebit);
$regexflg=($flg & $regexbit);
$keepflg=($flg & $keepbit);
$priority=$pcount;
$applyall='';
$applyall=1 if (!($to | $from | $subject | $fieldname | $fieldval | $size) && $dest);
# if it is a modify rule then save this rule for modify later
if (($ruletype=~/modify/i || ($applyall && $op eq 'forward' && $destt eq 'address')) && !($sto || $sfrom || $ssubject || $sdest || $ssize)) {
# can use 'DELETE' but data loss in form submit might cause a new rule to be lost if using IE
$ruletype=$OLDMODIFY;
$sto=$to;
$sfrom=$from;
$ssubject=$subject;
$modrule="1";
$spriority=$priority-1;
$sdestt=$destt;
$sdest=$dest;
$scopyflg=$copyflg;
$ssizeflg=$sizeflg;
$skeepflg=$keepflg;
$sflg=$flg;
$sregexflg=$regexflg ;
$ssearchflg=$searchflg;
$sfieldname=$fieldname ;
$sfieldval=$fieldval ;
$ssize=$size;
# save values for modify later
}
param("rules.priority.$rulecount","$priority");
param("rules.ruletype.$rulecount",$ruletype);
param("rules.searchflg.$rulecount",$searchflg);
if ($op eq 'forward' && $ruletype=~/DELETE/i) {
print hidden("rules.priority.$rulecount");
print hidden("rules.ruletype.$rulecount");
}
if ($op eq 'viewrules' ) {
# only print if viewer
print "
";
} # if viewrules
if (($op eq 'addrule' || $modrule) && ($op ne 'forward')) {
$modrule="";
#### New Rule Entry
my ($wild)="Hint: Use * or ? for wildcards To invert a rule use ! as the first character of your search string" ;
print hr,"
";
my @checked;
my @checkvalues=("copy","keep");
push @checkvalues,"regex" if $useregex;
if ($scopyflg) {
push @checked,"copy";
}
if ($skeepflg) {
push @checked,"keep";
}
if ($sregexflg) {
push @checked,"regex";
}
param("rules.copy.$rulecount",@checked);
print "
";
print "NOTE: If you want to keep a copy of messages that ",
"you are forwarding, don't use this screen. Create a",
" new filter rule to redirect your mail instead.";
print "
";
}
param('rulescount',$rulecount);
print hidden('rulescount');
}
sub printinfo {
my $percent='0.00';
$percent= sprintf "%2.2d",$quota[1]/$quota[2]*100 if ($quota[2]);
print "
\n";
print "
Server: $imapserver
Userid: $uid
";
print "
Used Quota: ";
if ($percent ne "" && ($havequota || !$useprocmail)) {
print "[$quota[1] kbytes used / $quota[2] kbytes available.($percent\% usage)]
';
return;
}
sub incorrect_login
{
print start_html(-title=>'Login Error!',-BGCOLOR=>'yellow'),
h2('Login Error'),
"There was an error in loging you in to the server. Please ",
"click HERE and try again.\n";
if ($error !~ /sieve/i) {
print "
System Error: $error";
print " User server=$userserver ";
}
else {
print "
Wrong Password! ";
}
print end_html;
exit;
}
sub web_authenticate
{
my @slist=@serverlist;
my %serverdisplay;
while ($_=shift @slist) {
$serverdisplay{$_}=$server_hosts{$_}[0] if $_;
}
print start_html(-title=>$header1,-BGCOLOR=>$bg),
"
",h1($header1),
"For Problems with this service, please email $problem_email ",$HOMEURL," ",
start_form,"
Your \"Login\" is the same as the part of your e-mail address that goes before the \@ symbol.
";
print end_form;
}
sub bind
{
&openimap($uid,$pass,$imapserver,$imapport,$useimapSSL,$unixhiersep);
if (!$imap || $IMAPERROR=~/NO login/i) {
$error=$IMAPERROR." ";
&closeimap;
return -1; # Return Failure
}
if (!$useprocmail) {
&opensieve($uid,$pass,$sieveport,$imapserver,$usesieveSSL);
if (!$sieve || $SIEVEERROR) {
$error.=$SIEVEERROR." ";
&closeimap;
&closesieve;
return -1;
}
}
return 0; # Return Success
}
sub modify_screen
{
# Print WWW Header
my $header2="Mail Server: $userserver" if $showserver;
$header2=" " if !$header2;
my $err;
print start_html(-title=>"$header1 for '$uid' on $userserver",-BGCOLOR=>$bg, -LINK=>"black", -VLINK=>"black"),
"
",h2("$header1 $header2"),"
";
%scripts=&getuserinfo;
$mode=$scripts{'mode'};
$op='';
$op=param('op') if param('op');
if ($mode =~ /advanced/i && !$op) {
$op = 'viewrules';
}
if ($showmenu||$showhome) {
print "
",tablebutton($HOMEURL);
print "
",tablebutton($LOGOUTURL),"
";
if ($useldapextras) {
print "
",tablebutton($LDAPSEARCHURL),"
";
if ($ismanager) {
print "
",tablebutton($NEWUSERURL),"
";
print "
",tablebutton($NEWGROUPURL),"
";
$showmenu = $mgrrecmail;
}
}
}
print "
";
print "
";
print "
",tablebutton($SETPASSWORDURL),"
" if $useauth;
print "
",tablebutton($SETVACATIONURL),"
" if ($usevacation && $mode ne 'advanced');
print "
",tablebutton($FORWARDALLURL),"
" if ($useforwardall && $mode ne 'advanced');
print "
",tablebutton($VIEWRULESURL),"
";
print "
",tablebutton($ADDRULEURL),"
" if ($mode ne 'advanced');
if ($useacl && !$ismanager) {
print "
",tablebutton($SETACLURL),"
" ;
}
elsif ($ismanager) {
print "
",tablebutton($ADMINMENUURL),"
";
}
print "
",tablebutton($ADVANCEDURL),"
" if ($allowadvanced || $usemulti);
print "
";
&printinfo;
# Draw up the Web Form
print start_form(-action=>$program_url);
$gomodifyit = 'yes';
print hidden('s',$sencode_params) if $useservercookie;
print "
\n";
if (!$useprocmail) {
param("vacationdays",$vacation{'days'});
print "
Repeat Days:
",textfield("vacationdays",$vacation{'days'},2,"")," (How many days before sending vacation notice again in reply to same user.)
\n";
param("vacaddresses",$tmpvacadd);
print "
Vacation Addresses:
",textarea("vacaddresses",$tmpvacadd,2,50,"","wrap=virtual")," (Your email addresses that you receive mail on)
\n";
} # if !$useprocmail
print "
";
}
sub createmailfolder {
my ($mbx,$partition)=@_;
my @list=&listmailbox($mbx);
my $err;
if (!(@list)) {
$err=&createmailbox($mbx,$partition);
}
else {
$err="$mbx already exists!";
}
if ($err) {
return $err;
}
print "$mbx created successfully. ";
return "";
}
#############################################
sub encode_list {
return undef unless @_;
my $out='';
foreach (@_) {
$out .= 'G'.pack('c', 65 + int(rand(6))) if $out;
$out .= reverse(uc(unpack('H'.(length)*2, $_))) if $_;
}
return $out.'='; # looks like some recognizable format
}
sub decode_list {
return undef unless $_[0];
my @out;
foreach ( split(/G[A-F]/, substr($_[0],0,-1)) ) {
push @out, pack('H'.(length), scalar reverse $_);
}
return @out;
}
##############################################
# Encryption routines for cookie
# from EZCrypt v2.0 (c) 2000 Croesus Design and Promotion
# Developed by Jason C. Fleming
# Base64 routines Copyright 1995-1997 Gisle Aas.
# This library is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
sub Encrypt {
my ($plaintext,$key) = @_; #get message and key from user
if (!$key) {
print "\$skey not set!!! ";
}
my ($cr,$index,$char,$key_char,$encrypted);
$plaintext = &rot13($plaintext); #garble source by swapping alphabet
$cr = '``'; #carriage return character unlikely to occur in text
$plaintext =~ s/[\n\f\t]//g; #remove whitespace chars
$plaintext =~ s/[\r]/$cr/g; #swap cr with our token
while ( length($key) < length($plaintext) ) { $key .= $key } #pad private key
$key=substr($key,0,length($plaintext)); #set key to same length as source
$index=0;
while ($index < length($plaintext)) { #go through each character and swap bits with key
$char = substr($plaintext,$index,1);
$key_char = substr($key,$index,1);
$encrypted .= chr(ord($char) ^ ord($key_char)); #THE MEAT OF THE ENCRYPTION
$index++;
}
$encrypted = encode_base64($encrypted); #convert xor encrypted string into printable blocks
$encrypted; #send the cyphertext back to user
}
sub Decrypt {
my ($encrypted, $key) = @_;
$encrypted = decode_base64($encrypted); #convert encrypted blocks into xor code
my ($cr,$index,$char,$key_char,$decrypted);
while ( length($key) < length($encrypted) ) { $key .= $key } #pad key
$key=substr($key,0,length($encrypted)); #set key to same length as source
$index=0;
while( $index < length($encrypted) ) { #swap bits with key
$char = substr($encrypted,$index,1);
$key_char = substr($key,$index,1);
$decrypted .= chr(ord($char) ^ ord($key_char)); #THE MEAT OF THE ENCRYPTION
$index++;
}
$cr = '``';
$decrypted =~ s/$cr/\r/g;#replace carriage returns
my $list=&rot13( $decrypted ); #unswap alphabet
}
sub rot13{ #swaps low letters (a-m) with high letters (n-z) and visa versa
my $source = shift (@_);
$source =~ tr /[a-m][n-z]/[n-z][a-m]/; #performs rot13 swapping (lc)
$source =~ tr /[A-M][N-Z]/[N-Z][A-M]/;#performs rot13 swapping (caps)
$source = reverse($source);
$source;
}
sub encode_base64 {
my $res = "";
my $eol = $_[1];
$eol = "\n" unless defined $eol;
pos($_[0]) = 0; # ensure start at the beginning
while ($_[0] =~ /(.{1,45})/gs) {
$res .= substr(pack('u', $1), 1);
chop($res);
}
$res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs
# fix padding at the end
my $padding = (3 - length($_[0]) % 3) % 3;
$res =~ s/.{$padding}$/'=' x $padding/e if $padding;
# break encoded string into lines of no more than 76 characters each
if (length $eol) {
$res =~ s/(.{1,76})/$1$eol/g;
}
$res;
}
sub decode_base64{
local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]
my $str = shift;
my $res = "";
$str =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
#if (length($str) % 4) {die "Base64 decoder requires string length to be a multiple of 4"}
$str =~ s/=+$//; # remove padding
$str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
while ($str =~ /(.{1,60})/gs) {
my $len = chr(32 + length($1)*3/4); # compute length byte
$res .= unpack("u", $len . $1 ); # uudecode
}
$res;
}
# end of encrypt routines
### only used in debugging #####
sub savetext {
my ($filename,$filetext)=@_;
open OUT,">/tmp/$filename";
print OUT $filetext;
close OUT;
}
sub URLEncode
{
my($url)=@_;
my(@characters)=split(/(\%[0-9a-fA-F]{2})/,$url);
foreach(@characters)
{
if ( /\%[0-9a-fA-F]{2}/ ) # Escaped character set ...
{
unless ( /(20|7f|[0189a-fA-F][0-9a-fA-F])/i
|| /2[2356fF]|3[a-fA-F]|40/i )
{
s/\%([2-7][0-9a-fA-F])/sprintf "%c",hex($1)/e;
}
}
else # Other stuff
{
s/([\000-\040\177-\377\074\076\042\+])
/sprintf "%%%02x",unpack("C",$1)/egx;
}
}
return join("",@characters);
}
# RC4 perl encryption routine by Andy Welter May 2001
# Encrypt a buffer at a type. Encryption is a stateful
# process, so we use the "@state" global variable to track
# the state.
sub rc4 {
my ($buf) = @_;
my ($ebuf, $char);
my $x=0;
my $y=0;
for(unpack('C*',$buf)) {
$x++;
$y=($state[$x%=256]+$y)%256;
@state[$x,$y]=@state[$y,$x];
$char= pack (C,
$_^=$state[ ($state[$x] + $state[$y]) %256 ]);
$ebuf= $ebuf . $char;
};
return $ebuf;
};
sub prepkey {
#
# Prepare the encryption key
#
my ($key)=@_;
my @hexkey=unpack('C*',$key);
my ($x, $y)=("0","0");
my @t;
my @state;
for(@t=@state=0..255){
$y=($hexkey[$_%@hexkey]+$state[$x=$_]+$y)%256;
@state[$x,$y]=@state[$y,$x];
#&swap;
}
return @state;
};
sub encrypt_rc4 {
my ($key,$buf)=@_;
local @state=&prepkey($key);
return &rc4($buf);
};
sub tablebutton
{
my ($text) = @_;
return "
".$text."
\n";
}
# this function will take a user's mail server host name and retrieve all port
# and host data to connect to it if not default.
sub getserverdata {
my ($userserver)=@_;
$imapserver=$userserver if $userserver;
if (defined $server_hosts{$userserver}) {
# $serverdisplay=$server_hosts{$userserver}[0] if $server_hosts{$userserver}[0];
$imapport=$server_hosts{$userserver}[1] if $server_hosts{$userserver}[1];
$sieveport=$server_hosts{$userserver}[2] if $server_hosts{$userserver}[2];
$maildomain=$server_hosts{$userserver}[3] if $server_hosts{$userserver}[3];
$mailhostappend=$server_hosts{$userserver}[4] if $server_hosts{$userserver}[4];
my $sslopts=$server_hosts{$userserver}[5];
if ($sslopts) {
$useimapSSL=1 if ($sslopts=~/imap|both|all|^ssl$/i);
$usesieveSSL=1 if ($sslopts=~/sieve|both|all|^ssl$/i);
}
}
return ($imapserver);
}
sub confirmmbxdelete {
if( !$ismanager ) {
print "Access not allowed ";
return;
}
$mbx=param('delmailbox');
return if !$mbx;
if ($mbx=~/\*/) {
print "Warning! You are attempting a wildcard delete !!! Not allowed! ";
return;
}
param('delmailbox',$mbx);
param( 'action', 'deletembx' );
print hidden('delmailbox');
print hidden('mbx');
print "
Confirm: Really delete $mbx from server $imapserver
";
print "
",submit("Confirm Delete"),"
";
print " If so, press the 'Confirm Delete' button.\n";
print " If not, press the back button in your browser.\n
";
return;
}
sub deleteimapmailbox {
if( !$ismanager ) {
print "Access not allowed ";
return;
}
$mbx=param('delmailbox');
return if !$mbx;
if ($ismanager ) {
my $err = setacl( $mbx ,
$uid,
"lrswipcda"
)." ";
}
$err.= &deletemailbox($mbx);
if ( $err ) {
print hr,"DeleteMailbox Error: imapdelerr $err";
return;
} else {
print "Mailbox: $mbx deleted. ";
}
}
sub mailruleupd {
my ($uid)=@_;
open (MAIL, "|$sendcmd");
print MAIL "From: $fromaddr\n";
print MAIL "To: $toaddr\n";
print MAIL "Subject: Filter activation\n";
print MAIL "X-Customfilter: $uid $adminsecret\n";
print MAIL "\n";
print MAIL "Filter activation message for $uid";
close(MAIL);
}