#!/usr/bin/perl -w
#----------------------------------------------------------------------
#
# copyright (C) Decaux Nicolas Aka 'GawiNDX'
# contributor: Nicolas Decaux <decauxnico@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
#----------------------------------------------------------------------
    package esmith;

    use strict;
	use esmith::db;
    use esmith::config;
    use esmith::ConfigDB;
    use File::Basename;
    use File::Path;
    use File::Temp;
    use File::Copy qw(copy);
	use Switch;
	use List::Util 'first';

	my $config = esmith::ConfigDB->open('') or die "Couldn't open DB\n";
	my $DomainName = $config->get('DomainName')->prop('type');
	
	my $mozus_db = esmith::ConfigDB->open('Mozus') or die "Couldn't open Mozus\n";
	my $tb_product_id = "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
    my $ff_product_id = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
	my $mozus = $mozus_db->get('Mozus');
    my $addons_dir = $mozus->prop('AddonsDir');
	chomp($addons_dir);
    my $sogo_dir = $mozus->prop('SOGo-pluginsDir')."/";
	chomp($sogo_dir);	
	
	#On verifie quelle action doit etre effectuee
	switch ($ARGV[0]){
		case('add_update') 	{if ( !defined($ARGV[2])){&add_update("$ARGV[1]");}else{ &add_update("$ARGV[1]","$ARGV[2]" );} }
		case('delete')		{&delte_mod("$ARGV[1]");}
		case('update_sogo')	{&update_sogo()}
		case('')	{ exit 1;}
		
	}
	1;
	
sub update_sogo
{
	#on va passer en revue tous les module et on mettra a niveau les modules sogo integrator
	#on part du principe que l'on possede la meme clef pour thunderbird et firefox
	my %list_addons = $mozus_db->get('Thunderbird')->props;
	my $addonskey = "";
	my $value = "";
	my @list_sogo;
	#on va remplacer les fichiers 'site.js' et 'extensions.rdf en fonction des parametres de Mozus
	system("/sbin/e-smith/expand-template /opt/mozilla-updates/sogo-templates/site.js");
	system("/sbin/e-smith/expand-template /opt/mozilla-updates/sogo-templates/extensions.rdf");
	system("/sbin/e-smith/expand-template /opt/mozilla-updates/sogo-templates/custom-preferences.js");
	#on recherche tous les modules sogo integrator disponibles
	while (($addonskey,$value) = each(%list_addons)) {
		if ( ($addonskey eq "type") or () or () ) {next;}
		if ( $addonskey =~/sogo-integrator/ ) {
			push(@list_sogo, $addonskey);
		}
	}

	#creation du repertoire temporaire
	my $tmp = File::Spec->tmpdir(); 
	my $tmpdir = $tmp ."/XPI_ADDON";
	my $xmlfile = $tmpdir ."/install.rdf";
	mkpath($tmpdir) or die unless (-d "$tmpdir");
	#On met a jour le nom du module
	foreach my $module (@list_sogo){
		my @value_key = split(";",($mozus_db->get_prop('Thunderbird',"$module")));
		my $module_version = $value_key[4];
		my $xpi = "$value_key[1]";
		#decompression du module. Si il n'existe pas on sort
		if ( -e "$addons_dir$xpi"){
			system("unzip -qqo $addons_dir$xpi -d $tmpdir")
		}else{
			die "Cannot locate $addons_dir$xpi";
		}
		#on met a jour les fichiers pour sogo
		copy "/opt/mozilla-updates/sogo-templates/site.js" , "$tmpdir/defaults/preferences/site.js";
		copy "/opt/mozilla-updates/sogo-templates/extensions.rdf" , "$tmpdir/chrome/content/extensions.rdf";
		copy "/opt/mozilla-updates/sogo-templates/custom-preferences.js" , "$tmpdir/chrome/content/general/custom-preferences.js";
		
		#on met a jour la version du module
		$module_version =~ s/\./,/g;		
		my @version_addon = split("," , $module_version);
		
		if ( scalar(@version_addon) < 4){
			push(@version_addon, 0);
		}
		$version_addon[3]++;
		my $old_version = $module_version;
		$module_version = join(",",@version_addon);
		$module_version =~ s/,/\./g;
		#on met  jour install.rdf pour la nouvelle version
		&modify_sogo_install_version("$xmlfile","$module_version","$old_version" );
		#on met a jour le nom du moule
		my $xpi_name = "sogo-integrator-".$module_version."-".$DomainName."\.xpi";
		#on met a jour les valeurs de la clefs en fonction du nouveau module que l'on va creer
		$value_key[4] = $module_version;
		$value_key[1] = $xpi_name;
		my $value = join(";",@value_key);
		#on recompresse le module en fichier .xpi
		chdir($tmpdir);
		system("zip -qr $addons_dir$xpi_name .");# or die("Cannot create module $xpi_name\n cause : $!\n");
		#on efface les fichier d'origine et on cree les nouveaux liens symbolique
		my @platform = split("@", $value_key[7]);
		my @xpi_file;
		push(@xpi_file, "$addons_dir$xpi");
		foreach my $pform (@platform){
			my $link = $sogo_dir.$pform."/".$xpi_name;
			my $file_link = $addons_dir.$xpi_name;
			unless( -d ( "$sogo_dir$pform" ) ){
				mkpath( "$sogo_dir$pform" ) or die;
			}
			symlink( $file_link , $link ) or die ;
			push(@xpi_file, "$sogo_dir/$pform/$xpi");
		}
		unlink(@xpi_file) or die;
		#maintenant que tout est pret on peut mettre a jour la clef, sous reserve de pouvoir supprimer la precedente
		my $platform = join("@",@platform);
		#on genere un identifiant correspondant aux plateformes compatibles
		my $pform_id = &get_platform_id($value_key[7]);
		(my $key_name = $value_key[3]) =~ s/ //g;
		(my $key_version = $value_key[4]) =~ s/\.//g;
		#on cree le nom de la clef
		$key_name = $key_name."_v".$key_version."_p".$pform_id;
		if ($mozus_db->get_prop_and_delete("Thunderbird", "$module")){
			$mozus_db->set_prop("Thunderbird","$key_name","$value") or die ("Cannot update key for $xpi_name\n");
		}
		if ($mozus_db->get_prop_and_delete("Firefox", "$module")){
			$mozus_db->set_prop("Firefox","$key_name","$value") or die ("Cannot update key for $xpi_name\n");
		}
		system("/sbin/e-smith/expand-template", $sogo_dir."updates\.php");
		rmtree($tmpdir, 0, 0);
	}
	exit(1);
}


