#!/bin/bash -x

PARTIAL=false
DOWNGRADE_ATTEMPT=false

# customization time replacement
NAMESPACE_IDENTIFIER="@NAMESPACE_ID@"
NAMESPACE_PATH="@NAMESPACE_PATH@"

# for script embedded in uninstaller helper binary
if [ ${NAMESPACE_IDENTIFIER::1} == "@" ] && [ ${NAMESPACE_IDENTIFIER: -1} == "@" ]; then
    NAMESPACE_IDENTIFIER="f-secure"
    NAMESPACE_PATH="F-Secure"
fi

NAMESPACE="/Library/$NAMESPACE_PATH"
NAMESPACE_APPSUPPORT="/Library/Application Support/$NAMESPACE_PATH"

MAGIC=/var/db/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstall
LOG="/Library/Logs/F-Secure Mac Protection uninstall.log"
MSGLOG="/Library/Logs/F-Secure Mac Protection uninstall messages.log"
PKGUTIL=/usr/sbin/pkgutil
NOUNINSTALL="$NAMESPACE/fsmac/sysconfig/.no_uninstall"

customization_parameter_enabled() {
    local parameter="$1"
    grep -qi "^${parameter}=true" $NAMESPACE/fsmac/config/parameters
}

while getopts puc opt
do
    case "$opt" in
    p) PARTIAL=true
            ;;
	u) DOWNGRADE_ATTEMPT=true
	    ;;
	\?) echo "Usage: $0"
            exit 1
            ;;
    esac
done

log_entry() {
    echo "$1" >> "$MSGLOG"
    date "+%Y-%m-%d %H:%M:%S $1"
    syslog -s -l Critical "$1"
}

previous_uninstall_state=""
broadcast_uninstall_state() {
    # todo: this could be turned into something that is visible to user in uninstaller UI.

    if [ "$previous_uninstall_state" != "" ]; then
        date "+%Y-%m-%d %H:%M:%S finished: $previous_uninstall_state"
    fi

    previous_uninstall_state="$1"
    log_entry "$1"
}

if $DOWNGRADE_ATTEMPT ; then
    # Downgrading is not allowed in any case anymore
    # and this is a workarounds for builds with no version check in the package
    log_entry "Downgrade is disallowed"

    # kill preflight process
    kill -SIGTERM "$(ps $$ -o ppid=)"
    exit 1
fi

if [ -f $NOUNINSTALL ] && [ $PARTIAL == false ] ; then
    log_entry "Uninstall disallowed"
    exit 1
fi

if [ "$(id -u)" != "0" ] ; then
    log_entry "Need root permissions to perform uninstall. Run the command as sudo $0"
    exit 1
fi

# This communicates with installer preflight and post install scripts: not possible to install while uninstalling.
UNINSTALL_IN_PROGRESS_FILE=/tmp/.fsmac.uninstall-in-progress

file_is_older_than() {
    file_name="$1"

    if [ -f "$file_name" ] ; then
        seconds="$2"
        current_time=$(date +%s)
        file_time=$(date -r "$file_name" +%s)
        if (( file_time < ( current_time - ( "$seconds" ) ) )); then
            echo "$file_name is older than $seconds seconds"
            return 0
        fi
    else
        echo "$file_name does not exist"
        return 0
    fi

    return 1
}

if ! file_is_older_than "$UNINSTALL_IN_PROGRESS_FILE" 600 ; then
    log_entry "Error: Uninstall already in progress!"
    exit 1
fi

rm -f "$UNINSTALL_IN_PROGRESS_FILE"
touch "$UNINSTALL_IN_PROGRESS_FILE"

echo > "$MSGLOG"
exec 1>>"$LOG"
exec 2>>"$LOG"

broadcast_uninstall_state "Uninstall starting (upgrade=${PARTIAL}): $0 $*"

uname -a
id -a

if [ -r "$(dirname $0)/safer_remove_dir" ] ; then
    . "$(dirname $0)/safer_remove_dir"
elif [ -r $NAMESPACE/bin/safer_remove_dir ] ; then
    . $NAMESPACE/bin/safer_remove_dir
else
    log_entry "Warning: safer_remove_dir not found, using built-in fallback"
    safer_rmrf() {
	   rm -rf "$@"
    }
fi

# to forget old sensord
sensord=false
if [ -d $NAMESPACE/sensor ] ; then
    sensord=true
fi

updatedaemon=false
if [ -d $NAMESPACE/updatedaemon ] ; then
    updatedaemon=true
fi

fscunifiedfamilyrulesd=false
if [ -f "$NAMESPACE/bin/fscunifiedfamilyrulesd" ] ; then
    fscunifiedfamilyrulesd=true
fi

# Remove any old flag files indicating previous Browser extension uninstalls
rm -f /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstalled-*-extension

if ! $PARTIAL ; then
    rm -f /tmp/.fsmac.post-install-alf-suppress
    rm -f /tmp/.fs-bwuser
    rm -f /tmp/fsmac_failed_keycode
    rm -rf /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.customizations*
    rm -f /tmp/.fsmac-prefpane-opened
fi

rm -f /tmp/.fsav.${NAMESPACE_PATH}.postflight-completed

