#!/usr/bin/env bash
#
# GNU/Linux does not really require something like RelativeLink.c
# However, we do want to have the same look and feel with similar features.
#
# Copyright 2017 The Tor Project.  See LICENSE for licensing information.

complain_dialog_title="Mullvad Browser"

# Make sure this script wasn't started as 'sh start-mullvad-browser' or similar.
if [ "x$BASH" = "x" ]; then
  echo "$complain_dialog_title should be started as './start-mullvad-browser'"
  echo "Exiting." >&2
  exit 1;
fi

# Do not (try to) connect to the session manager
unset SESSION_MANAGER

# Complain about an error, by any means necessary.
# Usage: complain message
# message must not begin with a dash.
complain () {
  # Trim leading newlines, to avoid breaking formatting in some dialogs.
  complain_message="`echo "$1" | sed '/./,$!d'`"

  # If we're being run in debug/verbose mode, complain to stderr.
  if [ "$show_output" -eq 1 ]; then
    echo "$complain_message" >&2
    return
  fi

  # Otherwise, we're being run by a GUI program of some sort;
  # try to pop up a message in the GUI in the nicest way
  # possible.
  #
  # In mksh, non-existent commands return 127; I'll assume all
  # other shells set the same exit code if they can't run a
  # command.  (xmessage returns 1 if the user clicks the WM
  # close button, so we do need to look at the exact exit code,
  # not just assume the command failed to display a message if
  # it returns non-zero.)

  # First, try zenity.
  zenity --error \
         --title="$complain_dialog_title" \
         --text="$complain_message"
  if [ "$?" -ne 127 ]; then
    return
  fi

  # Try kdialog.
  kdialog --title "$complain_dialog_title" \
          --error "$complain_message"
  if [ "$?" -ne 127 ]; then
    return
  fi

  # Try xmessage.
  xmessage -title "$complain_dialog_title" \
           -center \
           -buttons OK \
           -default OK \
           -xrm '*message.scrollVertical: Never' \
           "$complain_message"
  if [ "$?" -ne 127 ]; then
    return
  fi

  # Try gxmessage.  This one isn't installed by default on
  # Debian with the default GNOME installation, so it seems to
  # be the least likely program to have available, but it might
  # be used by one of the 'lightweight' Gtk-based desktop
  # environments.
  gxmessage -title "$complain_dialog_title" \
            -center \
            -buttons GTK_STOCK_OK \
            -default OK \
            "$complain_message"
  if [ "$?" -ne 127 ]; then
    return
  fi
}

if [ "`id -u`" -eq 0 ]; then
  complain "The Mullvad Browser should not be run as root.  Exiting."
  exit 1
fi

if test -r /proc/cpuinfo && ! grep -q '^flags\s*:.* sse2' /proc/cpuinfo; then
  complain "Mullvad Browser requires a CPU with SSE2 support.  Exiting."
  exit 1
fi

print_usage () {
  printf "\nMullvad Browser Script Options\n"
  printf "  --verbose         Display the browser output in the terminal\n"
  printf "  --log [file]      Record the browser output in file (default: mullvad-browser.log)\n"
  printf "  --detach          Detach from terminal and run Mullvad Browser in the background.\n"
  if test -z "$system_install"; then
    printf "  --register-app    Register Mullvad Browser as a desktop app for this user\n"
    printf "  --unregister-app  Unregister Mullvad Browser as a desktop app for this user\n"
  fi
}
log_output=0
show_output=0
detach=0
show_usage=0
register_desktop_app=0
logfile=/dev/null
while :
do
  case "$1" in
    --detach)
      detach=1
      shift
      ;;
    -v | --verbose | -d | --debug)
      show_output=1
      verbose_arg="$2"
      shift
      ;;
    -h | "-?" | --help | -help)
      show_usage=1
      show_output=1
      shift
      ;;
    -l | --log)
      if [ -z "$2" -o "${2:0:1}" == "-" ]; then
        printf "Logging Mullvad Browser debug information to mullvad-browser.log\n"
        logfile="../mullvad-browser.log"
      elif [ "${2:0:1}" == "/" -o "${2:0:1}" == "~" ]; then
        printf "Logging Mullvad Browser debug information to %s\n" "$2"
        logfile="$2"
        shift
      else
        printf "Logging Mullvad Browser debug information to %s\n" "$2"
        logfile="../$2"
        shift
      fi
      log_output=1
      shift
      ;;
    --register-app)
      register_desktop_app=1
      show_output=1
      shift
      ;;
    --unregister-app)
      register_desktop_app=-1
      show_output=1
      shift
      ;;
    *) # No more options
      break
      ;;
  esac
