#!/bin/sh
# JoyRemote - whether this computer's login screen may be seen from elsewhere.
#
#   joyremote-login-screen status     say which it is
#   sudo joyremote-login-screen enable        the login screen, for this computer
#   sudo joyremote-login-screen disable       put GNOME's own answer back
#   joyremote-login-screen enable-here        the lock screen, for this account
#   joyremote-login-screen disable-here       put that back
#
# Two commands because they are two different settings. The login screen belongs
# to the computer and needs root; the lock screen belongs to whoever is signed
# in, lives in their own dconf, and root cannot write it for them.
set -e

UUID="joyremote-login-screen@joyremote.com"
EXTENSION="/usr/share/gnome-shell/extensions/$UUID"
SCHEMAS="/usr/share/glib-2.0/schemas"
OVERRIDE="$SCHEMAS/90_joyremote-login-screen.gschema.override"
GDM_DB="/etc/dconf/db/gdm.d/90-joyremote-login-screen"

# The schema override alone is not enough everywhere. Overrides are applied in
# file-name order and the last one to name a key wins, so a distribution that
# ships its own default list replaces ours: Fedora's
# org.gnome.shell.gschema.override sorts after 90_ and says
# ['background-logo@fedorahosted.org'], and the greeter enabled that and
# nothing else - "Session creation inhibited" on every try, measured on
# Fedora 44. GDM's own dconf database is read by the login screen and by
# nothing else, ahead of every schema default, so the list goes there too:
# whatever the greeter would have enabled anyway, plus this.
gdm_profile() {
    for p in /etc/dconf/profile/gdm /usr/share/dconf/profile/gdm; do
        if [ -f "$p" ] && grep -q '^system-db:gdm$' "$p"; then
            echo "$p"
            return 0
        fi
    done
    return 1
}

# The list as the login screen would read it: GDM's profile with an empty
# user database in place of whoever is running this.
greeter_sees() {
    profile="$(gdm_profile)" || return 1
    command -v gsettings >/dev/null 2>&1 || return 1
    empty="$(mktemp -d)"
    XDG_CONFIG_HOME="$empty" DCONF_PROFILE="$profile" \
        gsettings get org.gnome.shell enabled-extensions 2>/dev/null
    rm -rf "$empty"
}

gdm_db_update() {
    command -v dconf >/dev/null 2>&1 && dconf update
}

as_root() {
    [ "$(id -u)" = "0" ] || {
        echo "This changes a setting for the login screen, so it needs root:" >&2
        echo "  sudo joyremote-login-screen $1" >&2
        exit 1
    }
}

recompile() {
    if command -v glib-compile-schemas >/dev/null 2>&1; then
        glib-compile-schemas "$SCHEMAS"
    else
        echo "glib-compile-schemas is not installed, so nothing was changed." >&2
        exit 1
    fi
}

case "${1:-status}" in
    enable)
        as_root enable
        [ -d "$EXTENSION" ] || {
            echo "$EXTENSION is not there; reinstall the joyremote package." >&2
            exit 1
        }
        cat > "$OVERRIDE" <<OVERRIDE_FILE
# Written by joyremote-login-screen. Remove it with:
#   sudo joyremote-login-screen disable
[org.gnome.shell]
enabled-extensions=['$UUID']
OVERRIDE_FILE
        recompile
        if gdm_profile >/dev/null && command -v dconf >/dev/null 2>&1; then
            # Asked without our own file first, so a list written by an earlier
            # `enable` is not carried forward as though it were the system's.
            rm -f "$GDM_DB"
            gdm_db_update
            current="$(greeter_sees)" || current=""
            case "$current" in
                *"'$UUID'"*) wanted="$current" ;;
                ""|"@as []"|"[]") wanted="['$UUID']" ;;
                *) wanted="$(printf '%s' "$current" | sed "s/]\$/, '$UUID']/")" ;;
            esac
            mkdir -p "$(dirname "$GDM_DB")"
            cat > "$GDM_DB" <<GDM_FILE
