#!/usr/pkg/bin/perl

# Distmp3, a program for distributing the encoding of music among several computers.
# Copyright (C) 2000  Martin Josefsson
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#
# Author: Martin Josefsson <gandalf@wlug.westbo.se>
#

use IO::Socket;
use IO::Handle;
use Net::hostent;

$|=1;

#----------------------------
$version = "0.1.9";

$config_file = "/usr/pkg/etc/distmp3.conf";

$RTR = "hejhopp_rtr";
$RTS = "hejhopp_rts";
$ACK = "hejhopp_ack";

$SRV_ID = "hejhopp_server_id";
$CLI_ID = "hejhopp_client_id";

#----------------------------

$SIG{INT} = sub { closedown("Caught INT signal, going down in flames..."); };

$SIG{TERM} = sub { closedown("Caught TERM signal, going up in smoke..."); };

sub parse_config_file
{
	open(CONFIG,"<$_[0]") or die "Couldn't open config file $_[0]";
	while ( <CONFIG> ) {
		if ( !(/^\n/ || /^#/ || /^;/) ) {
			if ( /^CLIENT_/ ) {
				chomp;
				($config_option,$config_value) = split("=",$_,2);
				$config_option =~ s/CLIENT_//;
				@config{$config_option} = $config_value;
			}
		}
	}
	close CONFIG;
}


sub parse_command_line
{
	$row = -1;
	$notdash = 0;
LOOP:	while ( ++$row <= @ARGV ) {

		if ( $ARGV[$row] eq "-h" || $ARGV[$row] eq "--help" ) {
			print_usage();
			exit(0);
		}

		if ( $ARGV[$row] eq "-p" ) {
			++$row;
			@config{PORT} = $ARGV[$row];
			next LOOP;
		}

		if ( $ARGV[$row] eq "-s" ) {
			++$row;
			@config{DATASIZE} = $ARGV[$row];
			next LOOP;
		}

		if ( $ARGV[$row] eq "-d" ) {
			++$row;
			if ( $ARGV[$row] == 1 ) {
				@config{DEBUG} = 1;
			} else {
				undef @config{DEBUG};
			}
			next LOOP;
		}

		if ( $ARGV[$row] eq "-df" ) {
			++$row;
			@config{DEBUGFILE} = $ARGV[$row];
			next LOOP;
		}

		if ( $notdash == 0 ) {
			@config{HOST} = $ARGV[$row];
			++$notdash;
			next LOOP;
		}

		if ( $notdash == 1 ) {
			@config{WAVFILE} = $ARGV[$row];
			++$notdash;
			next LOOP;
		}

		if ( $notdash == 2 ) {
			@config{MP3FILE} = $ARGV[$row];
			++$notdash;
			next LOOP;
		}
	}
}

sub print_usage
{
	print "Usage:  $0 [-p port] [-s datasize] [-d debug] [-df debugfile] host wav-file mp3-file\n";
}

sub open_remote_connection
{
	printd('Opening remote connection');
	$remote = IO::Socket::INET->new(Proto    => "tcp",
				    	PeerAddr => @config{HOST},
				    	PeerPort => @config{PORT})
		or die "Can't connect to @config{HOST} on port @config{PORT}: $!";

	$remote->autoflush(1);
	printd( "Connected to @config{HOST} on port @config{PORT}");
}

sub open_debug_file
{
	open (DEBUG, ">>@config{DEBUGFILE}") or die "Couldn't open debug-file @config{DEBUGFILE}: $!";
}

sub close_debug_file
{
	close DEBUG;
}

sub open_wav_file
{
	printd('opening wav-file');
	open (WAV_FILE, "<@config{WAVFILE}") || die "Can't open file @config{WAVFILE} for reading: $!";
	WAV_FILE->autoflush(1);
	$size_of_wavfile = sysseek(WAV_FILE,0,2);
	sysseek(WAV_FILE,0,0);
}

sub open_mp3_file
{
	printd('opening mp3-file');
	open (MP3_FILE, ">@config{MP3FILE}") || die "Can't open file @config{MP3FILE} for writing: $!";
	MP3_FILE->autoflush(1);
}

sub close_wav_file
{
	printd('closing wav-file');
	close WAV_FILE;
}

sub close_mp3_file
{
	printd('closing mp3-file');
	close MP3_FILE;
}

sub send_data
{
	$data = $_[0];
	print $remote $data;
}

sub recieve_data
{
	read $remote,$rdata,@config{DATASIZE};
	return $rdata;
} 

sub read_from_wav
{
	read WAV_FILE,$wdata,@config{DATASIZE};
	$data_read = $data_read + length($wdata);
	$persent_read = ($data_read*100)/$size_of_wavfile;
	printf "%.2f%% of $size_of_wavfile bytes done.\r", $persent_read;
	return $wdata;
}

sub write_to_mp3
{
	$mdata = $_[0];
	print MP3_FILE $mdata;
}

sub handshake
{
	printd('initiate handshake');

	send_data($CLI_ID);
	printd('sent Client id');

	read $remote,$answer,length($SRV_ID);
	printd('read Server id');

	if ( $answer ne $SRV_ID ) {
		die "Server isn't who he should be...";
	}
	printd('Ok, server id is what it should be');

	send_data($ACK);
	printd('sent ack');
}


sub printd
{
	if ( @config{DEBUG} ) {
		$message = $_[0];
		print "$message\n";
	}
	if ( @config{DEBUGFILE} ) {
		$message = $_[0];
		print DEBUG "$message\n";
	}
}

sub closedown
{ 
	if ( @config{DEBUG} || @config{DEBUGFILE} ) {
		printd("$_[0]\n");
	}
	if ( @config{DEBUGFILE} ) {
		close DEBUG;
	}
	print "Exited gracefully...\n"; 
	shutdown $remote,2;
	close WAV_FILE; 
	close MP3_FILE;
	exit(1); 
};


#Main program

if (@ARGV < 3) {
	print_usage();
	exit(1);
}

parse_config_file($config_file);

parse_command_line();

if ( @config{DEBUGFILE} ) {
	open_debug_file();
}

printd("Distmp3 client version $version");

print "Encoding @config{WAVFILE} into @config{MP3FILE} on host @config{HOST}\n";
printd("Encoding @config{WAVFILE} into @config{MP3FILE} on host @config{HOST}");

open_remote_connection();

handshake();

printd('forking like a GNU');

read $remote,$answer,length($RTR);
read $remote,$answer2,length($RTR);
if ( ($answer eq $RTR || $answer eq $RTS) && ($answer2 eq $RTS || $answer2 eq $RTR) ) {
	unless ($pid = fork) {
		printd('forking child to send data');
		open_wav_file();
		while ( $data = read_from_wav() ) {
			send_data($data);
		}
		close_wav_file();
		shutdown $remote,1;
		exit(0);
	}

	printd('entering code to recieve data');
	open_mp3_file();
	while ( $data2 = recieve_data() ) {
		write_to_mp3($data2);
	}
	close_mp3_file();
	exit(0);

	waitpid($pid,0);
} else {
	die "Server didn't send RTS and RTR!!!";
}

if ( $debug_file ) {
	print DEBUG "Finished\n";
	close_debug_file();
}

print "\n";