done

# We can't detach and show output at the same time..
if [ "$show_output" -eq 1 -a "$detach" -eq 1 ]; then
  detach=0
fi

if [ "$show_output" -eq 0 ]; then
  # If the user hasn't requested 'debug mode' or --help, close stdout and stderr,
  # to keep Firefox and the stuff loaded by/for it (including the
  # system's shared-library loader) from printing messages to
  # $HOME/.xsession-errors or other files. (Users wouldn't have seen
  # messages there anyway.)
  exec > "$logfile"
  exec 2> "$logfile"
fi

# If XAUTHORITY is unset, set it to its default value of $HOME/.Xauthority
# before we change HOME below.  (See xauth(1) and #1945.)  XDM and KDM rely
# on applications using this default value.
if [ -z "$XAUTHORITY" ]; then
  XAUTHORITY=~/.Xauthority
  export XAUTHORITY
fi

# If this script is being run through a symlink, we need to know where
# in the filesystem the script itself is, not where the symlink is.
myname="$0"
if [ -L "$myname" ]; then
  # XXX readlink is not POSIX, but is present in GNU coreutils
  # and on FreeBSD.  Unfortunately, the -f option (which follows
  # a whole chain of symlinks until it reaches a non-symlink
  # path name) is a GNUism, so we have to have a fallback for
  # FreeBSD.  Fortunately, FreeBSD has realpath instead;
  # unfortunately, that's also non-POSIX and is not present in
  # GNU coreutils.
  #
  # If this launcher were a C program, we could just use the
  # realpath function, which *is* POSIX.  Too bad POSIX didn't
  # make that function accessible to shell scripts.

  # If realpath is available, use it; it Does The Right Thing.
  possibly_my_real_name="`realpath "$myname" 2>/dev/null`"
  if [ "$?" -eq 0 ]; then
    myname="$possibly_my_real_name"
  else
    # realpath is not available; hopefully readlink -f works.
    myname="`readlink -f "$myname" 2>/dev/null`"
    if [ "$?" -ne 0 ]; then
      # Ugh.
      complain "start-mullvad-browser cannot be run using a symlink on this operating system."
    fi
  fi
fi

cd "$(dirname "$myname")"
browser_dir="$(pwd)"
if test -f "$browser_dir/is-packaged-app"; then
  system_install=1
  browser_home="$HOME/.mullvad-browser"
  mkdir -p "$browser_home"
  cd "$browser_home"
else
  browser_home="$browser_dir"
fi

# If ${PWD} results in a zero length string, we can try something else...
if [ ! "${PWD}" ]; then
  # "hacking around some braindamage"
  PWD="`pwd`"
  surveysays="This system has a messed up shell.\n"
fi

# This is a fix for an ibus issue on some Linux systems. See #9353 for more
# details. The symlink needs to be created before we change HOME.
if [ ! -d ".config/ibus" ]; then
  mkdir -p .config/ibus
  ln -nsf ~/.config/ibus/bus .config/ibus
fi

