#!/usr/bin/perl
# Copyright 1999-2015. Parallels IP Holdings GmbH. All Rights Reserved.
package QmailAgent;

use MailAccount;
use HelpFuncs;
use Logging;
use Mbox2Mdir;

use File::Copy;
use constant QMAIL_PATH => '/var/qmail/';
#use constant QMAIL_PATH => 'C:/qmail/';


sub new {
  my $self = { };
  bless($self);

  return $self;
}

sub get_installed {
  my $assign = QmailAgent::QMAIL_PATH . "users/assign";
  if( -e $assign ){ return 1; }
  return 0;
}

sub get_id_string{
  return 'qmail';
}

sub get_display_name{
  return 'qmail';
}

sub can_backup_accounts{
 return 1;
}

sub can_check_account{
 return 0;
}

sub has_account{
  my ($self, $name) = @_;
  return 0;
}

sub backup_accounts{
 my ( $self, $accounts ) = @_;

 my %pwds = load_passwdords();

 my $assign = QmailAgent::QMAIL_PATH . "users/assign";
 Logging::debug( "Read qmail assign file $assign" );
 open(ASSIGN, "< $assign");
 while(<ASSIGN>){
   chomp;
   push @lines, $_;
 }
 close(ASSIGN);

 foreach my $line (@lines){
    my @fields = split(":", $line);
    next unless defined $fields[4];
    my @parts = split("/", $fields[4]);
    if(defined($parts[5])){
      my $address = $fields[0];
      if( $address =~ /^(.?)[0-9]{1,}-(.*)/s ) { $address = $2; }
      else{ $address = ''; }
      my $accountname = $parts[5] . '@' . $parts[4];
      if( $accounts->add_account( $parts[4], $accountname, $pwds{$fields[4]} || '' ) ) {
        my $res = $self->parse_dot_qmail_file( $fields[4] );
        if ( defined $res->{maildir} ) { $accounts->set_account_maildir( $accountname, $fields[4] . $res->{maildir} ); }
        else{ $accounts->set_account_postbox( $accountname, 0 ); }
        if( defined $res->{redirect} ){
           $accounts->set_account_redirect_satus( $accountname, 1 );
           foreach my $redir(@{$res->{redirect}}) {
	        $accounts->set_account_redirect( $accountname, $redir );
           }
        }
        $accounts->set_account_quota( $accountname, $res->{quota} ) if defined $res->{quota};
      }
    }
  }
}

sub isReserved{
 my $dir = $_[0];
 return 1 if $dir eq '.' ;
 return 1 if $dir eq '..';
 return 1 if $dir eq 'new';
 return 1 if $dir eq 'cur';
 return 1 if $dir eq 'tmp';
 return 1 if $dir eq 'tmp';
 return 1 if $dir eq 'courierimapkeywords';
 return 0;

}

sub backupFolderMsgs{
  my( $dumpproc, $dumpdata, $backupFolder, $maildir, $imapFolder, $cnt, $flags ) = @_;
 Logging::debug( "Backup messages from dir $maildir" );
 $imapFolder =~ s/\./\//sg;
 opendir( DH, $maildir );
 my $dir;
  while( ( $dir = readdir( DH ) ) ){
    if( not isReserved( $dir ) ){
      $$cnt++;
      Logging::debug( "backup mail message $$cnt $maildir/$dir"  );
      #print "Found file $imapFolder/$dir\r\n";
      my $msgFile = "$backupFolder/Message$$cnt.msg";
      my $msgFlags = undef;
      if( $dir =~ m/(.)+?(\:2,)(.)+?$/sg ){
        $msgFlags = $3;
#      	HelpFuncs::log_admin( "Convert flags  of '$dir' to $3" );
      }
      if( copy( "$maildir/$dir", $msgFile ) ){
	      &$dumpproc( $dumpdata, $msgFile, $imapFolder, $msgFlags );
      }
      else{ HelpFuns::log_error( "Cannot copy '$maildir/$dir' to $msgFile. The message wil be lost!" ); }
    }
  }
  closedir( DH );
}

sub backupFolder{
  my( $dumpproc, $dumpdata, $backupFolder, $maildir, $imapFolder, $cnt, $checkmaildir ) = @_;
  if( $checkmaildir and not (-e "$maildir/maildirfolder") ){
  	Logging::debug( "The path '$maildir' does not contain 'maildirfolder'. Skipped." );
        return;
  }
  Logging::debug( "Backup content of mail dir $maildir" );
  if( -e "$maildir/new" ) { backupFolderMsgs( $dumpproc, $dumpdata, $backupFolder, "$maildir/new", $imapFolder, $cnt, '' ); }
  if( -e "$maildir/cur" ) { backupFolderMsgs( $dumpproc, $dumpdata, $backupFolder, "$maildir/cur", $imapFolder, $cnt, 'S' ); }

  #backup child dir
  my $dir;
  opendir( DH, $maildir );
  while( ($dir = readdir(DH)) ){
    if( not isReserved( $dir )  ){
      if( -d "$maildir/$dir" ){
        backupFolder( $dumpproc, $dumpdata, $backupFolder, "$maildir/$dir", "$imapFolder$dir", $cnt, 1 );
      }
    }
  }
  closedir( DH );
}