# Written by joyremote-login-screen: what the login screen enables, with
# JoyRemote's extension added. Remove it with:
#   sudo joyremote-login-screen disable
[org/gnome/shell]
enabled-extensions=$wanted
GDM_FILE
            gdm_db_update
            case "$(greeter_sees)" in
                *"'$UUID'"*) ;;
                *)
                    echo "The setting was written, but the login screen still does not list" >&2
                    echo "the extension; something with a higher priority sets that list." >&2
                    exit 1
                    ;;
            esac
        fi
        echo "The login screen may now be shared."
        echo
        echo "It takes effect the next time the login screen appears - after a"
        echo "restart, or a log out. Until then nothing has changed."
        echo
        echo "Only computers this one has already approved can connect there, and"
        echo "they are offered the screen and the keyboard and nothing else."
        echo
        echo "The lock screen is a separate setting, in each person's own session:"
        echo "  joyremote-login-screen enable-here"
        echo "Run as yourself, not with sudo. Without it, a viewer arriving at a"
        echo "locked screen still sees nothing."
        ;;
    enable-here)
        [ "$(id -u)" != "0" ] || {
            echo "This one is yours, not the computer's: it goes in your own dconf," >&2
            echo "so run it as yourself rather than with sudo." >&2
            exit 1
        }
        [ -d "$EXTENSION" ] || {
            echo "$EXTENSION is not there; reinstall the joyremote package." >&2
            exit 1
        }
        command -v gsettings >/dev/null 2>&1 || {
            echo "gsettings is not installed, so nothing was changed." >&2
            exit 1
        }
        # Written to the setting the shell reads as a session starts, not asked
        # of the shell that is running. `gnome-extensions enable` asks the
        # running one, and a shell that started before this package was
        # installed has never heard of the extension: it answered "does not
        # exist" on a Fedora that had just installed it. The JoyRemote host
        # does the same thing by itself the first time it starts (see
        # `share_lock_screen`), so this is for doing it by hand.
        current="$(gsettings get org.gnome.shell enabled-extensions 2>/dev/null)" || current=""
        case "$current" in
            *"'$UUID'"*) ;;
            ""|"@as []"|"[]")
                gsettings set org.gnome.shell enabled-extensions "['$UUID']" ;;
            *)
                gsettings set org.gnome.shell enabled-extensions                     "$(printf '%s' "$current" | sed "s/]\$/, '$UUID']/")" ;;
        esac
        disabled="$(gsettings get org.gnome.shell disabled-extensions 2>/dev/null)" || disabled=""
        case "$disabled" in
            *"'$UUID'"*)
                gsettings set org.gnome.shell disabled-extensions                     "$(printf '%s' "$disabled" | sed -e "s/'$UUID'//" -e 's/\[, /[/' -e 's/, ,/,/' -e 's/, \]/]/')" ;;
        esac
        # Saying so is not the same as it being so. `enabled-extensions` is the
        # list this just added a uuid to, and the shell ignores that whole list
        # when GNOME's Extensions switch is off:
        #
        #     let extensions = this._getModeExtensions();
        #     if (!global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
        #         extensions = extensions.concat(...ENABLED_EXTENSIONS_KEY);
        #
        # Ubuntu ships that switch off, and the extensions people see running -
        # the dock, the desktop icons - are in the session mode's own list, which
        # is the half that is not ignored. So this said "may now be shared" while
        # nothing had changed, five times over, on the computer it was written
        # for. Asked and answered here rather than left to be discovered.
        if [ "$(gsettings get org.gnome.shell disable-user-extensions 2>/dev/null)" = "true" ]; then
            echo
            echo "But GNOME's own Extensions switch is off, and while it is, the" >&2
            echo "shell ignores the list this was just added to. Turn it on with:" >&2
            echo "  gsettings set org.gnome.shell disable-user-extensions false" >&2
            echo "or the Extensions toggle in GNOME Tweaks / the Extensions app." >&2
            exit 1
        fi
        echo "Your lock screen may now be shared."
        echo
        echo "It takes effect the next time you log in, because the shell enables"
        echo "extensions as a session starts."
        echo
        echo "A viewer arriving at your locked screen now sees the lock screen and"
        echo "can type your password into it, instead of the screen being unlocked"
        echo "for it. Turn remote unlocking off in Settings to require that."
        ;;
    disable-here)
        [ "$(id -u)" != "0" ] || {
            echo "Run this as yourself rather than with sudo." >&2
            exit 1
        }
        command -v gsettings >/dev/null 2>&1 || {
            echo "gsettings is not installed, so nothing was changed." >&2
            exit 1
        }
        current="$(gsettings get org.gnome.shell enabled-extensions 2>/dev/null)" || current=""
        case "$current" in
            *"'$UUID'"*)
                gsettings set org.gnome.shell enabled-extensions                     "$(printf '%s' "$current" | sed -e "s/'$UUID'//" -e 's/\[, /[/' -e 's/, ,/,/' -e 's/, \]/]/')" ;;
        esac
        echo "Your lock screen is GNOME's own again: it will not be shared."
        ;;
    disable)
        as_root disable
        rm -f "$OVERRIDE"
        recompile
        if [ -f "$GDM_DB" ]; then
            rm -f "$GDM_DB"
            gdm_db_update || true
        fi
        echo "The login screen is GNOME's own again: it will not be shared."
        echo "A login screen already on display keeps what it started with."
        ;;
    status)
        if [ ! -d "$EXTENSION" ]; then
            echo "not installed: $EXTENSION is missing"
            exit 1
        fi
        if [ -f "$OVERRIDE" ] && grep -q "$UUID" "$OVERRIDE"; then
            # Said only when the login screen would really list it: a file of
            # ours that another list outranks is the Fedora failure, and it
            # used to be reported here as "enabled".
            case "$(greeter_sees || echo unknown)" in
                *"'$UUID'"*|unknown)
                    echo "login screen: enabled, from the next one onwards" ;;
                *)
                    echo "login screen: switched on, but another extension list outranks it"
                    echo "  sudo joyremote-login-screen enable" ;;
            esac
        else
            echo "login screen: disabled, it will not be shared"
            echo "  sudo joyremote-login-screen enable"
        fi
        # Asked of whoever is running this, because that is whose lock screen
        # the answer is about. Root has no session and no answer to give.
        if [ "$(id -u)" = "0" ]; then
            echo "lock screen: ask as the person whose screen it is, not as root"
        elif ! command -v gnome-extensions >/dev/null 2>&1; then
            echo "lock screen: cannot tell, gnome-extensions is not installed"
        elif gnome-extensions info "$UUID" 2>/dev/null | grep -qiE "^ *state: *(ACTIVE|ENABLED)"; then
            echo "lock screen: enabled for $(id -un)"
        elif [ "$(gsettings get org.gnome.shell disable-user-extensions 2>/dev/null)" = "true" ]; then
            echo "lock screen: disabled for $(id -un) - GNOME's Extensions switch is off"
            echo "  gsettings set org.gnome.shell disable-user-extensions false"
        else
            echo "lock screen: disabled for $(id -un), it will not be shared"
            echo "  joyremote-login-screen enable-here"
        fi
        ;;
    *)
        echo "usage: joyremote-login-screen [status|enable|disable|enable-here|disable-here]" >&2
        exit 2
        ;;
esac