if test -z "$system_install"; then
  # Fix up .desktop Icon and Exec Paths, and update the .desktop file from the
  # canonical version if it was changed by the updater.
  cp start-mullvad-browser.desktop ../
  sed -i -e "s,^Name=.*,Name=Mullvad Browser,g" ../start-mullvad-browser.desktop
  sed -i -e "s,^Icon=.*,Icon=$PWD/browser/chrome/icons/default/default128.png,g" ../start-mullvad-browser.desktop
  sed -i -e "s,^Icon=.*,Icon=$PWD/browser/chrome/icons/default/default128.png,g" start-mullvad-browser.desktop
  sed -i -e "s,^Exec=.*,Exec=sh -c '\"$PWD/start-mullvad-browser\" || ([ !  -x \"$PWD/start-mullvad-browser\" ] \&\& \"\$(dirname \"\$*\")\"/Browser/start-mullvad-browser)' dummy %k,g" ../start-mullvad-browser.desktop

  if [ "$register_desktop_app" -eq 1 ]; then
    mkdir -p "$HOME/.local/share/applications/"
    cp ../start-mullvad-browser.desktop "$HOME/.local/share/applications/"
    update-desktop-database "$HOME/.local/share/applications/"
    printf "Mullvad Browser has been registered as a desktop app for this user in ~/.local/share/applications/\n"
    exit 0
  fi

  if [ "$register_desktop_app" -eq -1 ]; then
    if [ -e "$HOME/.local/share/applications/start-mullvad-browser.desktop" ]; then
      rm -f "$HOME/.local/share/applications/start-mullvad-browser.desktop"
      update-desktop-database "$HOME/.local/share/applications/"
      printf "Mullvad Browser has been removed as a user desktop app (from ~/.local/share/applications/)\n"
    else
      printf "Mullvad Browser does not appear to be a desktop app (not present in ~/.local/share/applications/)\n"
    fi
    exit 0
  fi
fi

export BB_ORIGINAL_HOME="$HOME"
HOME="$browser_home"
export HOME

# Prevent disk leaks in $HOME/.local/share (tor-browser#17560)
function erase_leaky() {
  local leaky="$1"
  [ -e "$leaky" ] &&
    ( srm -r "$leaky" ||
      wipe -r "$leaky" ||
      find "$leaky" -type f -exec shred -u {} \; ;
      rm -rf "$leaky"
    ) > /dev/null 2>&1
}
local_dir="$HOME/.local/"
share_dir="$local_dir/share"
# We don't want to mess with symlinks, possibly pointing outside the
# Browser directory (tor-browser-build#41050).
# We're not using realpath/readlink for consistency with the (possibly
# outdated) availability assumptions made elsewhere in this script.
if ! [ -L "$local_dir" -o -L "$share_dir" ]; then
  if [ -d "$share_dir" ]; then
    for leaky_path in "gvfs-metadata" "recently-used.xbel"; do
      erase_leaky "$share_dir/$leaky_path"
    done
  else
    mkdir -p "$local_dir"
  fi
  ln -fs /dev/null "$share_dir"
fi
[ -L "$HOME/.cache" ] || erase_leaky "$HOME/.cache/nvidia"




# Avoid overwriting user's dconf values. Fixes #27903.
export GSETTINGS_BACKEND=memory

# tor-browser-build#41017: Nvidia drivers create a shader cache by default in
# $HOME/.cache/nvidia. We we can easily disable it.
export __GL_SHADER_DISK_CACHE=0

cd "$browser_dir"

if [ "$show_usage" -eq 1 ]; then
  # Display Firefox help, then our help
   ./mullvadbrowser --help 2>/dev/null
  print_usage
elif [ "$detach" -eq 1 ] ; then
   ./mullvadbrowser "${@}" > "$logfile" 2>&1 </dev/null &
  disown "$!"
elif [ "$log_output" -eq 1 -a "$show_output" -eq 1 ]; then
   ./mullvadbrowser "${@}" 2>&1 </dev/null | \
    tee "$logfile"
elif [ "$show_output" -eq 1 ]; then
   ./mullvadbrowser "${@}" < /dev/null
else
   ./mullvadbrowser "${@}" > "$logfile" 2>&1 </dev/null
fi

exit $?
