#!/usr/bin/perl 

########## Confixx(R) 3.0 Professional ############
####### Copyright SWsoft, Inc. 2004-2005 ##########
#### http://www.sw-soft.com - info@sw-soft.com ####

BEGIN {

  use POSIX;
  use lib;
  use lib POSIX::getcwd.'/'.substr($0,0,rindex($0,'/'));
  use lib POSIX::getcwd;
  use lib POSIX::getcwd.'/../subs';
  use lib POSIX::getcwd.'/admin/subs';
  use lib substr($0,0,rindex($0,'/'));
  
  push @INC,($realBase.'/../subs',$realBase.'/admin/subs');

}

use locale;
use DBI;
use DBD::mysql;
##use DBD::Pg;## mysql only !!!
use File::Basename;
use constant;
use File::Temp;
use File::Find;

use Cwd qw(abs_path);

use strict;
#no strict "vars";

use lib_module_common;

#===================================================

my ($sql,$sth,@row,%uids,$uid,$account,$ptrAccs,$maxUid,%repl,$cnt,$ptrUid,$npp,$i,$ptrUids);
my( $dbh );

&initConfig();

unless ($dbh = DBI->connect($db_address, $dbUser, $dbPw)) {
  die("Couldn't connect to SQL-server: $DBI::errstr\n");
}

print "Serach matching of uids ...\n";

if($dns_server == 2 || $mail_server == 2){
  $ptrUids = {};
}else{
#
# primary server
#
  $ptrUids = \%uids;
}
$sql = "select uid, kunde as account from kunden";
$maxUid = &fillUids($ptrUids,$sql,$maxUid);

#
# bug #32189 uid of ftp account is same as uid of user
#

#$sql = "select uid, account from ftp";
#$maxUid = &fillUids($ptrUids,$sql,$maxUid);

#
# end bug $32189
#

if($mail_pop3Server eq 'localhost'){
#
# pop accounts on localhost
#
  $ptrUids = \%uids;
}else{
  $ptrUids = {};
}

$sql = "select uid, account from pop3";
$maxUid = &fillUids($ptrUids,$sql,$maxUid);


$npp=0;

while (($uid,$ptrAccs)=each(%uids)){
  $cnt = scalar(@{$ptrAccs});
  for ($i=1; $i<$cnt; $i++){
    $account = $ptrAccs->[$i];
    $maxUid = &getMaxUID($maxUid);
    push @{$repl{$account}}, $maxUid;
    push @{$repl{$account}}, $uid;
    $npp++;
  }
}

if ($npp){
  print "$npp matching(s) found\n";
}else{
  print "O.K. Matching of uids is not found.\n";
  exit 0;
}

my ($cmd,$retcode,$newUID,$oldUID);
while (($account,$ptrUid)=each(%repl)){
  ($newUID,$oldUID) = @{$ptrUid};
  if ($account=~/\d+p\d+$/){
    $sql = "update pop3 set uid=$newUID where account='$account'";
  }elsif($account=~/\d+f\d+$/){
    $sql = "update ftp set uid=$newUID where account='$account'";
  }else{
    $sql = "update kunden set uid=$newUID where kunde='$account'";
  }
  $dbh->do($sql) or
    &executeError($sql,$DBI::errstr);
}

#============= update passwd/shadow ====================================
print "launch updatescript for update /etc/passwd\n";

$cmd = "$installDir/confixx_updatescript.pl -dbg -fs -sp";
$retcode = system($cmd);
if($retcode){
  $retcode>>=8;
  warn ("Error run command: $cmd\nerror code: $retcode\n");
}
#============= end update passwd/shadow ================================

print "change owner's uid ...\n";

my($path,$kunde);

while (($account,$ptrUid)=each(%repl)){

  ($newUID,$oldUID) = @{$ptrUid};

  $path='';
  
  if($account=~/\d+f\d+$/){

	print "$account: $oldUID -> $newUID\n";
  
    $sql = "select kunde,pfad from ftp where account='$account'";
    $sth = $dbh->prepare($sql);
    if ($sth->execute){
      if(($kunde,$path) = $sth->fetchrow){
		$path = "$user_homeDir/$kunde/html/$path";
      }
      $sth->finish;
    }

	delete ($repl{$account});  ## already prepared

  }
  if($path && -d $path){
    print "\t$path ...\n";
    find ( \&main::mapUid, $path );
  }

}

