#!/usr/bin/env perl

# This script does the following:
# 1. Clean up the screenenv directory.
# 2. Update the environment if a -r or -R option is used.
# 3. Unset SSH-related environment variables, as if a screen session
#    is started from a SSH connection, it may still be running after
#    the connection is closed and the variables would be incorrect.
# 4. Execute screen on the unmodified arguments.

use strict;

my ($proc) = '$Id: escreen 91724 2016-09-01 12:12:59Z vinc17/cventin $'
  =~ /^.Id: (\S+) / or die;

my $screenenv = $ENV{SCREENENV} || "$ENV{HOME}/.screenenv";

my %sessions;
open SESSIONS, '-|', qw(env LC_ALL=C screen -list)
  or die "$proc: can't exec screen -list: $!\n";
while (<SESSIONS>)
  {
    m,^\s*(\S+)\s+(?:\([-/: \d]+\)\s*)?\((Attached|Detached), or next;
    $sessions{$1} = $2 eq 'Detached' ? 1 : 0;
  }
close SESSIONS;
# Note: do not test the exit status as "screen -list" always returns
# with a non-zero exit status!

my $session;
foreach my $i (0..$#ARGV)
  {
    $ARGV[$i] =~ /^-[dD]?[rR]+$/ or next;
    $session = $ARGV[$i+1];
    defined $sessions{$session} and last;
    my @s = grep { ! defined $session || /(^|\.)\Q$session\E(\.|$)/ }
      keys %sessions;
    @s or undef $session, last;  # No matches amongst existing session names.
    @s == 1 and $session = $s[0], last;  # Single match, let's take it.
    # Several matches, let's see the detached sessions...
    my @d = grep { $sessions{$_} } @s;
    @d == 1 and $session = $d[0], last;  # Single match, let's take it.
    undef $session;
    last;
  }

if (-d $screenenv)
  {
    opendir SCREENENV, $screenenv
      or die "$proc: can't open directory '$screenenv': $!\n";
    my @dir = readdir SCREENENV;
    closedir SCREENENV
      or die "$proc: can't close directory '$screenenv': $!\n";
    unlink map "$screenenv/$_",
      grep { $_ ne '.' && $_ ne '..' && ! defined $sessions{$_} } @dir;
  }

sub setvar ($;$)
  {
    my ($var,$rep) = @_;
    my $value = $ENV{$var};
    defined $value or $value = $rep;
    #return (defined $value ? "$var=$value\nexport" : "unset")." $var\n\n";
    # The variant below may not work with old non-POSIX shells, but
    # avoids warnings with zsh + the WARN_CREATE_GLOBAL option for
    # variables that were not exported yet.
    return (defined $value ? "export $var=$value" : "unset $var")."\n\n";
  }

if (defined $session)
  {
    -d $screenenv or mkdir $screenenv
      or die "$proc: can't create directory '$screenenv': $!\n";
    chmod 0700, $screenenv;
    my $contents =
      setvar('DISPLAY').
      setvar('XAUTHORITY',"$ENV{HOME}/.Xauthority").
      setvar('XAPPLRESDIR').
      setvar('XFILESEARCHPATH').
      setvar('DBUS_SESSION_BUS_ADDRESS');
    foreach (grep /^X11_/, keys %ENV)
      { $contents .= setvar($_); }
    $contents .= setvar('SCREEN_IN_SSH',1) if defined $ENV{SSH_CONNECTION};
    $contents .= "# Written by $proc\n";
    my $file = "$screenenv/$session";
    open FILE, '>', $file
      or die "$proc: can't create file '$file': $!\n";
    print FILE $contents
      or die "$proc: can't write to file '$file': $!\n";
    close FILE
      or die "$proc: can't close file '$file': $!\n";
  }

delete $ENV{SSH_CLIENT};
delete $ENV{SSH_CONNECTION};
delete $ENV{SSH_TTY};

exec 'screen', @ARGV
  or die "$proc: can't exec screen: $!\n";