root_unload_remove () {
    echo "Unloading and removing $1"
    if [ -f "$1" ] ; then
        sudo launchctl bootout system "$1"
        sudo rm -rf "$1"
    else
        echo "$1 does not exist"
    fi
}

# This is the old uninstall trigger which is no longer needed.
old_uninstall_trigger="com.$NAMESPACE_IDENTIFIER.fsmac.uninstall"
root_unload_remove "/Library/LaunchDaemons/$old_uninstall_trigger.plist"
rm -f /var/db/.$old_uninstall_trigger

ERROR=false
check_error() {
    if test $? -ne 0 ; then
	   ERROR=true
	   echo "ERROR: $@" >> "$MSGLOG"
    fi
}

fatalexit() {
    fatalerrormessage="$1"
    fatalerrorexitcode="$2"
    if [ -z "$fatalerrorexitcode" ] ; then
        fatalerrorexitcode=1
    fi

    log_entry "Uninstall failed with error: ${fatalerrormessage}! Please contact support and email them the uninstall log file: $LOG"

    rm -f "$UNINSTALL_IN_PROGRESS_FILE"
    exit $fatalerrorexitcode
}

broadcast_uninstall_state "unload LaunchAgents"

unload_agent() {
    agent="$1"
    user="$2"
    uid="$3"

    if ! [ -f "$agent" ] ; then
        echo "$agent does not exist. Skipping..."
        return 0
    fi

    errors=$(launchctl asuser "$uid" sudo -u "$user" launchctl bootout "gui/$uid" "$agent" 2>&1)

    if [ -n "$errors" ] && [ "$errors" != "$agent: Operation now in progress" ] ; then
        echo "Unloading launch agent $agent for $user failed with $errors. Not fatal, continuing..."
        return 1
    fi

    return 0
}

unload_user_agents() {
    return_value=0

    for user in $(/usr/bin/who | grep "console" | cut -d' ' -f1); do
        uid=$(/usr/bin/id -u "$user")

        # skip users with UID < 500
        if [ "$uid" -lt 500 ] ; then
            echo "skipping id "$uid" for user "$user""
            continue
        fi

        unload_agent "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fsmac.gui.plist"  "$user" "$uid" || return_value=1
        unload_agent "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fscpasswordvault.plist"  "$user" "$uid" || return_value=1
        unload_agent "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.trasher.plist"    "$user" "$uid" || return_value=1
        unload_agent "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fsbpserver.plist" "$user" "$uid" || return_value=1
        unload_agent "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.XFENCEUserAgent.plist" "$user" "$uid" || return_value=1
    done

    return $return_value
}

systemextension_exists=false
if systemextensionsctl list | grep FSCSystemExtension > /dev/null ; then
    systemextension_exists=true
fi

unload_user_agents
check_error "Failed to unload GUI"

broadcast_uninstall_state "kill and remove LaunchAgents"

atLeastBigSur() {
    macOSVersion=$(sw_vers -productVersion)
    echo "macOS version $macOSVersion"
    limit=10.16.0
    if [ "$(version "$macOSVersion")" -ge "$(version "$limit")" ]; then
        return 0
    fi

    return 1
}

bigsur_hack () {
    # There is a problem with launchctl bootout, which happens on BigSur only.
    # launchctl bootout/unload commands return 0, but actually it takes some time for an agent to be unloaded.
    # So the processes killed in the next step will be relaunched killed again (with -9)
    # And relaunched menubar installs sysext again (and the system asks user to approve it).
    # Hacky workaround is to add a delay.
    if atLeastBigSur && $systemextension_exists ; then
        sleep 3
    fi
}

bigsur_hack

kill_user_agents() {
    processes_to_kill=("F-Secure Mac Protection")
    processes_to_kill+=("Safe Anywhere Mac Main Window")
    processes_to_kill+=("fscunifiedui")
    processes_to_kill+=("F-Secure XFENCE Configuration")
    processes_to_kill+=("Support Tool")
    processes_to_kill+=("fscpasswordvault")

    for process in "${processes_to_kill[@]}"; do
        if ! killall -0 "$process" 2> /dev/null; then
            continue
        fi

        if killall "$process"; then
            _pid=$(pgrep "$process") || _pid=1
            if [ $_pid != 1 ]; then
                sleep 2 # why is this needed?
                if killall -0 "$process" ; then
                    killall -9 "$process"
                fi
            fi
        fi
    done
}

remove_user_agents() {
    /bin/rm -f "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fsmac.gui.plist"
    /bin/rm -f "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fscpasswordvault.plist"
    /bin/rm -f "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fsmac.subsvars.plist"
    /bin/rm -f "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.trasher.plist"
    /bin/rm -f "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.fsbpserver.plist"
    /bin/rm -f "/Library/Preferences/com.$NAMESPACE_IDENTIFIER.fsmac.gui.plist"
    /bin/rm -f "/Library/LaunchAgents/com.$NAMESPACE_IDENTIFIER.XFENCEUserAgent.plist"
}

kill_user_agents
remove_user_agents

broadcast_uninstall_state "xfence uninstall"

