#!/usr/bin/perl 

use Net::DNS;
use Fuse;
use Data::Dumper;
use POSIX qw(ENOENT EISDIR EINVAL);
use Fdns;

use strict;
use warnings;

# (C) Miek Gieben, 2008
# Places under GPL v3

# TODO: filesize is not correct
# Syscalls to be implemented
# - readlink, can we do something nice with this?
#
# write calls:
# would be cool the edit stuff and have it dynamicly added
# to a nameserver....
# not implemented:
# - mknod
# - mkdir
# - rmdir
# - unlink
# - symlink
# - rename
# - link
# - chmod
# - chown
# - truncate
# - utime
# - write
# and a few more that are more obscure
my $DEBUG = 1;

my $res = Net::DNS::Resolver->new(
		recurse => 1,
		debug => 0);
# try to speed it up, at the cost of some robustness
$res->tcp_timeout(10);
$res->udp_timeout(10);
$res->retry(2);

sub e_getattr($) {
	print "e_getattr called ", "@_" , "\n" if $DEBUG;
	my @name = path2dns shift;
	my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
                  $atime,$mtime,$ctime,$blksize,$blocks);

	$dev = $ino = $nlink = 1;
	$mode = 16832;  # 33152  file
	$uid = $gid = 0;
	$rdev = 0;
	$size = 512;
	$atime = $mtime = $ctime = time(); # maybe some nice TTL trick?
	$blksize = 512;
	$blocks = 1;

	# @ treat differently, fake name we introduce in every dir
	if ($name[0] eq "\@") {
	    $mode = 33152;
	    return $dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
                  $atime,$mtime,$ctime,$blksize,$blocks;
	}

	if (dns_soa($res, join ".", @name)) {
	    # directory - we get SOA info back
	    $nlink = 2;
	    $size = 4096;
	    return $dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
                  $atime,$mtime,$ctime,$blksize,$blocks;
	} else {
	    # doesnt exists or other problems...
	    if (!dns($res, join (".", @name), "ANY")) {
		return -ENOENT();
	    }
	    # get the length...
	    $mode = 33152;
	    return $dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
                  $atime,$mtime,$ctime,$blksize,$blocks;
	}
}

sub e_getdir($) {
	print "e_getdir called ", "@_" , "\n" if $DEBUG;
	my @name = path2dns shift;
	my @fnames = dns_zones($res, join ".", @name);
	@fnames, 0;
}

sub e_open($$) {
	print "e_open called ", "@_" , "\n" if $DEBUG;
	my ($path, $flag) = @_;
	return 0;
}

sub e_read($$$) {
        # path, reg, off
	print "e_read called ", "@_" , "\n" if $DEBUG;
	my @name = path2dns shift;
	my ($req, $off) = @_;
	# cms nlnetlabs nl, treat @ different
	if ($name[0] eq "\@") {
		# kill @, as the domain
		shift @name;
		print "@ name: ", "@name", "\n";
	} 
	join  "\n", (dns_read($res, join(".", @name), "ANY"));
}

# some bogus return values
sub e_statfs { 
	print "e_statfs called ", "@_" , "\n" if $DEBUG;
    255, 1, 1, 1, 1, 2;
}

#e_read called /nl/_SOA 4096 0
#print e_read("/nl/atcomputing/cms", 4096, 0);
#print e_read("/nl/nlnetlabs/qubit", 4096, 0);

# If you run the script directly, it will run fusermount, which will in turn
# re-run this script.  Hence the funky semantics. Remove this?
my $mountpoint = shift if @ARGV;
if ( ! -d $mountpoint ) {
    die "Not a directory: $mountpoint";
}

Fuse::main(
	debug => 0,
	mountpoint => $mountpoint,
	getattr  => "main::e_getattr",
	getdir   => "main::e_getdir",
	open     => "main::e_open",
	statfs   => "main::e_statfs",
	read     => "main::e_read",
	threaded => 0
	);

__END__
e_getattr("/");
e_getattr("/nl");
e_getattr("/nl/SOA");
e_getattr("SOA");
e_getattr("/nl/nlnetlabs/SOA");
print e_read("/SOA");
print e_read("/nl/nlnetlabs/SOA");
print e_read("/nl/nlnetlabs/www");
print e_read("/nl/nlnetlabs/jelte");
