[mca1001] / cgi / hifi.pl  

mca1001: cgi/hifi.pl

File: [mca1001] / cgi / hifi.pl (download) (as text)
Revision: 1.4, Wed Oct 9 02:42:55 2002 UTC (7 years, 11 months ago) by mca1001
Branch: MAIN
CVS Tags: REL_2003_02_03, HEAD
Changes since 1.3: +1 -2 lines
bad Craig

#! /usr/bin/perl -Tw

$vsn = q$Id: hifi.pl,v 1.4 2002/10/09 02:42:55 mca1001 Exp $;

BEGIN {
    $ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin';
    $ENV{'ENV'}  = '';
}
use CGI::Carp qw(fatalsToBrowser);
use HTML::Entities;
use strict;
use vars qw(%cgi $self $vsn);

$self = $ENV{'SCRIPT_NAME'} || die "What's my name today, nurse?";
$self =~ s@^.+/([^/]+)$@$1@;
$| = 1;

# Read input
%cgi = ();
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
    CGIgetpairs($ENV{QUERY_STRING});
} else {
    die "$ENV{'REQUEST_METHOD'} not method not available for $self";
}

if ($ENV{'SERVER_NAME'} eq 'troop.granta.internal') {
    my %okhosts;
    @okhosts{map {"$_.granta.internal"}
	     qw(
carraway
robinson
mcgarry
raggy-dan
troop
mr-clamp
dibble
mr-craddock
relapse
aggee
grubb
mr-wilkins
nick-fisher
platt
walter-harkin
philby
nibbs
mrs-cobbit
varley
potter
dappy
mr-antonio
pugh
barney-mcgrew
		)} = ();
    die "Pah, I'm not talking to you! Ask the administrator (below) to put $ENV{'REMOTE_HOST'} on the list"
	unless exists $okhosts{$ENV{'REMOTE_HOST'}};
} else {
    warn "Skipping the builting access checks\n";
}

##############################################################################

if (not $cgi{'mode'}) {
    # "guess the mode" code
    my $quest = 'fuser -v /dev/dsp /tmp/xmms_*'; # ask for PID and name of programs using sound device
    my $ans = `$quest 2>&1`;
    die "Failed to determine current program from '$quest': $ans / $! ($?)" if $?;
    if ($ans =~ m@([-\w/]*(?:xmms|mpg123)[-\w/]*)\s*$@m) {
	my $mode = $1;
	my %pids = ();

	while ($ans =~ s@^.*?\s*(\d+) f\.\.\.\.  $mode\s*$@@m) { $pids{$1} = undef }
	@cgi{qw(mode pids)} = ($mode, join ".", keys %pids);
	warn "HIFIcomment: Greetings to ".who()."\n";
	reloc();
    } else {
	my $choose = "No (recognised) sound program is running. You could pick a mode, but it may not get you very far:\n<ul>\n";
	foreach my $m (qw(xmms mpg123)) { $choose .= '<li><a href="'.url(mode=>$m)."\">$m</a>\n" }
	$choose .= "</ul>\n<hr><pre>$ans</pre><hr>\n";
	output($choose, 2, $self); # exits
    }
}

die "I don't understand '$cgi{'mode'}' mode" unless $cgi{'mode'} =~ /^(xmms|mpg123)$/;


# we have a mode .. we assume it's still correct (ie. program hasn't died)

if (exists $cgi{'op'}) {
    warn "HIFIcomment: Operation '$cgi{'op'}' from ".who()."\n";
    docmd();
    reloc();
} elsif (exists $cgi{'vol'}) {
    my $v = $cgi{'vol'};
    warn "HIFIcomment: Volume set to '$cgi{'vol'}' from ".who()."\n";
    die "Volume ($v) must be an integer from 0 to 100. You should know that..."
	unless $v =~ /^(\d+)$/ && $v >= 0 && $v <= 100;
    $v = $1; # launder
    my $oops = `/usr/bin/aumix -w $v 2>&1`;
    die "Problem setting volume: $oops / $! / $?" if $? || $oops;
    reloc();
} elsif (exists $cgi{'chat'}) {
    $cgi{'chat'} =~ s/\s+/ /g;
    warn "HIFIcomment: Chat: $cgi{'chat'}\n";
    warn "HIFIcomment: from ".who()."...\n";
    reloc();
}

my $msgform = 'type quickly... <form action="'.$self.'" method="get">
<input type="text" name="chat" size="40">
'.(join "\n", map { '<input type="hidden" name="'.CGIencode($_).'" value="'.CGIencode($cgi{$_}).'">' }
   qw(mode pids seq)).'
<input type="submit" value="chat"></form>';

