#!/usr/local/bin/perl
#
# X Mosaic Client ver 1.0
#   Julian Anderson <jules@comp.vuw.ac.nz>, 16 Jun 1994
#   Milton Ngan <milton@comp.vuw.ac.nz> 26 January 1995
#
# The idea here is to use Mosaic's remote-control function to pop
# up a new window upon request, a la emacsclient.  

# globals
#  @hostlist     - List of hostnames in the order that they should be searched
#  %pscmd        - An alist of how to run ps to get info on a specific pid
#  $default_file - The default list of hosts with their specific
#                  options to ps
#  $home         - The user's home directory

$default_file = "/usr/local/lib/mosaic/xmc_hosts";
$home         = $ENV{HOME};


## sub search_pid(host, pid)
##
## Looks for a process called [Mm]osaic on the given host with the
## given pid

sub search_pid  {
    local($host, $pid) = @_;
    local($line);

    print STDERR "Looking for $pid on $host\n" if $debug;

    $exec = "rsh $host" if ($host ne "localhost");
    open(PS,"$exec $pscmd{$host} $option $pid |");
    <PS>;			# Throw away the header
    $line = <PS>;		# get the one line we want		
    close(PS);
    chop $line;	
    return 1 if ($line =~ /[Mm]osaic/);
    return 0;
}

## sub remote_copy(host, local, remote)
##
## Copies the local file to the remote destination.
## Uses rcp if dest if not local host, otherwise uses cp

sub remote_copy {
    local($host, $localfile, $remotefile) = @_;
    
    print STDERR "Copying $localfile to $host:$remotefile\n" if $debug;

    if ($host ne "localhost") {
	system("rcp $localfile $host:$remotefile");
    } else {
	system("cp $localfile $remotefile");
    }
}

## sub remote_kill(host, pid)
##
## Issues a SIGUSR1 signal to the process with the given pid on the
## given machine. A system is used to get around the system dependent
## signal values.

sub remote_kill {
    local($host, $pid) = @_;

    print STDERR "Executing kill -USR1 $pid on $host\n" if $debug;

    if ($host ne "localhost") {
	system("rsh $host kill -USR1 $pid");
    } else {
	system("kill -USR1 $pid");
    }
    sleep 1;
}

## sub remote_rm(host, local, remote)
##
## Removes the remote file from the host, and removes the
## corresponding file on the local file system

sub remote_rm {	 
    local($host, $localfile, $remotefile) = @_;
    
    print STDERR "Removing $remotefile on $host\n" if $debug;
    if ($host ne "localhost") {
	system("rsh $host rm $remotefile");
    } else {
	unlink($remotefile);
    }
    print STDERR "Removing $localfile\n" if $debug;
    system("rm $localfile");
}

## sub read_xmcrc(file)
##
## Reads in the xmc options file. Stores the information in @hostlist
## and %psopts. Returns -1 if no hosts read.

sub read_xmcrc {
    local $file =$_[0];
    local ($host, $psopt);

    if (-r $file) {
	print STDERR "Opening host list file: $file\n" if $debug;
	open(RC, "<$file");
	while($_=<RC>) {
	    next if /^#/;
	    chop;
	    ($host, $pscmd) = /^[ \t]*([^ \t]+)[ \t]*(.*)/;
	    $pscmd = "ps" if ($pscmd =~ /^[ \t]*$/);
	    $pscmd{$host} = $pscmd;
	    push @hostlist, $host;
	}
	close(RC);
	$pscmd{"localhost"} = "ps";
    }
    if ($debug) {
	print STDERR "Displaying list of hosts to check:\n";
	foreach (@hostlist) {
	    printf STDERR "\t%15s\t%s\n", $_, $pscmd{$_};
	}
	print STDERR "\n";
    }
    return $#hostlist;
}

###########################################################################
#                      Main Program starts here.                          #
###########################################################################

# Standard argument processing

while ($_ = $ARGV[0],/^-/) {
    shift;
    last if /^--$/;
    /^-D/ && ($debug = 1);
    /^-r/ && ($reuse = 1);
    if (/^-f/) {
	$xmcrc = $ARGV[0];
	if (! -r $xmcrc) {
	    print STDERR "Error: $xmcrc is not readable or does not exist\n";
	    exit(1);
	}
	shift;
    }
}
$args = join(' ',@ARGV);
die "Usage: xmc [-D | -r | -f <file>] <URL>\n" unless $args ne "";

# Look in the .mosaicpid for the running process. 
# If there is one I have to hunt down which machine it is on
# If no .mosaicpid file the start new mosaic

if (-r "$home/.mosaicpid") {		
    print STDERR "Reading .mosaicpid file\n" if $debug;
    $pid = `cat $home/.mosaicpid`;
    chop $pid;
} else {
    print STDERR "No .mosaicpid file\n" if $debug;
}

# There is a .mosaicpid file, so parse default hosts to search
# And then search each host in the given order

if ($pid) {
    $xmcrc = "$home/.xmcrc" if ($xmcrc eq "");
    $xmcrc = $default_file if (! -r $xmcrc);
    print STDERR "Failed to read defaults from $xmcrc\n" 
	if (read_xmcrc($xmcrc)<0);    
    foreach ("localhost", @hostlist) {
	$host = $_;
	if (search_pid($_, $pid)) {
	    $found = 1;						
	    last;
	}
    }
}

# If I have found a running mosaic create the message file and issue the
# SIGUSR1 signal. Remember to be a tidy kiwi and clean up afterwards.
# If there is no process running, or we have not found one on the
# given machines, start up a new one. I'll fork so that it behaves in
# the same manner as a normal invocation of xmc.

if ($found) {		
    $tmpfile="$home/.Mosaic.$pid";
    $cmdfile="/tmp/Mosaic.$pid";
    if ($debug) {
	print STDERR "Found Mosaic on $host\n" ;
	print STDERR "Writing to $cmdfile\n";
    }

    open(TMP,">$tmpfile");
    if ($reuse) { 
	printf(TMP "goto\n"); 
    } else {
	printf(TMP "newwin\n"); 
    }    
    printf(TMP "$args\n");
    close(TMP);

    remote_copy($host, $tmpfile, $cmdfile);
    remote_kill($host, $pid);
    remote_rm($host, $tmpfile, $cmdfile);
} else {
    if ($debug) {
	print STDERR "Could not find Mosaic process - ";
	print STDERR "Starting new process\n";
    }
    exec "xmosaic", "$args" if (!fork); 
}