remove() {
    file="$1"
    if [ -f "$file" ] ; then
        rm -f "$file"
    fi
    if [ -d "$file" ] ; then
        rm -rf "$file"
    fi
}

uninstall_xfence() {
    UNINSTALLER_SIGNAL_FILE="/Library/F-Secure/signal/xfence-disabled-by-uninstaller"
    remove "$UNINSTALLER_SIGNAL_FILE"

    xfenceKextLoaded=false
    if kextstat | grep "com.f-*secure.XFENCE" ; then
        xfenceKextLoaded=true
    fi

    isDaemonLoaded=false
    if launchctl list | grep -i -e "com.f-*secure.xfencedaemon" -e "com.f-secure.fscxfenced" > /dev/null ; then
        isDaemonLoaded=true
    fi

    if $isDaemonLoaded ; then
        touch /Library/F-Secure/signal/xfence-uninstall
        notifyutil -1 com.f-secure.xfence-uninstall-proceed && touch "$UNINSTALLER_SIGNAL_FILE" &
        notifyutil -p com.f-secure.xfence-uninstall

        SECONDS=0
        while [ $SECONDS -lt 10 ] && [ ! -f "$UNINSTALLER_SIGNAL_FILE" ]; do
            sleep 1
        done
    elif $xfenceKextLoaded ; then
        echo "kext is loaded but daemon is not - assuming filter is disabled and continuing anyway"
        # kext probably remains from previous installation
    fi

    root_unload_remove "/Library/LaunchDaemons/com.f-secure.fscxfenced.plist"
    root_unload_remove "/Library/LaunchDaemons/com.f-secure.xfencedaemon.plist"
    root_unload_remove "/Library/LaunchDaemons/com.f-secure.XFENCEDaemon.plist"
    root_unload_remove "/Library/LaunchDaemons/com.fsecure.XFENCEDaemon.plist"

    echo "Removing XFENCE files"
    if ! remove "/Library/Extensions/XFENCE.kext" ; then
        echo "Failed to remove XFENCE.kext - XFENCE may still be active."
        echo "Try rebooting and then run the uninstaller again."
        return 1
    fi

    if ! remove "/Library/F-Secure/Extensions/XFENCE.kext" ; then
        echo "Failed to remove XFENCE.kext - XFENCE may still be active."
        echo "Try rebooting and then run the uninstaller again."
        return 1
    fi

    remove "/Library/Application Support/XFENCE"
    remove "$NAMESPACE/XFENCE/F-Secure XFENCE Configuration.app"
    remove "/Library/LaunchDaemons/com.f-secure.XFENCE.plist"
    remove "/Library/LaunchDaemons/com.fsecure.XFENCE.plist"
    remove "/Library/LaunchAgents/com.f-secure.XFENCEUpdater.plist"
    remove "/Library/LaunchAgents/com.fsecure.XFENCEUpdater.plist"
    remove "/Library/F-Secure/XFENCE"
    remove "/Users/Shared/F-Secure XFENCE Extras"
    if ! $PARTIAL ; then
        remove "/Users/Shared/F-Secure XFENCE"
    fi

    if $isDaemonLoaded ; then
        echo "Killing xfence daemon"
        killall XFENCEDaemon || echo ok
        killall xfencedaemon || echo ok
        killall fscxfenced || echo ok
    fi

    if $xfenceKextLoaded ; then
        echo "Unloading XFENCE kext"
        kextunload -b com.f-secure.XFENCE
    fi
}

if [ $NAMESPACE_IDENTIFIER != "f-secure.mdr" ] && ! uninstall_xfence ; then
    date "+%Y-%m-%d %H:%M:%S xfence uninstall failed!"
    fatalexit "Failed to uninstall XFENCE" 2
fi

broadcast_uninstall_state "browser extension uninstall"

chromeNativeMessagingPath="/Library/Google/Chrome/NativeMessagingHosts"
firefoxNativeMessagingPath="/Library/Application Support/Mozilla/NativeMessagingHosts"
chromiumNativeMessagingPath="/Library/Application Support/Chromium/NativeMessagingHosts"

if [ -d "$NAMESPACE/browsingprotection" ] && ! ${PARTIAL} ; then

    rm -f /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.*-running

    date "+%Y-%m-%d %H:%M:%S removing browser extensions"

    if [ -d "$NAMESPACE/browsingprotection/chrome" ] ; then
        date "+%Y-%m-%d %H:%M:%S Triggering to uninstall Chrome Extension"
        touch /tmp/.com.$NAMESPACE_IDENTIFIER.fsav/uninstall
        chromeuninstallsignal="/tmp/.fs-chrome-extension-uninstall-completed-*"
        # 10 seconds time out for the use case of if user has deleted or disabled chrome extension
        timeout=$(( $(date +%s) + 10 ))
        while [ $(date +%s) -lt $timeout ] && [ -z "$(ls $chromeuninstallsignal)" ] ; do
            echo "+%Y-%m-%d %H:%M:%S Chrome extension is not uninstalled yet, waiting for uninstall complete signal"
            sleep 1
        done
        rm -fv "$chromeNativeMessagingPath/com.fsecure.browsingprotection"*"bootstrap.json"
        rm -fv "$chromiumNativeMessagingPath/com.fsecure.browsingprotection"*"bootstrap.json"
        safer_rmrf /tmp/.fs-chrome-extension-uninstall-*
    else
        date "+%Y-%m-%d %H:%M:%S no Chrome browsing protection package installed - not removing Chrome browser extensions"
    fi

    # uninstalling of firefox is by default handled by chrome uninstall as now chrome and firefox addon share same code:
    if [ -d "$NAMESPACE/browsingprotection/firefox" ] ; then
        date "+%Y-%m-%d %H:%M:%S Removing firefox extension native messaging json symlink"
        rm -fv "$firefoxNativeMessagingPath/com.fsecure.browsingprotectionbootstrap.json"
    else
        date "+%Y-%m-%d %H:%M:%S no firefox browsing protection package installed - not removing firefox extension native messaging symlink"
    fi