my $html = ("<table cellpadding=\"15\" border=\"1\">".
	    "<tr><td colspan=\"2\">\n".
	    volumecontrol().
	    "\n</td></tr><tr><td colspan=\"2\">\n".
	    nowplaying().
	    "\n</td></tr><tr><td>\n".
	    skipcontrol(). "</td><td>$msgform".
	    "\n</td></tr><tr><td colspan=\"2\">\n".
	    showlog().
	    "</td></tr></table>\n");
output($html, 0.5, url(), url(mode=>'', pids=>'')); # exits
exit 0;

##############################################################################

sub who # return text indication of who's calling
{
    my $who = $ENV{'REMOTE_HOST'}; # ." / ".$ENV{'HTTP_USER_AGENT'};
    $who =~ s/\s+/ /g;
    return $who;
}

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

sub volumecontrol # display a volume control
{
    my $volume = `/usr/bin/aumix -wq 2>&1`;
    return "<strong>Can't read current volume: $volume / $! / $?</strong>" if $?;
    return "Volume says '$volume', but that doesn't make much sense to me\n"
	unless $volume =~ /^pcm\s*(\d+)\s*,\s*(\d+)\s*(,\s*[RP]\s*)?$/;
    my ($l, $r) = ($1, $2);
    my $ctrl = '';
    if ($l != $r) {
	$ctrl = "Balance is off-centre ($l%, $r%) but it will be centred if you change volume from this interface<p>\n";
	$l = int(($l + $r) / 2);
    }

    $ctrl .= "<table border=\"1\">\n";
    my ($newvol, @btns);

    for ($newvol=0; $newvol < $l && $newvol <= 100; $newvol += 10) { push @btns, volbtn($newvol, $l) }
    $ctrl .= '<tr><td align="left"><nobr>' . (join " ", @btns) . "</nobr></td><td></td><td></td></tr>\n";

    @btns = ();
    for ($newvol = $l<5 ? 0 : $l-5; $newvol <= $l + 5 && $newvol <= 100; $newvol += 1)
    { push @btns, volbtn($newvol, $l) }
    $ctrl .= '<tr><td></td><td align="center"><nobr>' . (join " ", @btns) . "</nobr></td><td></td></tr>\n";

    @btns = ();
    for ($newvol = 100; $newvol > $l; $newvol -= 10) { unshift @btns, volbtn($newvol, $l) }
    $ctrl .= '<tr><td></td><td></td><td align="right"><nobr>' . (join " ", @btns) . "</nobr></td></tr>\n";

    $ctrl .= "</table>\n";

    $ctrl .= "<em>If you want it any louder you will have to walk over and tweak the knob on the speakers!</em>\n"
	if $l == 100;

    return $ctrl;
}

sub volbtn
{
    my ($n, $o) = (shift,shift);
    return ($n == $o ?
	    "<strong>[$n%]</strong>" :
	    '<a href="'.url(vol=>$n)."\">$n%</a>"
	    );
}

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

sub nowplaying # display item currently being played
{
    return "Dunno what's playing. Write some code." unless -d "/proc";

    die "Wot no pids? You want to start again I think"
	unless defined $cgi{'pids'};
    die "Can't get a sensible PID from '$cgi{'pids'}', that probably means they've gone home"
	unless $cgi{'pids'} =~ /^[\d.]+$/;

    my $playing;
    my %pids;

    @pids{ split /\./, $cgi{'pids'} } = ();

    foreach my $pid (keys %pids) {
	$playing = `ls -l /proc/$pid/fd 2>&1`; # eww, what a mess!
	if ($?) {
	    $playing .= " $!";
	    delete $pids{$pid}; # no point coming back to this one
	} else {
	    last;
	}
    }
    $cgi{'pids'} = join ".", keys %pids;
	
    return "I've no idea what's playing at the moment.
I got an error ($playing) while trying to find out\n"
	if $?;

    return "Can't tell what's playing. Patch the program.\n"
	unless $playing =~ /\s+\d+ -> (.+\.(?:mp3|ogg|wav|mid))\s*$/mi;

    return encode_entities($1);
}

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

sub skipcontrol # display remote-control buttons
{
    my @ctrls;

    if ($cgi{'mode'} eq 'xmms') {
	@ctrls = ([back => '&lt;&lt;'],
		  [play => '&gt;'    ],
		  [pause=> 'pause'   ],
		  [stop => '[]'      ],
		  [forw => '&gt;&gt;'] );
    } elsif ($cgi{'mode'} eq 'mpg123') {
	@ctrls = ([pause=> 'pause'   ],
		  [play => '&gt;'    ],
		  [forw => '&gt;&gt;'] );
    }

    return "Can't do skipcontrol for '$cgi{'mode'}' mode\n" unless @ctrls;

    return ("<center>[\n".
	    (join " &nbsp;\n", map {skipbtn(@{$_})} @ctrls).
	    "\n    ]</center>");
}