while (($account,$ptrUid)=each(%repl)){
  ($newUID,$oldUID) = @{$ptrUid};

  print "$account: $oldUID -> $newUID\n";

  $path='';

  if ($account=~/\d+p\d+$/){
    $path = &prepPop($account);
  }else{
    $path = "$user_homeDir/$account";
  }
  if($path && -d $path){
    print "\t$path ...\n";
    find ( \&main::mapUid, $path );
  }
}

print "Changing of uids successfully complete.\n";

exit 0;

sub prepPop{
  my($account)=@_;
  my($path,$dir,$file);

  if($mta eq "qmail"){
    $dir = "$pop_homeDir/$account";
    if(-d $dir){
      chown($newUID,$gidpop,$dir) or 
		warn "Error: chown dir '$dir' ($newUID.$gidpop) : $!\n";
    }
    if($maildrop eq "HOMEDIR/Mailbox"){
	  $file="$dir/$mailBoxName";
	  if(-f $file){
		chown($newUID, $gidpop, $file) or 
	  	  warn "Error: chown file '$file' ($newUID.$gidpop): $!\n";
	  }else{
	    warn ("Warning: file '$file' is not found\n");
	  }
    }elsif($maildrop eq "HOMEDIR/Maildir/"){
	  $path = "$dir/$mailBoxName";
    }elsif($maildrop eq "/var/spool/mail/USER"){
	  $file = "$mailSpool/$account";
	  if(-f $file){
	    chown($newUID, $gidpop, $file) or warn "Error: chown file '$file' ($newUID.$gidpop): $!\n";
	  }else{
	    warn ("Warning: file '$file' is not found\n");
	  }
    }
  }
  if(($mail_realHome == 1) && ($pop_homeDir ne "") && (-d $pop_homeDir)){
    $path = "$pop_homeDir/$account";
  }
  if((($mta eq 'sendmail') || ($mta eq 'postfix')) && (($mailSpool ne '') && (-d $mailSpool))){
     foreach $file ("$mailSpool/$account", "$mailSpool/.$account.pop", 
		    "$mailSpool/.$account.cache", "$mailSpool/$account.lock"){
       if(-f $file){
	 chown($newUID,0,$file) or
	   warn("Error: chown file '$file' ($newUID.0): $!\n");
       }
     }
  }
  if($path && !(-d $path)){
    warn("Warning: dir '$dir' is not found\n");
    $path='';
  }
  return $path;
}

sub mapUid{
  my($uid,$gid)=(stat($File::Find::name))[4,5];
  if (($uid == $oldUID) && ($uid!=$newUID)){

    $uid = $newUID;
		$gid = $newUID if ( $gid == $giduser || $gid == $uid );

    chown ($uid,$gid,$File::Find::name);
  }
}

sub getMaxUID {
  my($uid)=@_;
  $uid++;
  while( getpwuid($uid) ){
    $uid++;
  }
  return $uid;
}

sub fillUids {
  my($ptrUids,$sql,$maxUid)=@_;
  $maxUid = $min_uid unless $maxUid;
  my ($sth,$uid,$account);
  $sth = $dbh->prepare($sql) or
    &prepareError($sql,$DBI::errstr); 

  $sth->execute() or 
    &executeError($sql,$DBI::errstr);

  while (($uid,$account) = $sth->fetchrow){
    push @{$ptrUids->{$uid}},$account;
    $maxUid = $uid if ($maxUid< $uid);
  }

  $sth->finish;
  return $maxUid;
}

sub prepareError {
  my ($sql,$err)= @_;
  die("Couldn't prepare sql: $sql\n$err\n");
}

sub executeError {
  my ($sql,$err)= @_;
  die("Couldn't execute sql: $sql\n$err\n");
}