else
    date "+%Y-%m-%d %H:%M:%S upgrade or no browsing protection package installed - not removing browser extensions"
fi

if [ -d "/usr/local/$NAMESPACE_IDENTIFIER/browsingprotection" ] || [ -d "$NAMESPACE/browsingprotection" ] ; then
    installer_id="com.$NAMESPACE_IDENTIFIER.browsingprotection" 
    echo "Removing $installer_id from Installer's database"
    ${PKGUTIL} --forget "$installer_id"
fi

broadcast_uninstall_state "legacy chrome and firefox extension uninstall"

if [ -d "$NAMESPACE/browsingprotection" ] ; then
    date "+%Y-%m-%d %H:%M:%S removing chrome browser extensions"
    echo "Removing chrome extension for all users" >> "$MSGLOG"

    # Removing crx file from Chrome User Extension Folder
    chrome_external_extensions_dir_user="Library/Application Support/Google/Chrome/External Extensions"

    dscl . -list /Users NFSHomeDirectory|awk '{print $NF}' | sort | uniq | while read -r homedir ; do
      date "+%Y-%m-%d %H:%M:%S Deleting Chrome extension symlink for ${homedir}"
      chrome_extension_fullpath_user="${homedir}"/"${chrome_external_extensions_dir_user}"

      ls "$chrome_extension_fullpath_user" | grep -e "fcmmbkhhogkhbpijkidmocpcomnmpgif" -e "ceccehjjnpkifbmecpnmnfkkjbdknjnn" -e "idpkgibhbjmogkfbkmjnnkhpgdagoeme" | while read -r chrome_extension_id ; do
        chrome_extension_crx_user="$chrome_extension_fullpath_user"/"$chrome_extension_id"
          if [ -f "$chrome_extension_crx_user" ] ; then
              date "+%Y-%m-%d %H:%M:%S Deleting Chrome add-on symlink ${chrome_extension_crx_user}"
              rm -f "$chrome_extension_crx_user"
              touch /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstalled-chrome-extension-"${chrome_extension_id}"
          fi
      done
    done

    # Removing crx file from Chrome Global Extension Folder
    ls "/$chrome_external_extensions_dir_user" | grep -e "fcmmbkhhogkhbpijkidmocpcomnmpgif" -e "ceccehjjnpkifbmecpnmnfkkjbdknjnn" -e "idpkgibhbjmogkfbkmjnnkhpgdagoeme" | while read -r chrome_extension_id ; do
        chrome_extension_fullpath_global="/$chrome_external_extensions_dir_user/$chrome_extension_id"

        if [ -f "$chrome_extension_fullpath_global" ] ; then
            date "+%Y-%m-%d %H:%M:%S Deleting Chrome add-on from Chrome Global Extension Folder ${chrome_extension_fullpath_global}"
            rm -f "$chrome_extension_fullpath_global"
            touch /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstalled-chrome-extension-"${chrome_extension_id}"-global-folder
        fi
    done

    date "+%Y-%m-%d %H:%M:%S removing firefox browser extensions"
    echo "Removing firefox extension for all users" >> "$MSGLOG"

    firefox_application_id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
    firefox_user_extensions_folder="Library/Application Support/Mozilla/Extensions/${firefox_application_id}"

    dscl . -list /Users NFSHomeDirectory|awk '{print $NF}' | sort | uniq | while read -r homedir ; do
        date "+%Y-%m-%d %H:%M:%S Deleting Firefox extension xpi for ${homedir}"
        firefox_fullpath_user="${homedir}"/"${firefox_user_extensions_folder}"

        ls "$firefox_fullpath_user" | grep "@f-secure.com" | while read -r firefox_extension_xpi_file ; do
            firefox_extension_xpi_user="$firefox_fullpath_user"/"$firefox_extension_xpi_file"
            if [ -f "$firefox_extension_xpi_user" ] ; then
                date "+%Y-%m-%d %H:%M:%S Deleting Firefox add-on ${firefox_extension_xpi_user}"
                rm -f "$firefox_extension_xpi_user"
                touch /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstalled-firefox-extension-"${firefox_extension_xpi_file}"
            fi
        done
    done

    # Removing xpi file from Firefox Global Extension Folder
    ls "/$firefox_user_extensions_folder" | grep "@f-secure.com" | while read -r firefox_extension_xpi_file ; do
        firefox_extension_fullpath_global="/$firefox_user_extensions_folder/$firefox_extension_xpi_file"
        if [ -f "/$firefox_extension_fullpath_global" ] ; then
            date "+%Y-%m-%d %H:%M:%S Deleting Firefox add-on from Firefox Global Extension Folder ${firefox_extension_fullpath_global}"
            rm -f "$firefox_extension_fullpath_global"
            touch /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstalled-firefox-extension-"${firefox_extension_xpi_file}"-global-folder
        fi
    done
