#!@@HOMEBREW_PERL@@
# PROGRAM: sproxy
# VERSION: 1.02
# DATE:    September-25-2023
# AUTHOR:  Jeffrey Fulmer
##
use FindBin;
use lib "${FindBin::Bin}";
use lib "${FindBin::Bin}${main::SL}/../${main::SL}lib/sproxy"; 
use LWP::UserAgent; 
use HTTP::Daemon; 
use HTTP::Response; 
use JoeDog::Config;
use Getopt::Std;
use FileHandle;
use vars qw($opt_V $opt_v $opt_f $opt_h $opt_p $opt_o $opt_t); 
use vars qw($VERSION $PROGRAM $DATE);  
use strict; 

$VERSION = '1.02';
$PROGRAM = 'sproxy';
$DATE    = 'September-25-2023';
getopts('Vvhp:f:o:t:');
my($ua, $conf, %conf, $port, $host);

if($opt_h){
  print_help();
  exit;
} 
if($opt_V){
  printf("%s v%s-%s\n", uc($PROGRAM), $VERSION, $DATE);
  exit;
}

parse_config();

{ ## main 
  $ua = new LWP::UserAgent;
  $ua->agent(uc($PROGRAM)." v".$VERSION);
  $ua->env_proxy; 
  $ua->timeout(($conf{'timeout'} eq int($conf{'timeout'}))?$conf{'timeout'}:120);

  my $port = ($conf{'port'} eq int($conf{'port'}))?$conf{'port'}:9001;

  my $parent = new HTTP::Daemon(
    LocalAddr => $conf{'host'},
    LocalPort => $port,
  );
 
  my $child;
  my $FILE = open_file();
  printf("%s v%s listening on port %d\n", uc($PROGRAM), $VERSION, $port);
  printf("...appending HTTP requests to: %s\n", $conf{'file'});
  printf("...default connection timeout: %s seconds\n", $conf{'timeout'});
  while($child = $parent->accept){
    connection_handler($FILE, $child);
  }
  close_file($FILE);
  exit 0;
}

sub
parse_config()
{
  my $file = $ENV{'HOME'} . "/urls.txt";

  if($opt_f){
    $conf = new JoeDog::Config($opt_f);
  } else {
    $conf = new JoeDog::Config(
      "${FindBin::Bin}${main::SL}/../${main::SL}etc/sproxy.conf"
    );
  }
  %conf = $conf->getHash("=");
  $conf{'host'}    = ($ARGV[0])?$ARGV[0]:(($conf{'host'})?$conf{'host'}:"localhost");
  $conf{'port'}    = ($opt_p)?$opt_p:(($conf{'port'})?$conf{'port'}:9001);
  $conf{'file'}    = ($opt_o)?$opt_o:(($conf{'file'})?$conf{'file'}:$file);
  $conf{'timeout'} = ($opt_t)?$opt_t:(($conf{'timeout'})?$conf{'timeout'}:120);
  $conf{'verbose'} = ($opt_v)?"true":(($conf{'verbose'})?$conf{'verbose'}:"false");
}

sub
connection_handler()
{
  my $FILE = shift;
  my $conn = shift;
  my $pid;  
  
  if($pid = fork){
    close($conn);
    return;
  } elsif( defined($pid)){
    my ($req, $res);
    $req = $conn->get_request;
    if(defined($req)){
      $res = get_request($FILE, $req);
      $conn->send_response($res);
    } 
    close $conn;
    exit 0;
  } else {
    die "Unable to fork!";
  }
  return; 
}

sub
get_request()
{
  my $FILE = shift;
  my $req  = shift; 
  my $res  = "";
  my $postData = "";
  
  if($req->method() eq "POST"){
     $postData=$req->content();
     $postData =~ s/\n/&/g;
     $postData =~ s/&$//;
    if($conf{'verbose'} eq "true"){
      print     $req->uri()." ".$req->method()." ".$postData. "\n";
    } 
    print $FILE $req->uri()." ".$req->method()." ".$postData. "\n";
  } else {
    if($conf{'verbose'} eq "true"){ 
      print     $req->uri()."\n";
    }
    print $FILE $req->uri()."\n";
  }
  $res = $ua->request($req);
  $res;
} 

sub
open_file()
{
  my $LOCK_EX = 2;
  my $FILE;

  $FILE = new FileHandle();
  if($FILE->open(">>".$conf{'file'})){
    flock($FILE, $LOCK_EX);
  } else {
    die $PROGRAM." error: cannot open ".$conf{'file'};
  } 
  return $FILE;
}

sub
close_file()
{
  my $FILE    = shift;
  my $LOCK_UN = 8;

  flock($FILE, $LOCK_UN);
  close($FILE);
  return;
}

sub 
print_help
{
  print <<END_OF_HELP;
$PROGRAM v$VERSION-$DATE
Usage:      $PROGRAM [options] [hostname]
            (If a hostname is not specified, then $PROGRAM will bind
            to localhost [127.0.0.1])
Options:
  -V        VERSION, prints version number to screen.
  -v        Verbose, prints URLS to screen.
  -h        Help, prints this section.
  -t NUM    Timeout, set the $PROGRAM connection timeout to NUMM (default 120)
  -p NUM    Port, specify the port on which $PROGRAM will listen for 
            incoming connections (default 9001)
  -f FILE   File, specify an alternative configuration file. 
            (default \$prefix/etc/sproxy.conf)
  -o FILE   Output file, specify an alternative file to write URLs.
            (default \$HOME/urls.txt)
END_OF_HELP
}

