#!/usr/bin/perl

#
# agent for reading/writing pam_mount.conf.xml config.xml file
#

use lib "/usr/lib/YaST2/agents_non_y2";
use ycp;
use strict;
use XML::LibXML;
use Data::Dumper;

# map with whole config file contents
my $pam_mount;

# path to current config file (global, initialized on read)
my $pam_mount_file;

while (<STDIN>)
{
    my ($command, $path, $argument) = ycp::ParseCommand ($_);

    y2debug ("command: $command, path: $path");

    if ($command eq "Read")
    {
	if ($path eq "." && $pam_mount) {
	    y2milestone ("pam_mount already parsed");
	    ycp::Return ("true");
	}
	elsif ($path eq "." || $path eq ".force") {

	    # read given file, store its contents in global $pam_mount structure
	    my %retmap	= ();
	    $pam_mount_file	= $argument;
	    $pam_mount_file	= "/etc/security/pam_mount.conf.xml" if ! $argument;
	    if (-e $pam_mount_file) {

		my $parser	= new XML::LibXML;
		$pam_mount	= $parser->parse_file ($pam_mount_file);

		if ($pam_mount) {
		    ycp::Return ("true");
		}
		else {
		    ycp::Return ("false");
		}
	    }
	    else {
		y2error ("file $pam_mount_file does not exist!");
		ycp::Return ("false");
	    }
	}
	elsif ($path eq ".get") {

	    if (!$argument->{"element"}) {
		y2error ("element name not specified");
		ycp::Return (undef);
	    }
	    else {
		my @retlist	= ();
		my $el_name	= $argument->{"element"} || "";

		my $nodeList	= $pam_mount->getElementsByTagName ($el_name);
		for (my $i=1;$i<= $nodeList->size();$i++) {
		    my $element = $nodeList -> get_node ($i);
		    my $element_map	= {};
		    foreach my $attr ($element->attributes ()) {
			my $nn	= $attr->nodeName;
			my $val	= $attr->getValue ();
			if ($nn && $val) {
			    $element_map->{$nn}	= $val;
			}
		    }
		    push @retlist, $element_map if ($element_map);
		}
		ycp::Return (\@retlist, 1);
	    }
	}
	else {
	    y2error ("wrong command ($command)");
	    ycp::Return ("false");
	}
    }
    elsif ($command eq "Write")
    {
	# write the changes back to the file
	if ($path eq ".")
	{
	    y2milestone ("writing to $pam_mount_file");

	    my $o	= open (OUT, "> $pam_mount_file");
	    if (!defined $o) {
		y2error ("$pam_mount_file cannot be opened for writing!");
		close OUT;
		ycp::Return ("false");
	    }
	    else {
		print OUT $pam_mount->toString ();
		close OUT;
		ycp::Return ("true");
	    }
	}
	# change the value of an atrribute for given element
	# SCR::Write (.pam_mount.modify_attr, $[
	#	"element"	: "mntoptions",
	#	"attr"		: "require",
	#	"value"		: "nosuid"
	# ]);
	elsif ($path eq ".modify_attr") {
	    if (!defined $argument || ref ($argument) ne "HASH") {
		y2error ("argument not present or not a map");
		ycp::Return ("false");
	    }
	    else {
		my $el_name	= $argument->{"element"} || "";
		my $attr_name	= $argument->{"attr"} || "";
		my $value	= $argument->{"value"} || "";

		my $nodeList	= $pam_mount->getElementsByTagName ($el_name);
		for (my $i=1;$i<= $nodeList->size();$i++) {
		    my $element = $nodeList -> get_node ($i);


		    if ($element->hasAttribute($attr_name)) {
			my $attr	= $element -> getAttribute ($attr_name);
			y2internal ("attribute '$attr_name': $attr");
			# change the value of an attribute
			$element->setAttribute ($attr, $value);
		    }
		}
		ycp::Return ("true");
	    }
	}
	# create new element under root node
	# e.g. <volume user="user" fstype="civfs"/> would be added by
	# SCR::Write (.pam_mount.add, $[
	#	"element"   	: "volume",
	#	"attrmap"       : $[
	#		"user"      : "hh",
	#		"fstype"    : "cifs"
	#	],
	#	"newline"	: true
	# ]);
	# FIXME currently only attributes, no values
	# FIXME no new line when new item is added...?
	elsif ($path eq ".add") {
	    if (!defined $argument || ref ($argument) ne "HASH") {
		y2error ("argument not present or not a map");
		ycp::Return ("false");
	    }
	    elsif (!$argument->{"element"}) {
		y2error ("element name not specified");
		ycp::Return ("false");
	    }
	    else {
		my $el_name	= $argument->{"element"} || "";
		my $attr_map	= $argument->{"attrmap"};

		my $new_element = XML::LibXML::Element->new ($el_name);
		while (my ($name, $val) = each %$attr_map) {
		    $new_element->setAttribute ($name, $val);
		}
		my $root	= $pam_mount->documentElement();

		$root->appendChild ($new_element);

		if ($argument->{"newline"}) {
		    $root->appendTextNode ("\n\n");
		}

		ycp::Return ("true");
	    }
	}
	# delete all elemets with given criterias
	# e.g. delete all "volume" elements with attribute fstype="civfs":
	# SCR::Write (.pam_mount.delete, $[
	#	"element"   	: "volume",
	#	"attrmap"       : $[
	#		"fstype"    : "cifs"
	#	]
	# ]);
	elsif ($path eq ".delete") {
	    if (!defined $argument || ref ($argument) ne "HASH") {
		y2error ("argument not present or not a map");
		ycp::Return ("false");
	    }
	    elsif (!$argument->{"element"}) {
		y2error ("element name not specified");
		ycp::Return ("false");
	    }
	    else {
		my $el_name	= $argument->{"element"} || "";
		my $attr_map	= $argument->{"attrmap"};

		my $root	= $pam_mount->documentElement();

		my $nodeList	= $pam_mount->getElementsByTagName ($el_name);
		for (my $i=1;$i<= $nodeList->size();$i++) {

		    my $element = $nodeList -> get_node ($i);
		    my $delete	= 1;
		    # if attributes are present, they specify the elements that
		    # should be deleted
		    while (my ($name, $val) = each %$attr_map) {
			if (!$element->hasAttribute($name)) {
			    y2debug ("attribute $name not present");
			    $delete	= 0;
			}
			elsif ($element->getAttribute ($name) ne $val) {
			    y2debug ("attrbute $name has not the value $val");
			    $delete	= 0;
			}
		    }

		    if ($delete) {
			$root->removeChild ($element);
		    }
		}

		ycp::Return ("true");
	    }
	}
	else {
	    y2error ("wrong command ($command)");
	    ycp::Return ("false");
	}
    }
    elsif ($command eq "result")
    {
	exit;
    }
    else
    {
	y2error ("wrong command ($command)");
	ycp::Return("wrong command $command");
    }
}

# end