else
    date "+%Y-%m-%d %H:%M:%S no browsing protection package installed - not removing legacy browser extensions"
fi

broadcast_uninstall_state "passwordvault browser extension uninstall"

if [ -d "$NAMESPACE/passwordvault" ] && ! ${PARTIAL} ; then
    # todo: how to handle key/idp extension uninstall?

    date "+%Y-%m-%d %H:%M:%S Removing passwordvault extension native messaging manifests"
    rm -fv "$chromeNativeMessagingPath/app.fskey-chrome.json"
    rm -fv "$firefoxNativeMessagingPath/app.fskey-firefox.json"

    installer_id="com.$NAMESPACE_IDENTIFIER.passwordvault" 
    echo "Removing $installer_id from Installer's database"
    ${PKGUTIL} --forget "$installer_id"
else
    date "+%Y-%m-%d %H:%M:%S upgrade or no passwordvault browsing protection package installed - not removing passwordvault browser extensions"
fi

# Kill any remnant fscbootstrapnative processes still left running by browsers
if [ -d "$NAMESPACE/browsingprotection" ] ; then
    pkill fscbootstrapnative || echo "Failed to kill fscbootstrapnative, may not have been running"
fi

broadcast_uninstall_state "unload and remove LaunchDaemons"

# Restore firewall initial state
if ! $PARTIAL ; then
    if $NAMESPACE/bin/system_firewall_tool --restore ; then
        echo "Firewall state successfully restored"
    else 
        echo "Failed to restore initial state of system firewall"
    fi
else
    echo "Not restoring initial state of system firewall (upgrade is in progress)"
fi

daemon_plists="com.$NAMESPACE_IDENTIFIER.fsavd.dbver_update.plist \
com.$NAMESPACE_IDENTIFIER.clstate-dbupdate.plist \
com.$NAMESPACE_IDENTIFIER.clstate-periodic.plist \
com.$NAMESPACE_IDENTIFIER.fsmac.fsupdated.plist \
com.$NAMESPACE_IDENTIFIER.fsmac.fsupdated_guts2.plist \
com.$NAMESPACE_IDENTIFIER.fsavd.dbhelper.plist \
com.$NAMESPACE_IDENTIFIER.fsavd.plist \
com.$NAMESPACE_IDENTIFIER.fsmacuninstall.plist \
com.$NAMESPACE_IDENTIFIER.fsmac.licensetool.plist \
com.$NAMESPACE_IDENTIFIER.fsmac.guts2downloader.plist \
com.$NAMESPACE_IDENTIFIER.fscsafesettingsd.plist \
com.$NAMESPACE_IDENTIFIER.urlexceptiond.plist \
com.$NAMESPACE_IDENTIFIER.fscsafeadmind.plist \
com.$NAMESPACE_IDENTIFIER.uplinkdaemon.plist \
com.$NAMESPACE_IDENTIFIER.fsctelemetryd.plist \
com.$NAMESPACE_IDENTIFIER.fscesproviderd.plist \
com.$NAMESPACE_IDENTIFIER.fscreputationd.plist \
com.$NAMESPACE_IDENTIFIER.sensord.plist \
com.$NAMESPACE_IDENTIFIER.fscswupd.plist \
com.$NAMESPACE_IDENTIFIER.remote.scan_for_malware.plist \
com.$NAMESPACE_IDENTIFIER.remote.collect_fsdiag.plist \
com.$NAMESPACE_IDENTIFIER.scheduledscanning.plist"

orspplist=com.$NAMESPACE_IDENTIFIER.orspclient.plist
if [ -f "/Library/LaunchDaemons/$orspplist" ] ; then
    daemon_plists="$daemon_plists $orspplist"
fi

updatedaemon_plists="com.$NAMESPACE_IDENTIFIER.fscupdated.plist \
com.$NAMESPACE_IDENTIFIER.fscupdatedownloadd.plist"
for daemon in $updatedaemon_plists; do
    if [ -f "/Library/LaunchDaemons/$daemon" ] ; then
        daemon_plists="$daemon_plists $daemon"
    fi
done

fscunifiedfamilyrulesdplist=com.$NAMESPACE_IDENTIFIER.fscunifiedfamilyrulesd.plist
if $fscunifiedfamilyrulesd ; then
    daemon_plists="$daemon_plists $fscunifiedfamilyrulesdplist"
fi

for daemon in $daemon_plists; do
    root_unload_remove "/Library/LaunchDaemons/$daemon"
done

