#!/usr/bin/perl -w

# 04/28/2001 - Michael Carey
# this mighty application is released under
# the GPL
#
# CONFIGURATION REQUIRED...  SEE THE VARIABLE
# DECLARATIONS.
#
# simple freenet requester client.  If called
# with one parm, "favorites", it will read
# in keys from a text file.  I have had good luck
# scheduling this application to download MSK's.
# I typically don't have to wait for MSK's I
# visit often like Snarfoo.
#
# As a simple requester client, it tries an HTL100
# every time...  not sophisticated, but
# functional.
#
# features:
#    1. cross plaform (currently UNIX and Windows)
#    2. auto configuring...  will detect paths and
#       environment
#    3.
#

# sample UNIX config
# my $pathtojava = "/usr/local/bin/IBMJava2-13/jre/bin/java";
# my $classpath = "/home/extractoman/Freenet/freenet.jar";
# my $fnetport = "32285";
# my $pathtokeys = "/usr/local/bin";

# sample windows config
# my $pathtojava = "C:/jdk1.3/bin/java.exe";
# my $classpath = "c:/progra~1/freenet/freenet.jar";
# my $fnetport = "32285";

my $nullfile;
my $pathtojava;
my $classpath = "c:/progra~1/freenet/freenet.jar";
my $fnetport = "32285";
my $returncode;
my $pathtokeys = "c:/usr/local/bin";
my @favorites;
my $max_retrys = 4;
my $retry_num = 0;
my $helptext = <<EOT;
USAGE: freenet_request.pl <key>
                         Will search freenet for <key> and display the results
                         on screen.

       freenet_request.pl <key> <filename for key data>
                         Will search freenet for <key> and place the results
                         in <filename for key data>

       freenet_request.pl favorites
                         Will search freenet for keys listed in keys.txt

       freenet_request.pl is a simple freenet key request client.  It requests
       with an HTL of 100 always.  When called with one parameter, <key>, it
       request the key and displays the contents of the key contents on the
       screen.  When called with the key and a filename, it will request the
       key and place the contents of the key in the specified file.  When
       called with the word "favorites" it will request all keys in the file
       "keys.txt" and place the contents in a temp file that is discarded.
EOT

$SIG {__DIE__} = \&deadbrodie;

chomp @ARGV;

$pathtojava = getjavapath();
$nullfile = getnullfile();

if ($ARGV[0]) {

	if ($ARGV[0] eq "favorites" or $ARGV[0] eq "FAVORITES") {

		logit("getting keys from $pathtokeys/keys.txt");

		# get favorites from keys.txt and
		# push onto an array
		undef(@favorites);
		open(KEYLIST, "$pathtokeys/keys.txt") || die "cannot find $pathtokeys/keys.txt";
		while (<KEYLIST>) {
			push(@favorites, $_);
			}
		close(KEYLIST);
		chomp(@favorites);

		# get all favorites
		foreach (@favorites) {
			$returncode = 1;
			$retry_num = 1;
			while ($returncode != 0 and $retry_num <= $max_retrys) {
				logit("ATTEMPT: $retry_num REQUEST: $_");
				$returncode = 0xffff & system("$pathtojava -classpath $classpath Freenet.client.RequestClient --serverAddress tcp/127.0.0.1:$fnetport --htl 100 --logging error --verbosity 0 $_ $nullfile 1>$nullfile 2>$nullfile");
				logit("RETURN CODE: $returncode REQUEST: $_");
				sleep(3);
				$retry_num = $retry_num + 1;
				}
			}

		} else {

		if ($ARGV[1]) {
			$returncode = 1;
			$retry_num = 1;
			while ($returncode != 0 and $retry_num <= $max_retrys) {
				logit("ATTEMPT: $retry_num REQUEST: $ARGV[0], placing in file $ARGV[1]");
				$returncode = system("$pathtojava -classpath $classpath Freenet.client.RequestClient --serverAddress tcp/127.0.0.1:$fnetport --htl 100 --logging error $ARGV[0] $ARGV[1]");
				logit("RETURN CODE: $returncode REQUEST: $ARGV[0], placing in file $ARGV[1]");
				if ($returncode != 0) {
					sleep(3);
					}
				$retry_num = $retry_num + 1;
				}
			} else {
			$returncode = 1;
			$retry_num = 1;
			while ($returncode != 0 and $retry_num <= $max_retrys) {
				logit("ATTEMPT: $retry_num REQUEST: $ARGV[0] for the screen.");
				$returncode = system("$pathtojava -classpath $classpath Freenet.client.RequestClient --serverAddress tcp/127.0.0.1:$fnetport --htl 100 --logging error $ARGV[0]");
				logit("RETURN CODE: $returncode REQUEST: $ARGV[0] for the screen.");
				if ($returncode != 0) {
					sleep(3);
					}
				$retry_num = $retry_num + 1;
				}
			}
		if ($returncode == 0) {
			exit 0;
			} else {
			exit 1;
			}
		}
	logit("completed request(s)");

	} else {

	print $helptext;

	}

