#!/usr/bin/perl
# $Id: glotv 323 2008-09-17 12:56:03Z bd $

# Copyright 2004,2006,2008 Bjorn Danielsson
# http://glotv.dax.nu/
#
# This file is part of GLOTV. GLOTV is free software; you can redistribute
# it and/or modify it under the terms of the GNU General Public License as
# published at this URL: http://www.gnu.org/licenses/gpl.html.

use vars qw(%config);
use Socket;
use Getopt::Long;
use POSIX;
use Time::HiRes;

my $PATHPREFIX = "/usr/local/glotv";
do "$PATHPREFIX/etc/glotv.conf" or die "Failed reading configuration file";

my $opt_port = undef;
my $opt_host = undef;
my $opt_cmd = 'play_locked';
my $opt_record = undef;
my $opt_rec_tag = undef;
my $opt_abort_recording = undef;
my $opt_start = 0;
my $opt_stop = 0;
my $opt_exec = undef;
my $opt_tuner = undef;

GetOptions('host=s' => \$opt_host,
	   'port=s' => \$opt_port,
	   'command=s' => \$opt_cmd,
	   'record:s' => \$opt_record,
	   'rec-tag:s' => \$opt_rec_tag,
	   'abort-recording' => \$opt_abort_recording,
	   'start=s' => \$opt_start,
	   'stop=s' => \$opt_stop,
	   'exec=s' => \$opt_exec,
	   'tuner=i' => \$opt_tuner,
	   );

if ($opt_tuner) {
    #
    # Switch to alternative configuration:
    #
    my $altconf = $config{alternatives} || [];
    die "Unkown tuner: $opt_tuner" if $opt_tuner < 0 || $opt_tuner > @$altconf;
    my $conf = $$altconf[$opt_tuner-1];
    %config = ();
    do "$PATHPREFIX/etc/$conf" or die "Failed reading $PATHPREFIX/etc/$conf";
}

my $pidfile = $config{rec_pidfile} || "/tmp/glotvrecord.pid";

if ($opt_abort_recording) {
    exec("$PATHPREFIX/glotvrecord -p $pidfile");
    exit(1);
}

$opt_port = $config{tcp_port} || 1150 unless defined($opt_port);
$opt_host = $config{glotv_server} unless defined($opt_host);
$opt_exec = $config{default_exec} || "/bin/cat" unless defined($opt_exec);

my $spooldir = $config{spooldir} || "/home/video/recordings";
my $sockname = $config{sockname} || "/tmp/glotv.sock";

my $opt_segcount = $config{rec_maxsegs} || 50;
my $opt_seglimit = $config{rec_seglimit};
$opt_seglimit = 2001000000 unless defined($opt_seglimit);

sub spoolfilename {
    my $t = shift;
    my $nametag = shift;
    if (defined $nametag && $nametag ne "") {
	$nametag =~ tr{/}{}d;
	$nametag = "_${nametag}";
    } else {
	$nametag = "";
    }
    $tunerletter = chr($opt_tuner % 26 + ord("a"));
    my ($second,$minute,$hour,$day,$month,$year) = localtime($t);
    my $timetag = sprintf("%04d-%02d-%02d_%02d:%02d",
			  $year+1900, $month+1, $day, $hour, $minute);
    opendir SPOOL, $spooldir or die "Couldn't open spool directory: $!";
    my @spoolnames = readdir(SPOOL);
    closedir SPOOL;
    my $n = 0;
    foreach (@spoolnames) {
	if (/^\Q${timetag}${nametag}_${tunerletter}\E(\d\d)\.mpg$/i) {
	    $n = $1;
	}
    }
    return ("${timetag}${nametag}_${tunerletter}%02d.mpg", $n + 1);
}

sub quotify {
    my $arg = shift;
    $arg =~ s/'/'\\''/g;
    return "'$arg'";
}