sub add_update
{
	#on va ajouter un nouveau module ou mettre a jour un module existant
	my ($xpi,$xpi_new_name) = @_;
	my ($xpi_name,$xpi_path)=fileparse($xpi);
	my $addon_statut = 'disabled';
	if ( defined($xpi_new_name) and ($xpi_new_name ne '' )) {
		#on remplace le module existant avec son nom definitif		
		#copy "$xpi" , "$xpi_path/$xpi_new_name";
		rename($xpi,"$xpi_path/$xpi_new_name");
		$xpi_name = $xpi_new_name;
		$xpi = "$xpi_path/$xpi_name";
	}
	#creation du repertoire temporaire
	my $tmp = File::Spec->tmpdir(); 
    my $tmpdir = $tmp ."/XPI_ADDON";
	mkpath($tmpdir) or die unless (-d "$tmpdir");
    
	#decompression du module. Si il n'existe pas on sort
	if ( -e $xpi){
		system("unzip -qqo $xpi -d $tmpdir")
    }else{
		die "Cannot locate $xpi";
    }
	#on recupere les informations contenues dans le fichier "install.rdf". Le parse est fait manuellement en raison de la mauvaise qualite de la plupart des fichiers.
	my $xmlfile = $tmpdir ."/install.rdf";
    my ($array_product , $array_versions , $addon_full_name , $addon_id_name , $addon_version, $array_platform) = &parse_xpi($xmlfile);
    my @addon_product_id = @$array_product;
    my @addon_product_versions = @$array_versions;
    my @array_platform = @$array_platform;
	my $sogo;
	$sogo = &is_sogo($addon_full_name);
	if ( ( $sogo = &is_sogo($addon_full_name) ) != 0 ) { $addon_statut = 'enabled' } ;
	if ( $sogo == 2){
		my @list_prod = qw (Thunderbird Firefox);
		foreach my $product (@list_prod){
			#le module est 'sogo integrator' on le traite differement
			#on commence par verifier si le module existe deja
			my %list_addons = $mozus_db->get("$product")->props;
			my $addonskey = "";
			my $value = "";
			#on definit la clef que devrait avoir le module si il est deja existant
			my $version_addon = substr($addon_version , 0 , 2);
			my $key_search = "sogo-integrator\@inverse\.ca_v$version_addon";
			#on passe en revue toutes les clefs definit pour savoir si le module existe
			while (($addonskey,$value) = each(%list_addons)) {
				if ( ($addonskey eq "type") or () or () ) {next;}
				if ( $addonskey =~ /$key_search/ ){
					#le module existe deja, on definir sa nouvelle version et modifier les parametres en consequence
					#on compare la version du module existant avec celle du nouveau module
					#mais il faut comparer ce qui est comparable donc on convertit les deux versions sous la meme forme
					my @value_key = split(';',$value);
					my $tmp_vers = $value_key[4];
					$tmp_vers =~ s/\./;/g;
					my @version_key = split(";" , $tmp_vers);
					($tmp_vers = $addon_version) =~ s/\./;/g;
					my @vers_addon = split(';',$tmp_vers);
					my @old_pform_xpi = split("@",$value_key[7]);
					my $old_xpi_name = $value_key[1];
					#on commence par verifier si on est sur la meme version mineure
					if (( $version_key[0] == $vers_addon[0]) and ( $version_key[1] == $vers_addon[1]) and ( $version_key[2] == $vers_addon[2])){
						if ( scalar(@vers_addon) == 3 ){
							push(@vers_addon,'0');
						}
						#le nouveau module est une variant du module existant, on ne fait qu'incrementer sa version de 0.0.0.1
						$vers_addon[3] = ($version_key[3] || 0 ) + 1;
						my $old_addon = "$addons_dir$old_xpi_name";
						#on prepare la liste des fichiers et lien symbolique a supprimer
						my @old_files;
						foreach my $pform (@old_pform_xpi){
							my $old_file = "$sogo_dir$pform/$old_xpi_name";
							if ( ( ( first { /$old_file/ } @old_files ) || '' ) eq ''){
								push(@old_files, $old_file);
							}
						}
						if ( ( ( first { /$old_addon/ } @old_files ) || '' ) eq ''){
								push(@old_files, $old_addon);
						}
						#on supprime les anciens fichiers du module
						foreach my $file (@old_files){
							if (-e $file){ unlink($file) or die "cannot unlink $!"; }
						}
#						unlink(@old_files) or die "cannot unlink $!";
					}
					#on met a jour le parametre de version pour l'incorporer a la clef. On en profite pour supprimer l'ancienne clef
					my $old_addon_version = $addon_version;
					$addon_version = join('.',@vers_addon);
					$mozus_db->get_prop_and_delete("$product","$addonskey");
				}
			}
		}
		if ( scalar(@addon_product_id) == 1){
			@addon_product_id = ("$tb_product_id","$ff_product_id");
			push(@addon_product_versions, $addon_product_versions[0]);
			#on met  jour install.rdf pour la nouvelle version
			&modify_install_rdf_for_firefox("$tmpdir/install.rdf");
		}
		#On met a jour le nom du module
		$xpi_name = "sogo-integrator-".$addon_version."-".$DomainName."\.xpi";
		$addon_statut = "enabled";
		#on remplace les fichiers 'site.js' et 'extensions.rdf en fonction des parametres de Mozus
		#par securite, on fait un expand-template pour etre sur de travailler avec les derniers parametres
		system("/sbin/e-smith/expand-template /opt/mozilla-updates/sogo-templates/site.js");
		system("/sbin/e-smith/expand-template /opt/mozilla-updates/sogo-templates/extensions.rdf");
		system("/sbin/e-smith/expand-template /opt/mozilla-updates/sogo-templates/custom-preferences.js");
		copy "/opt/mozilla-updates/sogo-templates/site.js" , "$tmpdir/defaults/preferences/site.js";
		copy "/opt/mozilla-updates/sogo-templates/extensions.rdf" , "$tmpdir/chrome/content/extensions.rdf";
		copy "/opt/mozilla-updates/sogo-templates/custom-preferences.js" , "$tmpdir/chrome/content/general/custom-preferences.js";
		#on recompresse le module en fichier .xpi
		chdir($tmpdir);
		system("zip -qr $addons_dir$xpi_name .");
		#on efface le fichier d'origine, il n'est plus ncessaire
		unlink($xpi);
    }else{
		#le module n'est pas sogo integrator, on recompose son nom et on verifie si il est deja existant auquel cas on ne fait que le recopier 
		unless ( -e "$addons_dir.$xpi_name" ){
			if (!defined($xpi_new_name)){
				my $platform =join("@",@array_platform);
				$xpi_name = &get_xpi_name("$addon_full_name","$addon_version",&get_platform_id($platform ));
			}
			rename($xpi , $addons_dir.$xpi_name);
		}
    }

    my $count=0;
	my $platform;
	#on va creer le nom de la clef du module pour chaque produit Mozilla associe
    foreach my $product (@addon_product_id){
		my $prod;
		if ( $product eq $tb_product_id ){
			$prod = "Thunderbird";
		}elsif ( $product eq $ff_product_id ){
			$prod = "Firefox";
		}
		my @addon_versions = split("@",$addon_product_versions[$count]);
		$platform = join("@",@array_platform);
		#on genere un identifiant correspondant aux plateformes compatibles
		my $pform_id = &get_platform_id($platform);
		$addon_versions[0] =~ s/\./,/g;
		$addon_versions[1] =~ s/\./,/g;
		(my $key_name = $addon_id_name) =~ s/ //g;
		(my $key_version = $addon_version) =~ s/\.//g;
		#on cree le nom de la clef
		$key_name = $key_name."_v".$key_version."_p".$pform_id;
		my $value = $addon_statut.";".$xpi_name.";".$addon_full_name.";".$addon_id_name.";".$addon_version.";".$addon_versions[0].";".$addon_versions[1].";".$platform;
		#si la clef existe deja on la supprime
		if ( ($mozus_db->get("$prod"))->prop("$key_name") ){
			$mozus_db->get_prop_and_delete("$prod","$key_name");
		}
		#on definit la clef avec les nouveaux parametres
		$mozus_db->set_prop("$prod","$key_name","$value");
		$count++;
    }
	#on cree les liens symboliques en fonction des plateformes compatibles avec le modules
    my @platform = split("@",$platform);
    foreach my $pform (@platform){
		my $link = $sogo_dir.$pform."/".$xpi_name;
		my $file_link = $addons_dir.$xpi_name;
		unless( -d ( "$sogo_dir$pform" ) ){
			mkpath( "$sogo_dir$pform" ) or die;
		}
		symlink( $file_link , $link );
    }
	#si on est face a un module sogo, on met a jour 'updates.php'
    if ($addon_statut eq 'enabled' ){
		system("/sbin/e-smith/expand-template", $sogo_dir."updates\.php");
    }
    
	#on supprime l'arborescence temporaire
	rmtree($tmpdir, 0, 0);
	exit(1);
}