exit 0;

sub getjavapath {
	#
	# put preferred jre's last
	my @win32locations = ("C:/jdk1.3/bin/java.exe");
	my @unixlocations = ("/usr/local/bin/IBMJava2-13/jre/bin/java");
	my $location;
	my $jrelocation;
	#
	# get jre location
	if ($^O eq "MSWin32") {
		# find java on win32
		foreach $location (@win32locations) {
			if (-e $location && -r $location) {
				$jrelocation = $location;
				}
			}
		} else {
		# find java on unix
		foreach $location (@unixlocations) {
			if (-e $location && -r $location && -x $location) {
				$jrelocation = $location;
				}
			}
		}

	if (!$jrelocation or $jrelocation eq "") {
		die("cannot find java runtime executable");
		}

	return($jrelocation);
	}
sub getnullfile {
	my $location;
	#
	# set /dev/null or NUL depending on platform
	if ($^O eq "MSWin32") {
		# for win32
		$location = "NUL";
		} else {
		# for unix
		$location = "/dev/null";
		}

	return($location);
	}
sub logit {
	#
	# called thusly
	# logit("logtext", [logtype[, "loglabel"]]);
	#
	# logtext:
	#   text to be logged
	#
	# loglabel:
	#   label for log entry.  for instance
	#   the application name.
	#
	# logtype:
	#   1 - console only
	#   2 - logfile only
	#   3 - logfile and console
	#

	my $logyear;
	my $logmonth;
	my $logday;
	my $loghour;
	my $logminute;
	my $logsecond;
	my $logweekday;
	my $logyearday;
	my $logisdst;
	my $logampm;
	my $humanloghour;
	my $logfilename;
	my $logfilepath;
	my $logtype = 3;
	my $logtimestamp;
	my $humanlogtimestamp;
	my $loglabel = $0;
	my $logprogpath = $0;
	my $logpathchopped;
	my $logtext = "no text passed to logger";

	#
	# set $logfilepath and $logfilename if not already set
	if (!$logfilename) {
		$logfilename = "freenet_request.log";
		}
	if (!$logfilepath) {
		do {
			$logpathchopped = chop($logprogpath);
			} while ($logpathchopped and $logpathchopped ne "/" and $logpathchopped ne "\\");
		if ($logprogpath) {
			$logfilepath = $logprogpath;
			} else {
			$logfilepath = "./";
			}
		} # endif !$logfilepath
	#
	# set timestamps
	($logsecond, $logminute, $loghour, $logday, $logmonth, $logyear, $logweekday, $logyearday, $logisdst) = localtime();
	if ($loghour > 12) {
		$humanloghour = $loghour - 12;
		$logampm = "PM";
		} elsif ($loghour == 0) {
		$humanloghour = 12;
		$logampm = "AM";
		} else {
		$humanloghour = $loghour;
		$logampm = "AM";
		}
	$logtimestamp = sprintf("%04d%02d%02d%02d:%02d:%02d", $logyear+1900, $logmonth+1, $logday, $loghour, $logminute, $logsecond);
	$humanlogtimestamp = sprintf("%02d/%02d/%04d %02d:%02d:%02d%s", $logmonth+1, $logday, $logyear+1900, $humanloghour, $logminute, $logsecond, $logampm);
	#
	# set logtext, if passed
	if ($_[0] and $_[0] ne "") {
		$logtext = $_[0];
		}
	#
	# set logtype, if passed
	if ($_[1] and $_[1] < 5 and $_[1] > 0) {
		$logtype = $_[1];
		}
	#
	# set loglabel, if passed
	if ($_[2]) {
		$loglabel = $_[2];
		}
	#
	# if logtype is 1 or 3, log to console
	if ($logtype == 1 or $logtype == 3) {
		print "- $humanlogtimestamp $logtext\n";
		}
	#
	# if logtype is 2 or 3, log to logfile
	if ($logtype == 2 or $logtype == 3) {
		open (LOGFILE, ">>$logfilepath/$logfilename") or die "cannot open $logfilepath/$logfilename, this is a serious problem $!";
		flock (LOGFILE, 2) or die "cannot lock $logfilepath/$logfilename, this is a serious problem $!";;
		print LOGFILE "$logtimestamp $loglabel $logtext\n" or die "cannot append $logfilepath/$logfilename, this is a serious problem $!";;
		close (LOGFILE) or die "cannot close $logfilepath/$logfilename, this is a serious problem $!";
		}
	return;
	}