for ulService in $(ls -1 /Library/LaunchDaemons/com.$NAMESPACE_IDENTIFIER.ultralight*); do
    echo "Unloading ultralight service: $ulService"
    root_unload_remove "$ulService"
done

broadcast_uninstall_state "defaults delete"

release_license_with_timeout() {
    echo "Releasing subscription" >> "$MSGLOG"
    $NAMESPACE/fssp/bin/licensetool --release-me &

    time_elapsed=0
    timeout_seconds=$1
    while [ "$time_elapsed" -le "$timeout_seconds" ] ; do
        if ! pgrep licensetool; then
            echo "Successfully released subscription" >> "$MSGLOG"
            return 0
        fi
        /bin/sleep 1
        ((time_elapsed++))
    done

    return 1
}

if ! $PARTIAL ; then
    root_defaults=( com."$NAMESPACE_IDENTIFIER".fscsafeadmind )
    # PSB stores CCR token in uplinkdaemon's user defaults, and FSKit (used by uplinkdaemon) stores subscription info
    if [ -x $NAMESPACE/bin/uplinkdaemon ] && customization_parameter_enabled IS_CORPORATE ; then
        root_defaults+=( com."$NAMESPACE_IDENTIFIER".uplinkdaemon )
        root_defaults+=( uplinkdaemon )
    fi
    for domain in "${root_defaults[@]}"; do
        defaults delete "$domain"
    done
    # PSB SPI doesn't support subscription release
    if ! [ -f $NAMESPACE/fsmac/config/always_tokensignup ] ; then
        timeout_seconds=20
        if ! release_license_with_timeout $timeout_seconds; then
            echo "Subscription release call did not finish within $timeout_seconds seconds. Terminating licensetool process..." >> "$MSGLOG"
            kill %?licensetool
        fi
    fi
fi

# prefpane is not namespaced and is not available in namespaced products atm (i.e. MDR)
if [ "$NAMESPACE_IDENTIFIER" = "f-secure" ]; then
    rm -rf "/Library/PreferencePanes/Safe Anywhere Mac Settings.prefPane"
fi