sub skipbtn
{
    my ($op, $sym) = (shift,shift);
    return '<a href="'.url(op=>$op)."\">$sym</a>";
}

sub docmd
{
    die "Invalid command '$cgi{'op'}'" unless $cgi{'op'} =~ /^([a-z]+)$/;
    my $cmd = $1;
    $cgi{'mode'} =~ /^(\w+)$/;
    $cmd .= ".$1";

    my %cmd = ('back.xmms'  => '/usr/bin/xmms -r',
	       'play.xmms'  => '/usr/bin/xmms -p',
	       'pause.xmms' => '/usr/bin/xmms -u',
	       'stop.xmms'  => '/usr/bin/xmms -s',
	       'forw.xmms'  => '/usr/bin/xmms -f',
	       'pause.mpg123'=> 'killall -STOP mpg123',
	       'play.mpg123' => 'killall -CONT mpg123',
	       'forw.mpg123' => 'killall -INT mpg123 ; sleep 1',
	       );
    if (defined $cmd{$cmd}) {
	my $oops = `$cmd{$cmd} 2>&1`;
	die "Oops - '$cmd{$cmd}': $oops $!" if $?;
    } else {
	die "Command '$cmd' not implemented";
    }
}

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

sub showlog # display who's been at what
{
    # eww, this is hideous; for people with CPU to burn
    my $logfile = `/usr/bin/tail -200 /var/log/apache/error.log 2>&1`;
    $logfile .= " $!" if $?;
    my @logs = grep s/.*HIFIcomment: (.+)/$1/, split /\n/, $logfile;

    return (join "<br>\n",
	    reverse
	    map { /chat/i ? '<font color="red">'.$_.'</font>' : $_ }
	    map {encode_entities($_)}
	    @logs
	    );
}

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

sub output # args = (HTML, [optional: refresh time/sec, refresh url, [option: bottom-linked refresh url]])
{
    my $html = shift;
    my ($reftime, $refurl) = @_ ? (shift, shift) : (undef, undef);
    my $clickrefresh = @_ ? shift : ( defined $refurl ? $refurl : undef );

    print "Content-type: text/html\nPragma: no-cache\n
<html><head>\n  <title>Hifi: $ENV{'SERVER_NAME'}</title>\n";

    print '  <meta http-equiv="Refresh" content="'.(60 * $reftime).";URL=$refurl\">\n" if defined $reftime;
    print "</head>\n<body>\n$html\n";
    print "<i>this page should <a href=\"$clickrefresh\">refresh</a> in $reftime minutes...</i>\n" if defined $reftime;
    print "<em>Generated by $vsn</em>\n";
    print "</body></html>\n";

    exit 0;
}

sub reloc
{
    my $where = ("http://$ENV{'SERVER_NAME'}".
		 substr($ENV{'SCRIPT_NAME'}, 0,
			length($ENV{'SCRIPT_NAME'}) - length($self)).
		 url());

    print <<"magic";
Content-type: text/html
Location: $where

<html><head><title>Go to the $cgi{'mode'} mode</title></head>
<body>You want to be <a href="$where">here</a> now.</body>
</html>
magic
    exit 0;
}

##############################################################################

sub url # arg = (key => value pairs, as separate items)
{
    my %itms = splice @_, 0;
    foreach (qw(mode pids seq)) { $itms{$_} = $cgi{$_} if defined $cgi{$_} && not defined $itms{$_} }
    $itms{'seq'} = defined $itms{'seq'} ? $itms{'seq'}+1 : 0;
    return ("$self?".
	    join "&", map { CGIencode($_).'='.CGIencode($itms{$_}) } keys %itms
	    );
}

#
#> CGI library functions
#

sub CGIgetpairs # arg = string to break into key=value
# data is poked into the global %cgi
{
    local $_;
    foreach (split /[&?]/, $_[0]) {
	my ($key, $val) = split '=', $_;
	$val = '' unless defined $val;
	$cgi{lc(CGIdecode($key))} = CGIdecode($val)
	    if defined $key;
    }
}

# the CGI conversion convention
sub CGIencode # arg = input, returns quoted
{
    local $_ = shift;
    s/([^\w\/\-., ])/uc sprintf("%%%02x",ord($1))/eg;
    s/ /+/g;
    return $_;
}

sub CGIdecode # arg = input, returns decoded
{
    local $_ = shift;
    s/\+/ /g;
    s/%([0-9a-f]{2})/pack("c",hex($1))/gie;
    return $_;
}

Repository owner

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help