sub deadbrodie {
	#
	# this is to be a replacement for $SIG {__DIE__}
	#

	my $brodieyear;
	my $brodiemonth;
	my $brodieday;
	my $brodiehour;
	my $brodieminute;
	my $brodiesecond;
	my $brodieweekday;
	my $brodieyearday;
	my $brodieisdst;
	my $brodieampm;
	my $humanbrodiehour;
	my $humanbrodietimestamp;
	my $brodietimestamp;
	my $brodiemessage = "with no comments...";
	my $brodieexception = "with no exception...";
	my $brodiefile = __FILE__ . ".deadbrodie";

	#
	# if something is passed, place it in the message
	if ($_[0] and $_[0] ne "") {
		$brodiemessage = $_[0];
		chomp($brodiemessage);
		}
	#
	# if there is a value in $!, place it in the exception
	if ($! and $! ne "") {
		$brodieexception = $!;
		chomp($brodieexception);
		}
	#
	# set timestamps
	($brodiesecond, $brodieminute, $brodiehour, $brodieday, $brodiemonth, $brodieyear, $brodieweekday, $brodieyearday, $brodieisdst) = localtime();
	if ($brodiehour > 12) {
		$humanbrodiehour = $brodiehour - 12;
		$brodieampm = "PM";
		} elsif ($brodiehour == 0) {
		$humanbrodiehour = 12;
		$brodieampm = "AM";
		} else {
		$humanbrodiehour = $brodiehour;
		$brodieampm = "AM";
		}
	$brodietimestamp = sprintf("%04d%02d%02d%02d:%02d:%02d", $brodieyear+1900, $brodiemonth+1, $brodieday, $brodiehour, $brodieminute, $brodiesecond);
	$humanbrodietimestamp = sprintf("%02d/%02d/%04d %02d:%02d:%02d%s", $brodiemonth+1, $brodieday, $brodieyear+1900, $humanbrodiehour, $brodieminute, $brodiesecond, $brodieampm);
	#
	# print exception to console
	print "- $humanbrodietimestamp DEADBRODIE $brodiemessage ==> $brodieexception\n";
	#
	# log exception to *.deadbrodie file
	open (BRODIEFILE, ">>$brodiefile") or die "cannot open $brodiefile, this is a serious problem $!";
	flock (BRODIEFILE, 2) or die "cannot lock $brodiefile, this is a serious problem $!";
	print BRODIEFILE "$brodietimestamp DEADBRODIE $brodiemessage ==> $brodieexception\n" or die "cannot append $brodiefile, this is a serious problem $!";
	close (BRODIEFILE) or die "cannot close the $brodiefile, this is a serious problem $!";
	exit 1;
	}