# Remove infections.db for all users
/bin/rm -f /Users/*/Library/Application\ Support/$NAMESPACE_PATH/Mac\ Protection/infections.db
/bin/rm -f /tmp/infections_[0-9][0-9]*.db /tmp/.com.$NAMESPACE_IDENTIFIER.fsav/infections.db*
/bin/rm -f $NAMESPACE/fssp/var/infections/infections.db*
# Remove F-Secure directories, only if they're empty
/bin/rmdir /Users/*/Library/Application\ Support/$NAMESPACE_PATH/Mac\ Protection
/bin/rmdir /Users/*/Library/Application\ Support/$NAMESPACE_PATH

# For all non-system users, delete any defaults domain we may have created
# Do it with the "defaults" command to make sure the change is visible to all
prefdomains="com.$NAMESPACE_IDENTIFIER.fsmac.gui \
com.$NAMESPACE_IDENTIFIER.Safe-Anywhere-Mac-Settings \
com.$NAMESPACE_IDENTIFIER.fsmac.gui-main-window \
com.$NAMESPACE_IDENTIFIER.XFENCEConfiguration \
com.fsecure.XFENCEConfiguration"

clear_sandboxes_for_user() {
    sandbox_container="/Users/$1/Library/Containers"
    echo "Removing sandboxed app data in $sandbox_container"
    rm -rf "$sandbox_container/com.$NAMESPACE_IDENTIFIER.fscunifiedui"
    rm -rf "$sandbox_container/com.$NAMESPACE_IDENTIFIER.fsmac.gui"
    rm -rf "$sandbox_container/com.$NAMESPACE_IDENTIFIER.fsmac.gui.Safe-Anywhere-Mac-Safari-App-Extension"
}

dscl . list /Users uid | while read -r username uid ; do
    if [ "$uid" -ge 500 ] ; then
        if ! $PARTIAL ; then
            for domain in $prefdomains; do
                domain=$(echo "$domain" | sed -e 's/\+/ /g') # to handle domains with spaces
                date "+%Y-%m-%d %H:%M:%S Deleting defaults domain $domain for user $username ($uid)"
                # "sudo -u user" is necessary here as there is no other way to clear defaults for a specific user
                launchctl asuser "$uid" sudo -u "$username" defaults delete "$domain"

                clear_sandboxes_for_user "$username"
            done
        fi
    fi
done

broadcast_uninstall_state "Removing in /Applications"

remove_app() {
    app="$1"
    bundleid="$2"
    applicationsSubfolder="/Applications"

    # This is a workaround for MACT-4555
    if [ "$NAMESPACE_IDENTIFIER" != "f-secure" ]; then
        applicationsSubfolder="$applicationsSubfolder/$NAMESPACE_PATH"
    fi

    find "$applicationsSubfolder" -maxdepth 2 -type d -name "$app" | while read -r app_path; do
	if [ -z "$app_path" ]; then
	    echo "$app was not found. Maybe someone (re)moved it?" >> "$MSGLOG"
	    continue
	fi
	if grep "<string>${bundleid}</string>" "${app_path}/Contents/Info.plist"; then
	    :
	else
	    echo "$app_path found, but bundle id does not match $bundleid" >> "$MSGLOG"
	    continue
	fi
	if [ "$app_path" = "/Applications" ] || [ "$app_path" = "/" ]; then
	    echo "Something is wrong! Installation folder was detected as $app_path" >> "$MSGLOG"
	else
	    safer_rmrf "$app_path"
	fi
	app_parent=$(dirname "$app_path")
	if [ "$app_parent" = "/Applications" ] || [ "$app_parent" = "/" ]; then
	    echo "app parent dir $app_parent, not removing" >> "$MSGLOG"
	else
	    rmdir "$app_parent"
	fi
    done
}

if ! $PARTIAL ; then
    remove_app 'F-Secure Mac Protection.app' "com.$NAMESPACE_IDENTIFIER.fsmac.gui"
    remove_app 'Support Tool.app' "com.f-secure.fsmac.fsdiag"
    remove_app 'uninstall.app' "com.f-secure.fsmac.gui.uninstall"
fi

broadcast_uninstall_state "Removing daemons and command line tools"

if ${PARTIAL} ; then
    /usr/bin/find -d $NAMESPACE/ -type f -or -type l | /usr/bin/grep -v "guts2-datadir\|fssp/var/auth/test\|fsmac/SECL\|fsmac/sysconfig\|fsmac/substatus\|var/fsctelemetryd\|var/fate\|sensor/customer_config.json\|ultralight/var" | while read -r file ; do /bin/rm -v "$file"; done
    
    # do not remove empty folders inside ultralight/var, it is part of the ultralight configuration
    # already removed sensor folder will be fixed by the next ul release, see DRRD-17440
    /usr/bin/find -d $NAMESPACE/ -type d | /usr/bin/grep -v "fsmac/sysconfig/parentalcontrolsettings\|ultralight/var" | while read -r dir ; do /bin/rmdir "$dir"; done
else
    safer_rmrf "$NAMESPACE/"
    dscl . -delete /Groups/fsc
fi

if [ $NAMESPACE_IDENTIFIER != "f-secure.mdr" ] ; then
    /bin/rm -f /usr/local/bin/dbupdate /usr/local/bin/fsav
fi

broadcast_uninstall_state "Removing fsavd and its kext"
log_entry "$(fsav --version)"

waiting=10
while killall -0 fsavd && [ $waiting -gt 0 ]; do
    echo "fsavd still running, waiting for it to exit"
    sleep 1
    waiting=$(expr $waiting - 1)
done
if killall -0 fsavd; then
    echo "fsavd is still running, falling back to kill -9"
    killall -9 fsavd
    sleep 1
fi

remove_kext() {
    kextBundleId=$1
    kextBundleName=$2
    required=$3

    if kextstat -b "$kextBundleId" | grep -q "$kextBundleId"; then
        kextunloaded=false
        for attempt in 1 2 3 4; do
            if ! kextunload -b "$kextBundleId" ; then
                echo "Failed to unload $kextBundleId, retrying in a few seconds (attempt: $attempt)"
                sleep 3
            else
                kextunloaded=true
                break
            fi
        done
        if ! $kextunloaded ; then
            if [ "$required" == "true" ] ; then
                echo "ERROR: Failed to remove kernel extension $kextBundleId" >> "$MSGLOG"
                ERROR=true
            else
                echo "WARNING: Failed to remove kernel extension $kextBundleId, will continue" >> "$MSGLOG"
            fi
        fi
    fi
    safer_rmrf "/System/Library/Extensions/$kextBundleName"
    safer_rmrf "/Library/Extensions/$kextBundleName"
}

# MDR doesn't have any kexts/sysext yet
if [ $NAMESPACE_IDENTIFIER != "f-secure.mdr" ] ; then
    remove_kext com.$NAMESPACE_IDENTIFIER.kext.fsauth fsauth.kext true
    # TODO: with MDR response part, MACT-4423 will become a problem
    remove_kext com.f-secure.kext.nke fsnke.kext false # fsnke may fail to unload if firewall is activated
    safer_rmrf "$NAMESPACE/LegacyExtensions"
    safer_rmrf "$NAMESPACE/Extensions"
fi

version() {
    echo "$@" | awk -F. '{ printf("%d%03d%03d\n", $1,$2,$3); }'
}

if atLeastBigSur ; then
    echo "Not invalidating kextcache since kexts are not supported in this macOS version"
else
    echo "Invalidating kextcache..."
    /usr/sbin/kextcache -i / # some kexts may still be in cache after rm'ing them from /Library/Extensions
fi

broadcast_uninstall_state "Removing receipts"

${PKGUTIL} --pkgs | grep ^com.$NAMESPACE_IDENTIFIER.fsmac | grep customiz | xargs -n 1 ${PKGUTIL} --forget
ls -d /Library/Receipts/com.$NAMESPACE_IDENTIFIER.fsmac* | grep customiz | xargs rm -rf

echo $(${PKGUTIL} --pkgs | grep ^com.$NAMESPACE_IDENTIFIER.fsmac | grep -v customiz) com.$NAMESPACE_IDENTIFIER.fssp.pkg com.$NAMESPACE_IDENTIFIER.fssp com.$NAMESPACE_IDENTIFIER.agents-and-daemons.pkg com.$NAMESPACE_IDENTIFIER.agents-and-daemons | xargs -n 1 ${PKGUTIL} --forget
echo `${PKGUTIL} --pkgs | grep ^com.$NAMESPACE_IDENTIFIER.ultralight` | xargs -n 1 ${PKGUTIL} --forget

if [ -d /usr/local/$NAMESPACE_IDENTIFIER/orspclient ] || [ -d $NAMESPACE/orspclient ] ; then
    ${PKGUTIL} --forget com.$NAMESPACE_IDENTIFIER.orspclient
fi

if $sensord ; then
    ${PKGUTIL} --forget com.$NAMESPACE_IDENTIFIER.sensord
fi

if $updatedaemon ; then
    ${PKGUTIL} --forget com.$NAMESPACE_IDENTIFIER.updatedaemon.pkg
fi

if $fscunifiedfamilyrulesd ; then
    ${PKGUTIL} --forget com.$NAMESPACE_IDENTIFIER.fscunifiedfamilyrulesd.pkg
fi

if [ $NAMESPACE_IDENTIFIER != "f-secure.mdr" ] ; then
    # fsnke package is not namespaced and should be forgotten if no products using it left, MACT-4423
    ${PKGUTIL} --forget com.f-secure.fsmac.fsnke.pkg
    ${PKGUTIL} --forget com.$NAMESPACE_IDENTIFIER.xfence

    rm -rf /Library/Receipts/com.$NAMESPACE_IDENTIFIER.fsauth.*
    rm -rf /Library/Receipts/com.f-secure.fsnke.*
fi

ls -d /Library/Receipts/com.$NAMESPACE_IDENTIFIER.fsmac* | grep -v customiz | xargs rm -rf
rm -rf /Library/Receipts/com.$NAMESPACE_IDENTIFIER.fssp.*

rm -rf /tmp/.com.$NAMESPACE_IDENTIFIER.fsav
rm -f /tmp/ods-*.db
rm -f /tmp/ods-*.db.real
rm -f /Users/*/Library/Application\ Support/$NAMESPACE_PATH/Mac\ Protection/infections.db
rm -f /var/log/fsavd.log
rm -rf /Library/Caches/com.$NAMESPACE_IDENTIFIER.MacProtection.*
rm -f "$NAMESPACE_APPSUPPORT/expirytime"