sub modify_install_rdf_for_firefox
{
	my $installfile = $_[0];
	if ( -e "$installfile" ) {
		open ( RDFFILE , "<" , $installfile ) or die "Couldn't open $installfile : $!";
		my @newfile;
		my @lines = <RDFFILE>;
		close (RDFFILE);
		my $count = 0;
		print "@lines\n";
		foreach my $line (@lines){
			if ( index($line, 'Iwquq2') != -1) {
				if ( index($line, 'about=') != -1 ) {
					my $newline = $lines[$count] . $lines[ ( $count +1 ) ] . $lines[ ( $count + 2 ) ] . $lines[ ( $count + 3 ) ];
					$newline =~ s/$tb_product_id/$ff_product_id/g ;
					$newline =~ s/Iwquq2/firefox/g ;
					push(@newfile,$newline);
					push(@newfile,$line);
				}else{
					push(@newfile,$line);
					$line =~ s/Iwquq2/firefox/g ;
					push(@newfile,$line);
				}
			}else{
				push(@newfile,$line);
			}
		$count++;
		}
		open ( RDFFILE , ">" , $installfile ) or die "Couldn't open $installfile : $!";
		print RDFFILE @newfile;
	}
}

sub modify_sogo_install_version
{
	my $xmlfile = $_[0];
	my $new_version = $_[1];
	my $old_version = $_[2];
	$old_version =~ s/,/./g;
	if ( -e "$xmlfile" ){
		open my $info, $xmlfile or die "Could not open $xmlfile: $!";
		my @all_lines = <$info>;
		my @new_xmlfile;
		foreach my $line (@all_lines){
			if ( $line =~ /em:version/ ){
				my $line_mod = $line;
				$line_mod =~ s/$old_version/$new_version/g ;
				push (@new_xmlfile, $line_mod);
			}else{
				push (@new_xmlfile, $line);
			}
		}
		close($info);
		unlink ($xmlfile);
		open(my $newxml,">","$xmlfile");
		foreach my $new_line (@new_xmlfile){
			if ( $new_line eq ''){next;}
			print $newxml "$new_line";
		}
		close($newxml);
	}
}

