#!/usr/bin/env bash
# start-xvnc-server --- launch vnc server
# Author: Noah Friedman <friedman@splode.com>
# Public domain.

# $Id: start-xvnc-server,v 1.10 2019/01/10 21:01:27 friedman Exp $

# Commentary:
# Code:

# Name by which this script was invoked.
progname=${0##*/}

# To prevent hairy quoting and escaping later.
bq=\` eq=\'

usage="Usage: $progname {options}

Options are:
-n, --name         NAME            Set server desktop-name.
-d, --display      VNCDISPLAY      Set server display number.
-g, --geometry     WIDTHxHEIGHT    Set server size.
-D, --depth        DEPTH           Set framebuffer depth: 8, 16, or 24

Suggested geometries:
    2560x1600    1280x960
    1920x1200    1152x864
    1600x1200    1366x768
    1680x1050    1024x768
    1400x1050     800x600
    1400x960      640x480
    1280x1024
"

# Usage: eval "$getopt"; value=$optarg
# or     optarg_optional=t; eval "$getopt"; value=$optarg
#
# This function automatically shifts the positional args as appropriate.
# The argument to an option is optional if the variable `optarg_optional'
# is non-empty.  Otherwise, the argument is required and getopt will cause
# the program to exit on an error.  optarg_optional is reset to be empty
# after every call to getopt.  The argument (if any) is stored in the
# variable `optarg'.
#
# Long option syntax is `--foo=bar' or `--foo bar'.
# For optional args, you must use the `--foo=bar' long option syntax
# if the argument starts with `-', otherwise the argument will be ignored
# and treated as the next option.
getopt='
  { optarg=
    case $1 in
      --*=* ) optarg=`echo "$1" | sed -e "1s/^[^=]*=//"` ; shift ;;
      -* ) case ${2+set}:$optarg_optional in
             set:   ) optarg=$2 ; shift ; shift ;;
             set:?* ) case $2 in
                        -* ) shift ;;
                        *  )  optarg=$2; shift; shift ;;
                      esac ;;
             : ) option=$1
                 case $option in
                   --*=* ) option=`echo "$option" | sed -e "1s/=.*//;q"` ;;
                 esac
                 exec 1>&2
                 echo "$progname: option $bq$option$eq requires argument."
                 echo "$progname: use $bq--help$eq to list option syntax."
                 exit 1 ;;
             * ) shift ;;
           esac ;;
    esac
    optarg_optional=
  }'

name=
geom=
depth=

# Parse command line arguments.
# Make sure that all wildcarded options are long enough to be unambiguous.
# It's a good idea to document the full long option name in each case.
# Long options which take arguments will need a `*' appended to the
# canonical name to match the value appended after the `=' character.
while : ; do
    case $# in 0) break ;; esac

    case $1 in
        -h | --help | --h* )
            echo "$usage" 1>&2
            exit 0 ;;

        -d | --display* | --di* )
            eval "$getopt"
            XVNCDISPLAY=$optarg ;;

        -D | --depth* | --de* )*
            eval "$getopt"
            depth=$optarg ;;

        -g | --geometry* | --g* )
            eval "$getopt"
            geom=$optarg ;;

        -n | --name* | --n* )
            eval "$getopt"
            name=$optarg ;;

        -- ) shift; break ;; # Stop option processing
        -? | --* )
            case $1 in
                --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;;
                * )     arg=$1 ;;
            esac
            exec 1>&2
            echo "$progname: unknown or ambiguous option $bq$arg$eq"
            echo "$progname: Use $bq--help$eq for a list of options."
            exit 1 ;;
        -??* ) # Split grouped single options into separate args and try again
            optarg=$1
            shift
            set : `echo "x$optarg" | sed -e 's/^x-//;s/\(.\)/-\1 /g'` "$@"
            shift ;;
        * ) break ;;
    esac
done

homedirs=( $XDG_CONFIG_HOME
           $XDG_DATA_HOME
           $HOME/etc/misc )
for dir in "${homedirs[@]}"; do
    if [ -d "$dir/.vnc" ]; then
        HOME=$dir
        break
    fi
done

displaynum=${XVNCDISPLAY-10}
displaynum=${displaynum#*:}

# add elements to end of bash shell array in a readable way
apush() { eval "$1=(\"\${$1[@]}\" \"\${@:2}\")"; }
vnccmd=( ${VNCSERVER-vncserver} :$displaynum )
case ${name:+isset}  in isset ) apush vnccmd -name     $name  ;; esac
case ${geom:+isset}  in isset ) apush vnccmd -geometry $geom  ;; esac
case ${depth:+isset} in isset ) apush vnccmd -depth    $depth ;; esac

# Figure out if we're running tightvnc or real/tiger vnc
case `Xvnc -version 2>&1 | grep '^Xvnc'` in
    *tight*         ) apush vnccmd -dontdisconnect ;;
    *TigerVNC*      ) if ! [ -s $HOME/.vnc/config ]; then
                          apush vnccmd -DisconnectClients=0 -ZlibLevel=3
                      fi ;;
    *' version 4.'* ) apush vnccmd -DisconnectClients=0 -ZlibLevel=3 ;;
esac

javadirs=( /usr/share/vnc/classes
           /usr/share/x11vnc/classes
           /usr/local/share/vnc/classes )
for dir in "${javadirs[@]}"; do
    if [ -d "$dir" ]; then
        apush vnccmd \
              -httpd "$dir" \
              -httpPort $((5800 + $displaynum))
        break
    fi
done

case ${DISPLAY:+isset} in
    isset ) PARENTDISPLAY=$DISPLAY; export PARENTDISPLAY ;;
esac

# The vncserver script will background itself
set -x
exec with -s "${vnccmd[@]}" "$@"

# eof