echo >> "$MSGLOG"

/bin/rmdir "$NAMESPACE_APPSUPPORT/"

if ! ${PARTIAL} ; then
    echo "Removing $NAMESPACE/fsmac because partial=${PARTIAL}"
    safer_rmrf /usr/local/f-secure # there is nothing here except a hard coded var/orsp cert cache, never namespaced
    safer_rmrf /usr/local/$NAMESPACE_IDENTIFIER # /usr/local/f-secure(-mdr)/bin keeps symlinks to uninstallers in /Library/F-Secure(-mdr)/bin, MACT-5944
    safer_rmrf $NAMESPACE/fsmac
    /bin/rmdir $NAMESPACE # will be removed if empty
    echo "Removing SECL logs and application support files"
    rm -fv /Library/Logs/SECL.log*
    dscl . -list /Users NFSHomeDirectory|awk '{print $NF}' | sort | uniq | while read -r homedir; do
        for f in "${homedir}/Library/Logs/SECL.log" "${homedir}/Library/Logs/SECL.log.old" \
                 "${homedir}$NAMESPACE_APPSUPPORT/Safe Anywhere Mac/browsing-protection-settings" \
                 "${homedir}$NAMESPACE_APPSUPPORT/Safe Anywhere Mac/upstream.db" ; do
            if [ -f "$f" ] ; then
                echo "Deleting $f"
                rm -f "$f"
            fi
        done
        # Remove F-Secure app support directories, only if they're empty
        /bin/rmdir "${homedir}$NAMESPACE_APPSUPPORT/Safe Anywhere Mac/"
        /bin/rmdir "${homedir}$NAMESPACE_APPSUPPORT/"
    done
else
    echo "Not removing $NAMESPACE/fsmac because this is an upgrade"
fi

broadcast_uninstall_state "Removing Support Tool's privileged helper"

helperToolBundleID="com.f-secure.fsmac.fsdiag.helper"
root_unload_remove "/Library/LaunchDaemons/$helperToolBundleID.plist"
rm /Library/PrivilegedHelperTools/$helperToolBundleID

# Empty the contents of the magic file to prevent further accidental uninstalls.
echo >$MAGIC

if $ERROR ; then
    {
        echo "Some errors were encountered during uninstall."
        echo "Please contact support and email them the uninstall log file:"
        echo "$LOG"
        echo "Please reboot before reinstalling the product."
    } >> "$MSGLOG"

    rc=1
else
    rc=0
fi

echo $rc > /tmp/.com.$NAMESPACE_IDENTIFIER.fsmac.uninstall-rc

broadcast_uninstall_state "uninstall finished with state $rc"
rm -f "$UNINSTALL_IN_PROGRESS_FILE"

exit $rc