sub backupMailContent{
  my( $self, $dumpproc, $dumpdata, $backupFolder, $account ) = @_;
  my $maildir = ${$account}{maildir};
  my $username = ${$account}{name};
  my $cnt = 0;
  if( -e $maildir ){
     Logging::debug( "Backup content of $username $maildir" );
     if( $maildir =~ m/(.*)(\/$)/so ) {
        chop $maildir;
     	backupFolder( $dumpproc, $dumpdata, $backupFolder, $maildir, "INBOX", \$cnt, 0 );
     }
     else {
     		Logging::debug( "Found mailbox format. Convert to temp dir $maildir" );
                my $tempdir = HelpFuncs::getUniqueDir( $backupFolder, "tmp" );
                mkdir $tempdir, 0777 or HelpFuncs::dieWithError( "Cannot make dir $tempdir" );
                Mbox2Mdir::convert( $maildir, $tempdir );
                Logging::debug( "Mailbox converted." );
                backupFolder( $dumpproc, $dumpdata, $backupFolder, $tempdir, "INBOX", \$cnt, 0 );
                Logging::debug( "Mailbox dumped." );
                chdir $backupFolder;
                HelpFuncs::deleteFolder( $tempdir );
     }
  }
  else{
	  Logging::debug( "Cannot backup content of $username. Mail dir is not exists. $maildir" );
  }
  Logging::debug( "Found $cnt messages for user $username" );
}

sub get_rcpthosts {
  my $self = shift;
  open(RCPTHOSTS, '<'. QmailAgent::QMAIL_PATH . 'control/rcpthosts') or  return(undef, 0, "Unable to open rcpthosts file.");
  my @results;
  while (<RCPTHOSTS>) {
    chomp;
    push(@results, $_);
  }
  close(RCPTHOSTS);
  return @results;
}


sub get_virtualdomains {
  my $self = shift;
  open(VDOMS, '<'.  QmailAgent::QMAIL_PATH . 'control/virtualdomains') or return(undef, 0, "Unable to open virtualdomains file.");

  my @results;
  while (<VDOMS>) {
    chomp;
    my ($domain, $user) = split(':');
    push(@results, { domain => $domain, user => $user } );
  }
  close(VDOMS);
  return @results;
}

sub get_info_from_assign {
  my ($self, $assign) = @_;
  my (@lines, @results);

  my %pwds = load_passwdords();

  $assign ||= QmailAgent::QMAIL_PATH . "users/assign";
  open(ASSIGN, "< $assign");
  while(<ASSIGN>){
    chomp;
    push @lines, $_;
  }
  close(ASSIGN);

  foreach my $line (@lines){
    my @fields = split(":", $line);
    next unless defined $fields[4];
    my @parts = split("/", $fields[4]);
    if(defined($parts[5])){
      my $address = $fields[0];
      if( $address =~ /^(.?)[0-9]{1,}-(.*)/s ) { $address = $2; }
      else{ $address = ''; }
      push(@results, { domain => $parts[4], mailname => $parts[5], directory => $fields[4], address => $address, pwd => $pwds{$fields[4]} || '' } );
    }
  }
  return @results;
}

sub parse_dot_qmail_file {
  my ($self, $directory) = @_;
  my (@lines, %results);
  %results = ( redirect => undef, maildir => undef, quota => undef);
  my $res = \%results;

  my $dotQmail = $directory."/.qmail";
  if( -e $dotQmail) {
        Logging::debug( "Parse qmail user config $dotQmail" );
	open( DOTQMAIL, "< $dotQmail" );
	while(<DOTQMAIL>) {
	    chomp;
	    push @lines, $_;
	}
	close(DOTQMAIL);

	foreach my $line(@lines) {
	    if ($line=~/^\&(.*)/) {
	      push @{$res->{redirect}}, $1;
              Logging::debug( "Add redirect:$1" );
	}
	if ($line=~/^[\/\.](.*)/) {
	      $res->{maildir} = $1;
	      Logging::debug( "Set mail dir to:$1" );
	    }
	}
  }
  $dotQmail = $directory."/mbox.quota";
  if( -e $dotQmail ){
        Logging::debug( "Parse qmail quota $dotQmail" );
	open( DOTQMAIL, "< $dotQmail" );
        my $line = <DOTQMAIL>;
        chomp ($line );
        $res->{quota} = $line;
        close(DOTQMAIL);
        Logging::debug( "Set quota to:" . $res->{quota} );
  }
  return $res;
}


sub load_passwdords {
  my ($self, $passwd_file) = @_;
  $passwd_file ||= QmailAgent::QMAIL_PATH . "users/poppasswd";
  Logging::debug( "Parse password file $passwd_file" );
  my %result;
  open(PASSWD, "< $passwd_file");
  while(<PASSWD>) {
    chomp;
    my @fields = split(":");
    $result{$fields[3]} = $fields[1];
  }
  close(PASSWD);
  return %result;
}

sub get_passwd_by_dir {
  my ($self, $directory, $passwd_file) = @_;
  $passwd_file ||= QmailAgent::QMAIL_PATH . "users/poppasswd";

  my $result;

  open(PASSWD, "< $passwd_file");
  while(<PASSWD>) {
    chomp;
    my @fields = split(":");
    if($fields[3] eq $directory) {
      $result = $fields[1];
    }
  }
  close(PASSWD);

  return $result;
}

1;