#!/bin/perl
#
# Provide a "shelf" for storing files

use strict;
use CGI;

our $filestore = "/var/www/localhost/shelf";
#	Where uploaded files are stored on the web server. Must be
#	writeable by the user cgi scripts run as.
our $accessre = "^10\.";
#	The regexp used to check for the ability to upload files. This is
#	intended to restrict access to an organisation's network.
our $md5tool = "/usr/bin/md5sum";
#	Path to a utility which will display an MD5 digest to stdout when
#	given a name as a parameter.
our $stdheader = "/var/www/localhost/htdocs/header.html";
our $stdtrailer = "/var/www/localhost/htdocs/trailer.html";
our $stdcss = "/default.css";
#	Include bits of HTML at top and bottom of pages generated which
#	is my way of generating a standard look&feel. 

our $q = new CGI;
our @names = $q->param();

if (($q->param('upload') eq 1) && (check_access() eq 1)) {
	upload();
} elsif (defined(my $filename = $q->param('get'))) {
	getfile($filename);
} else {
	check_access();
	uploadform();
}


# check_access
#
# Simplistic routine to check whether access should be allowed or not. If
# access is denied, then a simple page is displayed. This may need editing
# for local requirements.

sub check_access {
    if ($ENV{"REMOTE_ADDR"} =~ /$accessre/) {
        return 1;
    } else {
    	print <<END;
		Content-type: text/html

		<html>
		  <head>
		    <title>No Access</title>
		    <link rel=StyleSheet href=$stdcss type="text/css">
		  </head>
END
	outfile($stdheader);
	print "<p>For security reasons, access has been denied.\n";
	outfile($stdtrailer);
	return 0;
    }
}

# uploadform
#
# Display a form for uploading a file.
 
sub uploadform {
    print <<END;
Content-type: text/html

	<html>
	  <head>
	    <title>Shelf Upload Form</title>
	    <link rel=StyleSheet href=$stdcss type="text/css">
	  </head>
END
	outfile($stdheader);
	print <<END;
	    <h1>Shelf Upload Form</h1>
	    <hr>
	    <p>
	    If you upload a file here, it will be saved on this server for
	    a week. Anytime during that week someone can download it using
	    the URL that will be displayed at the end of the process.
	    <p>
	    Whilst this facility is intended to make file available for a
	    small number of people, it should not be regarded as secure.
	    Whilst you need the URL given to download the file (which gives
	    you a small amount of security), anyone who guesses the URL can
	    also get the file.
	    <p>
	    Don't upload anything that <em>must</em> remain private.
	    <p>
	    <form enctype=multipart/form-data action=/cgi-bin/shelf
	    	method=post>
		<input type=hidden name=upload value=1>
		<input type=file name=upfile><br>
		<input type=submit value=Upload>
	    </form>
	    <p>
	    After pressing the 'Upload' button, there will be a short delay
	    whilst the file is uploaded and processed. Please be patient!
END
	outfile($stdtrailer);
}

# upload
#
# Process an upload request by storing a file in the data store. End by
# displaying appropriate details to the user.

sub upload {
    my $buffer;
    my $md5;
    my $file;
    my $bytesread;

    $file = $q->param('upfile');
    # This is where the file contents come from.
    open OUT, "> $filestore/upload.$$" or die "Can't open output!";
    while ($bytesread=read($file,$buffer,1024)) {
       print OUT $buffer;
    }
    close OUT;
    # Copy file contents into a temporary name
    $md5 = `$md5tool $filestore/upload.$$`;
    $md5 =~ s/\s.*//;
    system("mv $filestore/upload.$$ $filestore/$md5");
    $file = $?;

print <<END;
Content-type: text/html

<html>
  <head>
    <title>Upload Processed</title>
    <link rel=StyleSheet href=$stdcss type="text/css">
  </head>
END
	outfile($stdheader);
	print <<END;
    <H1>Upload Complete</h1>
    <p>
    Your file has been uploaded ... the file can be downloaded by visiting
    the following URL :-
    <p>
    <a href=http://tools.iso.port.ac.uk/cgi-bin/shelf\?get=$md5>
    	http://tools.iso.port.ac.uk/cgi-bin/shelf\?get=$md5</a>
    <p>
    You could cut and paste this into an email message. You may wish to tell
    the recipient what the original filename was so he or she can rename this
    download appropriately.
END
	outfile($stdtrailer);
}

# getfile
#
# User attempts to retrieve a file from the filestore.

sub getfile {
    my $fname = pop(@_);

    $fname =~ s/\///g;
    # Get rid of any slashes to prevent escaping out of the filestore.
    $fname = "$filestore/" . $fname;
    # Construct into a proper filename
    if (-r $fname) {
	print "Content-type: application/octet-stream\n\n";
	open IN, "<$fname";
	while (<IN>) {
	    print $_;
        }
	close IN;
    } else {
        print <<END;
Content-type: text/html

<html>
  <head>
    <title>Get a file ($fname)</title>
    <link rel=StyleSheet href=$stdcss type="text/css">
  </head>
END
	outfile($stdheader);
	print <<END;
    <h1>Get file named $fname</h1>
    <p>
    The file you requested is not available.
END
	outfile($stdtrailer);
    }
}

# outfile
#
# Takes a filename as a parameter and dumps the content to stdout.

sub outfile {
    my $fname = pop(@_);

    open IN, "< $fname" or return;
    while (<IN>) {
	print $_;
    }
    close(IN);
}