#!/usr/bin/perl
# $Id: glotvschedule 320 2008-09-17 11:09:22Z bd $

# Copyright 2004,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 Getopt::Long;
use Time::Local;
use POSIX;

# Explicit path needed since this script will be invoked by a setuid wrapper.
$ENV{PATH}  = '/bin:/usr/bin';

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

my $opt_tuner = 0;
my $opt_channel = undef;
my $opt_start = undef;
my $opt_until = undef;
my $opt_rec_tag = "";
my $opt_cancel = undef;
my $opt_list = undef;
my $opt_canonize = undef;

GetOptions('channel=s' => \$opt_channel,
	   'tuner=i' => \$opt_tuner,
	   'start=s' => \$opt_start,
	   'until=s' => \$opt_until,
	   'rec-tag:s' => \$opt_rec_tag,
	   'cancel=s' => \$opt_cancel,
	   'list' => \$opt_list,
	   'canonize' => \$opt_canonize,
	   );

$opt_channel = $opt_channel + 0 if defined $opt_channel;
$opt_tuner = $opt_tuner + 0 if defined $opt_tuner;

sub find_tomorrows_date {
    my $t = shift;
    my @ctime = localtime($t);
    my ($second,$minute,$hour,$day,$month,$year) = localtime($t+82800);
    if ($day == $ctime[3]) {
	($second,$minute,$hour,$day,$month,$year) = localtime($t+90000);
    }
    return ($day,$month,$year);
}

sub timespec {
    my $t = shift;
    my $spec = shift;

    my ($second1,$minute1,$hour1,$day1,$month1,$year1) = localtime($t);

    my $date_supplied = undef;
    if ($spec =~ s/^(\d\d\d\d)-(\d\d)-(\d\d)\s*//) {
	$year1 = $1 - 1900;
	$month1 = $2 - 1;
	$day1 = $3;

	$hour1 = 0;
	$minute1 = 0;
	$second1 = 0;

	$date_supplied = 1;
    }

    my $starttime = timelocal($second1,$minute1,$hour1,$day1,$month1,$year1);

    if ($spec =~ m/^(\d?\d):(\d\d)(:(\d\d))?$/) {
	my $hour2 = $1;
	my $minute2 = $2;
	my $second2 = $4 || 0;

	my $day2 = $day1;
	my $month2 = $month1;
	my $year2 = $year1;

	my $starttime2 = timelocal($second2,$minute2,$hour2,$day2,$month2,$year2);
	if ($starttime2 < $starttime && !$date_supplied) {
	    ($day2,$month2,$year2) = &find_tomorrows_date($starttime);
	    $starttime2 = timelocal($second2,$minute2,$hour2,$day2,$month2,$year2);
	}
	$starttime = $starttime2;
    }

    return $starttime;
}

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

if (defined $opt_cancel) {
    foreach my $x (split /,/, $opt_cancel) {
	if ($x =~ m/^(\d+)-(\d+)$/) {
	    unlink sprintf("$PATHPREFIX/var/schedule/%013d-%04d", $1, $2);
	} 
    }
} elsif ($opt_list) {
    my $dir = "$PATHPREFIX/var/schedule";
    opendir DIR, $dir or die "Couldn't open $dir: $!";
    my @names = readdir(DIR);
    closedir DIR;
    my $now = time;
    foreach (sort @names) {
	if (m/^(\d{13})-\d{4}$/) {
	    if ($_ < $now) {
		unlink "$dir/$_";
	    } elsif (open FILE, "$dir/$_") {
		print STDOUT <FILE>;
		close FILE;
	    }
	}
    }
} else {
    my $now = time;
    my $starttime = 0;
    my $stoptime = 0;

    $starttime = &timespec($now,$opt_start);

    if (defined($opt_until)) {
	if ($opt_until =~ m/^\+(\d+)$/) {
	    $stoptime = $starttime + 60*$1;
	} else {
	    $stoptime = &timespec($starttime,$opt_until);
	}
    }

    if ($opt_canonize) {
	my @t = localtime($starttime);
	printf "%04d-%02d-%02d %02d:%02d", $t[5]+1900,$t[4]+1,$t[3],$t[2],$t[1];
	if ($stoptime) {
	    @t = localtime($stoptime);
	    printf ",%04d-%02d-%02d %02d:%02d", $t[5]+1900,$t[4]+1,$t[3],$t[2],$t[1];
	} else {
	    print ",";
	}
	print ",", $opt_channel;
	print ",", $opt_tuner;
	$opt_rec_tag =~ tr{/}{_}d if $opt_rec_tag;
	print ",", $opt_rec_tag;
	print "\n";
    } else {
	if ($starttime > $now) {
	    my $tmpfile = "$PATHPREFIX/var/schedule/tmp$$";
	    open TMP, ">$tmpfile" or die "Couldn't create $tmpfile: $!";
	    print TMP "$starttime,$stoptime,$opt_channel,$opt_tuner,$opt_rec_tag\n";
	    close TMP;
	    rename $tmpfile, sprintf("$PATHPREFIX/var/schedule/%013d-%04d", $starttime, $opt_tuner);
	}

	my $recopt = "--record";
	$recopt .= "=$opt_channel" if defined($opt_channel);

	my $glotv_cmd = "$PATHPREFIX/glotv --tuner=$opt_tuner $recopt";
	$glotv_cmd .= " --rec-tag=" . &quotify($opt_rec_tag) if defined($opt_rec_tag);
	$glotv_cmd .= " --stop=$stoptime";

	# We need to be very clever here to work around brain-damaged
	# implementations of the "at" command:

	my $minutes = int(($starttime || $now) / 60) - 1 - int(time/60);

	if ($minutes > 0) {
	    my $at_arg = "now + $minutes minutes";
	    open ATJOB, "|TZ=UTC0 at '${at_arg}'" or die "Couldn't open atjob pipe: $!";
	    print ATJOB "unset TZ", "\n";
	    print ATJOB "$glotv_cmd --start=$starttime", "\n";
	    close ATJOB;
	} else {
	    print STDERR "Immediate recording initiated.\n";
	    system("$glotv_cmd &");
	    sleep(1);			# Wait for glotv to print spool file name
	}
    }
}