sub open_socket {
    if ($opt_host) {
	my $tcp_proto = getprotobyname("tcp");
	socket(CONN, PF_INET, SOCK_STREAM, $tcp_proto) or die "Couldn't create socket: $!";
	connect(CONN, sockaddr_in($opt_port, inet_aton($opt_host)))
	    or die "Connect to ${opt_host}:${opt_port} failed: $!";
    } else {
	socket(CONN, PF_UNIX, SOCK_STREAM, 0) or die "Couldn't create socket: $!";
	connect(CONN, sockaddr_un($sockname)) or die "Connect to socket $sockname failed: $!";
    }
}

if (defined($opt_record)) {
    my $now = time;
    my $adj_stop = 0;
    my $adj_start = 0;
    $adj_start = $opt_start - 3 if $opt_start;

    if ($adj_start > $now + 5) {
	sleep($adj_start - $now - 5);
    }

    &open_socket();		# Do this after sleeping, to avoid auto-disconnect

    if ($opt_start) {
	my $timename = sprintf("%013d-%04d", $opt_start, $opt_tuner);
	my $schedfile = "$PATHPREFIX/var/schedule/${timename}";
	my $privatefile = "$PATHPREFIX/var/schedule/tmp${$}_${timename}";
	if (rename($schedfile, $privatefile) && open(SCHED, "<$privatefile")) {
	    unlink $privatefile;
	    my $line = <SCHED>;
	    close SCHED;
	    chomp $line;
	    ($opt_start,$opt_stop,$opt_record,$opt_tuner,$opt_rec_tag) = split(/,/, $line);
	} else {
	    exit(0);
	}
    }

    $adj_stop = $opt_stop + 3 if $opt_stop;

    system($config{rec_start_hook}) if $config{rec_start_hook};

    my ($spoolfilefmt,$spoolnum) = &spoolfilename($opt_start || $now, $opt_rec_tag);

    printf $spoolfilefmt, $spoolnum;
    print "\n";

    my $spoolfilename = sprintf($spoolfilefmt, $spoolnum);

    if ($opt_record ne "") {
	my $glotv_cmd = "$PATHPREFIX/glotv --command='channel_lock $opt_record'";
	$glotv_cmd .= " --tuner=$opt_tuner" if defined($opt_tuner);
	$glotv_cmd .= " --host=$opt_host" if defined($opt_host);
	$glotv_cmd .= " --port=$opt_port" if defined($opt_port);
	system($glotv_cmd);
	sleep 0.05;			# There is a delay before the channel change happens
    }

    my $quotedname = &quotify("$spooldir/$spoolfilename");
    my $rec_cmd = "$PATHPREFIX/glotvrecord -p $pidfile $quotedname $opt_seglimit $adj_stop $adj_start";

    open(STDIN, "<&CONN") or die "Couldn't redirect stdin to socket: $!";
    fcntl(STDIN, F_SETFD, 0);	# Doesn't hurt to spell it out.
    select CONN; $| = 1;
    print CONN $opt_cmd, "\n";
    while ($opt_segcount > 0) {
	if (system($rec_cmd) != 0) {
	    close CONN;
	    system($config{rec_end_hook}) if $config{rec_end_hook};
	    exit(0);
	}
	$spoolnum++;
	$spoolfilename = sprintf($spoolfilefmt, $spoolnum);	
	$quotedname = &quotify("$spooldir/$spoolfilename");
	$rec_cmd = "$PATHPREFIX/glotvrecord -p $pidfile $quotedname $opt_seglimit $adj_stop 0";
	$opt_segcount--;
    }
    exit(1);
} elsif (defined($opt_exec)) {
    &open_socket();
    open(STDIN, "<&CONN") or die "Couldn't redirect stdin to socket: $!";
    fcntl(STDIN, F_SETFD, 0);	# Doesn't hurt to spell it out.
    select CONN; $| = 1;
    print CONN $opt_cmd, "\n";
    exec($opt_exec);
    exit(1);
}

