#!/usr/bin/perl

use strict;
use Getopt::Long;
use File::Basename;
use Cwd;

=head1 NAME

edg-gridftp-ls - List a file or contents of directory.

=head1 SYNOPSIS

edg-gridftp-ls [B<--proxy>=I<proxy>] [B<--timeout>=I<timeout>] [B<--verbose>] [B<--noauth>] I<URL> 

edg-gridftp-ls B<--usage> 

edg-gridftp-ls B<--help> 

=head1 DESCRIPTION 

B<edg-gridftp-ls> will list (to the standard output) a file or the
contents of a directory for the given URL.  It will return a zero
status on success.  In all other cases, it will return a non-zero
value and print an error message to the standard error.

=head1 OPTIONS

=over 4

=item B<--proxy>=I<proxy>

Set the proxy to use for the GridFTP operation.  If this is unset,
then the underlying GridFTP library will try to find the proxy in the
usual locations.  This is useful if the proxy is in a non-standard
location, or the caller is a daemon which must act on the behalf of
a user. 

=item B<--timeout>=I<timeout>

Set the time (in seconds) within which the listing must complete. If no timeout
is specified a default 120 second timeout will be used. A negative or zero
timeout will report a timeout error before attempting to contact the FTP server.

=item B<--verbose>

If this flag is set, then the listing will include more information
about the status of the file in addition to the filename.

=item B<--noauth>

If this flag is set, then the authentication of the data channel will
be turned off.  It is on by default. 

=item B<--usage>

Short description of the usage of this command is given.

=item B<--help>

A description of the usage of this command and information on all of
the options is given. 

=item I<URL>

URLs of the following formats are accepted: 

ftp://ftp.server.org//absolute/file/name
gsiftp://gridftp.server.org/~/home/relative/name.txt
gridftp://gridftp.server.org/home/relative/name.txt

Note: for the URLs without a tilde, the server configuration
determines whether the filename is absolute or relative.  On servers
which do not restrict users to their home areas, the tilde notation
will not work.

=back

=head1 AUTHOR

Charles Loomis (charles.loomis@cern.ch). Later modifications by
CERN IT-DM/SMD.

=head1 LICENSE

Copyright (c) 2002 by Charles A. Loomis, Jr. and Le Centre National de
la Recherche Scientifique (CNRS).  All rights reserved.

The software was distributed with and is covered by the European
DataGrid License.  A copy of this license can be found in the included
LICENSE file.  This license can also be obtained from
http://www.eu-datagrid.org/license.

The underlying GridFTP library is part of the Globus Toolkit (TM) and
is covered by the Globus Toolkit Public License.  See
http://www.globus.org for more information. 

=cut

# Set the base command name.
my $basecmd = "edg-gridftp-base-ls";

# Set a successful return.
my $exitcode = 0;

# Check that the options are specified correctly. 
my %options;
GetOptions(\%options, 'usage', 'help', 'proxy=s', 'timeout=i', 'verbose', 'noauth') 
    || printUsage(\*STDERR,0);

# If usage or help is specified, print the appropriate thing. 
printUsage(\*STDOUT,0) if ($options{usage});
printUsage(\*STDOUT,1) if ($options{help});

# If the proxy was specified, then check that the file exists and set
# the appropriate environmental variable. 
if ($options{proxy}) {
    my $f = $options{proxy};
    printUsage(\*STDERR,0,"Given proxy ($options{proxy}) isn't readable.") unless (-r $f);
    $ENV{X509_USER_PROXY} = $f;
}

# Must be exactly one URL.
printUsage(\*STDERR,0,"Must supply exactly one URL.") unless ($#ARGV==0);

# Ensure that the base command can be found and executed. 
my $exe = libexecPath($0) . "/$basecmd";
die "Can't execute $exe.\n" if (! -x $exe);

# Add the no authorization flag if desired.  (Order important here!)
$exe = "$exe -n" if ($options{noauth});

# Add the verbose flag if desired.
$exe = "$exe -l" if ($options{verbose});

# timeout value to pass to executable
my $remain;
if (exists $options{timeout}) {
    $remain = $options{timeout};
    if ($remain <= 0) {
      print STDERR "$0: timeout exceeded\n";
      exit(1);
    }
} else {
    $remain = 120;
}

# Now process all of the arguments.  The URL are processed
# sequentially.  The processing ends at the first failure. 
my $url = $ARGV[0];

open CMD, "$exe -t $remain '$url' |";
print while (<CMD>);
close CMD;

if ($? & 0x7f) {
  # exited with a signal, return the signal number
  $exitcode = $? & 0x7f;
} else {
  # set exitcode to return code if it was non zero
  $exitcode = ($? >> 8) if ($?);
}

exit($exitcode);


# This subroutine creates the libexec directory from the given
# filename.  If the filename is given as the current working
# directory, then it is used to generate the name. 
sub libexecPath {
    my ($fullname) = @_;
    my ($fname, $fpath) = fileparse($fullname);
    $fpath = cwd() if ("$fpath" eq ".");
    my @parts = split(/\//, $fpath);
    $parts[$#parts] = 'libexec';
    $fpath = join('/',@parts);

    return $fpath;
}


# A subroutine to act like pod2usage.  Since EDG uses a very old
# version of perl. 
sub printUsage {

    my $usageText = <<'END'

SYNOPSIS

edg-gridftp-ls [--proxy=proxy] [--timeout=timeout] [--verbose] [--noauth] URL 

edg-gridftp-ls --usage 

edg-gridftp-ls --help 

END
    ;

    my $helpText = $usageText . <<'END'

DESCRIPTION 

edg-gridftp-ls will list (to the standard output) a file or the
contents of a directory for the given URL.  It will return a zero
status on success.  In all other cases, it will return a non-zero
value and print an error message to the standard error.

END
    ;

    my ($fh, $level, $message) = @_;

    print $fh "$message\n" if ($message);

    my $text = ($level) ? ($helpText) : ($usageText);

    print $fh "$text\n";

    exit($level);
}