sub is_sogo
{
	my ($addon) = @_;
	if ( $addon eq 'Inverse SOGo Connector' ){
		return 1;
	}elsif  ( $addon eq 'Inverse SOGo Integrator' ){
		return 2;
	}else{
		return 0;
	}
}

sub get_xpi_name
{
	my ($name,$version,$id_pform) = @_;
	$name =~ s/ //g ;
	my $new_name = $name."_".$version."_".$id_pform.".xpi";
	return $new_name;
}

sub get_platform_id
{
   my $platform = shift;
   my @platform = split("@",$platform);
   my $pformid= 0;
   foreach my $pform (@platform){
	if ($pform eq 'WINNT_x86-msvc'){
		$pformid = $pformid + 8;
	}elsif ($pform eq 'Darwin_x86-gcc3'){
		$pformid = $pformid + 4;
	}elsif ($pform eq 'Linux_x86-gcc3'){
		$pformid = $pformid + 2;
	}elsif ($pform eq 'Linux_x86_64-gcc3'){
		$pformid = $pformid + 1;
	} 
   }
   return $pformid;
}

sub parse_xpi
{
    my $xmlfile = $_[0];
    my $tb_product_id = "3550f703-e582-4d05-9a08-453d09bdfdc6";
    my $ff_product_id = "ec8030f7-c20a-464f-9b0e-13a3a9e97384";
    my @addon_product_id;
    my @array_platform;
    my @addon_product_versions;
    my $addon_min_version;
    my $addon_max_version;
    my $addon_full_name;
    my $addon_id_name;
    my $addon_version;
    my $count = 0;
    if ( -e "$xmlfile" ){
	#Because 'install.rdf' is often malformed xml, we parse them manualy
	open my $info, $xmlfile or die "Could not open $xmlfile: $!";
	my @all_lines = <$info>;
	foreach my $line (@all_lines){
		$count++;
	        if ( $line =~ /em:id/ ){
               	my $element = substr $line,( index($line, 'em:') + 6);
	            $element =~ s/"//g;
        	    $element =~ s/<\/em:id>//g;
				$element =~ s/[\r\n]+//g;	
				if (( $element =~ /$tb_product_id/) or ( $element =~ /$ff_product_id/)){
					push( @addon_product_id,$element);
					push( @addon_product_versions, &get_product_versions($count,@all_lines) );
				}else{
					$addon_id_name = $element;
				}
	        }
        	if ( $line =~ /em:name/ ){
                $addon_full_name = substr $line, index($line, 'em:')+8;
	            $addon_full_name =~ s/"//g;
				$addon_full_name =~ s/<\/em:name>//g;
				$addon_full_name =~ s/[\r\n]+//g;
#			$addon_full_name = substr($addon_full_name ,0, index($addon_full_name, ' ')) if ($addon_full_name =~ / /);
        	}
	        if  ( $line =~ /em:version/ ){
        	    $addon_version = substr $line, index($line, 'em:')+11;
	            $addon_version =~ s/"//g;
				$addon_version =~ s/<\/em:version>//g;
				$addon_version =~ s/[\r\n]+//g;
				$addon_version = substr($addon_version ,0,index($addon_version, ' ')) if ($addon_version =~ / /) ;
        	}
	        if  ( $line =~ /em:targetPlatform/ ){
        	    my $tmp_platform = substr $line, index($line, 'em:')+18;
	            $tmp_platform =~ s/"//g;
				$tmp_platform =~ s/<\/em:targetPlatform>//g;
				$tmp_platform =~ s/[\r\n]+//g;
				$tmp_platform = substr($addon_version ,0,index($addon_version, ' ')) if ($addon_version =~ / /) ;
				push(@array_platform, $tmp_platform);
        	}
	}
	close $info;
	if (scalar(@array_platform) eq '0' ){@array_platform = ("WINNT_x86-msvc","Darwin_x86-gcc3","Linux_x86-gcc3","Linux_x86_64-gcc3")};
	return (\@addon_product_id , \@addon_product_versions , $addon_full_name , $addon_id_name , $addon_version , \@array_platform);

    }
	
}

sub get_product_versions
{
	my $line_number = $_[0];
	my $min_version;
	my $max_version;
	my @parse_line = ("1","2","3","4","5");
	my $lines;
	foreach my $elements (@parse_line){
        	$lines = $_[$line_number + $elements];
		if ( $lines =~ /em:minVersion/ ){
                	$min_version = substr $lines, index($lines, 'em:')+14;
	                $min_version =~ s/"//g;
        	        $min_version =~ s/\/>//g;
        	        $min_version =~ s/<\/em:minVersion>//g;
	        }
        	if ( $lines =~ /em:maxVersion/ ){
                	$max_version = substr $lines, index($lines, 'em:')+14;
	                $max_version =~ s/"//g;
        	        $max_version =~ s/\/>//g;
                	$max_version =~ s/<\/em:maxVersion>//g;
	        }
	}
	my $result = $min_version ."@".$max_version;
	$result =~ s/[\r\n]+//g;
	return $result;

}
