#!/bin/bash

  # vpnd - Void Package Notifier Daemon
    
    #         "He who fights against (certain kinds of) daemons should beware lest 
    #          he himself becomes a daemon. And when you gaze long into the Void,
    #  	       sometimes the Void gazes also into you....
    #	             ....and sometimes you just need to update your system."
    
    # 	             (with apologies to F. Nietzsche)

    # Copyright (C) 2017-2021 Benjamin Slade

    # version: 0.2

    # LICENCE:
    # This program is free software: you can redistribute it and/or modify it under the
    # terms of the GNU General Public License as published by the Free Software
    # Foundation, either version 3 of the License, or (at your option) any later
    # version.

    # This program is distributed in the hope that it will be useful, but WITHOUT ANY
    # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
    # PARTICULAR PURPOSE. See the GNU General Public License for more details.

    # You should have received a copy of the GNU General Public License along with this
    # program. If not, see http://www.gnu.org/licenses/.

# terminal emulator:
determterm() {
    if [ -z ${preferred_terminal+x} ];
       then
    terms=(xterm urxvt konsole gnome-terminal lxterminal terminology terminator kitty alacritty tilix qterminal lilyterm cool-retro-term aminal xiate sakura)
    for t in ${terms[*]}
    do
        if [ $(command -v $t) ]
        then
            detected_term=$t
            break
        fi
    done
    echo ${detected_term}
    else
        echo ${preferred_terminal}
    fi
}

export -f determterm

# sourcing
source "/etc/vpnd.conf"
if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/vpnd/vpnd.conf" ]
then
    source "${XDG_CONFIG_HOME:-$HOME/.config}/vpnd/vpnd.conf"
fi

export void_vpnd_iconuptodate
export void_vpnd_iconneedsupdating
export void_vpnd_iconbroken

# create a FIFO file, used to manage the I/O redirection from shell
VOID_VPND_PIPE="$(mktemp -u --tmpdir "${0##*/}.XXXXXXXX")"
mkfifo "$VOID_VPND_PIPE"

# attach a file descriptor to the file
exec 3<> "$VOID_VPND_PIPE"

voidvpndblinky() {
    starttime=$(date +%s)
    while true
    do
        exec 3<> "$VOID_VPND_PIPE" >&3
        echo "tooltip:Void Package Notifier Daemon updating..."
        echo "icon:$void_vpnd_iconuptodate"
        sleep 0.5
        exec 3<> "$VOID_VPND_PIPE" >&3
        echo "icon:$void_vpnd_iconneedsupdating"
        sleep 0.5

        # timeout in case of loss of connection after check start
        if [ "$(echo $(( $(date +%s) - $starttime )))" -gt 150 ]
        then
            exec 3<> "$VOID_VPND_PIPE" >&3
            voidvpnconnectivity=0
            echo "icon:$void_vpnd_iconbroken"
            echo "tooltip:Could not contact Void package database"
           break
        fi
    done
}

#Kills the sub process quietly
voidvpndkillsub() 
{
    kill -9 "${1}" 2>/dev/null
    wait "${1}" 2>/dev/null
}


export preferred_notifier
# notification routines
void-vpnd-send-notification() {
    if ! [ "$(command -v ${preferred_notifier})" ]
    then
        echo "no"
        if [ "$(command -v notify-send)" ]
        then
            preferred_notifier="notify-send"
        elif [ "$(command -v notify-send.sh)" ]
        then
            preferred_notifier="notify-send.sh"
        else
            echo "ERROR: No notification application available. Please install 'libnotify' or 'notify-send.sh'" >&0
        fi
    fi
    ${preferred_notifier} "Void Package Notification Daemon:" "$(cat /tmp/void-pkginfo)" --icon="$current_icon"
}

export -f void-vpnd-send-notification

# define function for yad to call on left-click, forcing check updates
void-vpnd-updater() {
    echo "STARTING..."
    source "/etc/vpnd.conf"
    if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/vpnd/vpnd.conf" ]
    then
        source "${XDG_CONFIG_HOME:-$HOME/.config}/vpnd/vpnd.conf"
    fi

    # blink systray icon (if enabled)
    if [ "$display_method" -ne 1 ]
    then
        voidvpndblinky &
        voidvpndblinky_pid=$!
    fi
    
    #Add a trap incase of unexpected interruptions
    trap 'voidvpndkillsub ${voidvpndblinky_pid}; exit' INT TERM EXIT
    
    # Check to see if active internet connection
    voidvpndconnectivity=1
    ping -q -w1 -c1 kernel.org 1>/dev/null 2>&1 || \
        ping -q -w1 -c1 voidlinux.org 1>/dev/null 2>&1 || \
        ping -q -w1 -c1 google.com 1>/dev/null 2>&1 || voidvpndconnectivity=0

    if [ "$voidvpndconnectivity" = 0 ]
    then
        current_icon="$void_vpnd_iconbroken"
        pkginfo="No connection"
    else
        /usr/bin/xbps-install -Munv 2>/tmp/void-errs 1>/tmp/void-raw-data
        # grep MISSING /tmp/void-raw-data > /tmp/void-errs
        # grep breaks /tmp/void-raw-data > /tmp/void-breaks        
        # /usr/bin/xbps-install -Munv 2>&1 | grep MISSING > /tmp/void-errs
        grep breaks /tmp/void-raw-data > /tmp/void-breaks
        # /usr/bin/xbps-install -Munv 1>/dev/null 2>/tmp/stderr

        # grep broken /tmp/stderr >> /tmp/void-breaks

        # if non-null then errors
        en=$(/usr/bin/wc -l < /tmp/void-errs)
        eb=$(/usr/bin/wc -l < /tmp/void-breaks)
        
        if [ "$en" = 0 ] && [ "$eb" = 0 ] # no error
        then
	    pkginfo="" # blank pkginfo
        else # error
    	    pkginfo="!!!!ERROR!!!!\n"
            pkgcount=0
            grep 'MISSING' /tmp/void-errs > /tmp/tmpline
            grep 'broken' /tmp/void-errs > /tmp/tmpline
            grep 'breaks' /tmp/void-errs > /tmp/tmpline
	    while read -r line; do  # check each problematic pkg
	        # echo "$line" > /tmp/tmpline  # strip out each line about problem pkgs to tmp file /tmp/tmpline
	        # problem=$(cut -d' ' -f2- /tmp/tmpline | sed 's/[<>=].*//') # narrow to pkg-name in /tmp/tmpline, store in $problem
	        # pkginfo="$pkginfo $line \n     required by: $(/usr/bin/xbps-query -X "$problem")" # check what packages require problem pkg with xbps-query -X
	        pkginfo="$pkginfo $line \n"       
	    done < /tmp/tmpline
            pkginfo="$pkginfo \n * * * * * * * * * * * * * \n"
        fi
        if [ "$eb" -ne 0 ] # breaking errors
        then
	    while read -r line; do # list all breaking packages
	        pkginfo="$pkginfo $line \n"
	    done < /tmp/void-breaks
	    pkginfo="$pkginfo # # # # # # # # # # # # # \n"            
        fi

        # Cut out relevant info from all lines with "Found"
        # if [ "$show_upinst" = 1 ]
        # then
            # xbpsline="grep 'Found' /tmp/void-raw-data | cut -d' ' -f1-2 | column -t"
        # else
        xbpsline="grep 'Found' /tmp/void-raw-data | cut -d' ' -f2 | column -t"
        # fi

        if [ "$show_ver" = 0 ]
        then
            xbpsline="$xbpsline | sed -e 's/\-[0-9\.]*_[0-9]*$//g'"
        fi

        # output packages to void-pkgs 
        xbpsline="$xbpsline > /tmp/void-pkgs"
        
        # run xbps-install -Munv with options
        bash -c "$xbpsline"
                
        # count packages needing updating
        n=$(/usr/bin/wc -l < /tmp/void-pkgs)
        # set last checked timestamp
        d="$(stat /tmp/void-pkgs|grep Access|grep 20|sed 's/\..*$//'|sed 's/Access: /Last checked: /')"
        # pkgcount=0
        while read -r line; do
            ((pkgcount=pkgcount+1))
            if [ "$pkgcount" -lt 34 ]
            then            
                pkgs="$pkgs\n $line"
            fi
        done < /tmp/void-pkgs
        if [ "$n" -gt 34 ] # don't overflow the mouseover
        then
            pkgs="$pkgs\n ...(and $(($n-34)) others)..."
        fi
        if [ "$en" -ne 0 ] || [ "$eb" -ne 0 ] # if errors
        then
            pkginfo="$pkginfo \n $n packages need updating \n --------------------------- $pkgs \n --------------------------- \n [$d]"            
            current_icon="$void_vpnd_iconbroken"
        elif [ "$n" -eq 0 ] # no new pkgs
        then
	    pkginfo="all packages up-to-date \n --------------------------- \n [$d]"            
            current_icon="$void_vpnd_iconuptodate"
        elif [ "$n" -eq 1 ] # 1 new pkg
        then
	    pkginfo="$n package needs updating: \n --------------------------- $pkgs \n --------------------------- \n [$d]"            
            current_icon="$void_vpnd_iconneedsupdating"
        else # >1 new pkgs
	    pkginfo="$n packages need updating:  \n --------------------------- $pkgs \n --------------------------- \n [$d]"            
            current_icon="$void_vpnd_iconneedsupdating"
        fi
    fi

    # make pkginfo available
    echo "$pkginfo" > /tmp/void-pkginfo
    # update systray (if enabled)
    if [ "$display_method" -ne 1 ]
    then
        voidvpndkillsub ${voidvpndblinky_pid}
	exec 3<> "$VOID_VPND_PIPE" >&3
        echo "icon:$current_icon"
        echo "tooltip:$pkginfo" # set mouse-over to relevant pkginfo
    fi
    
    # show notification (if enabled)
    if [ "$display_method" -ne 0 ]
    then
        if [ "$current_icon" != "$void_vpnd_iconuptodate" ] || [ "$show_no_up_notif" -eq 1 ]
        then
            void-vpnd-send-notification
        fi
    fi
    trap 'voidvpndkillsub ${voidvpndupdater_pid}; exit' INT TERM EXIT
}

# add handler function to manage process shutdown
on_exit() {
    echo "quit" >&3
    rm -f "$VOID_VPND_PIPE"
}
trap on_exit EXIT

# export needed things
export VOID_VPND_PIPE

# save out functions
export -f void-vpnd-updater
export -f voidvpndblinky
export -f voidvpndkillsub

# handle left-click
# handle right-click
if [ "$VPND_LEFTCLICK" = "" ]
then
    VPND_LEFT=" "
else
    VPND_LEFT=" --command=${VPND_LEFTCLICK} "
fi


# handle middle-click
if [ "$void_vpnd_quit_on_middle" -ne 1 ]
then
    VPND_MIDDLE=" --no-middle "
else
    VPND_MIDDLE=" "
fi

# handle right-click
if [ "$VPND_RIGHTCLICK_MENU" = "" ]
then
    VPND_RIGHT=" "
else
    VPND_RIGHT=" --menu=${VPND_RIGHTCLICK_MENU} "
fi

# summon yad systray icon (if enabled)
if [ "$display_method" -ne 1 ]
then
    if [ "$(command -v yad)" ]
    then # kill running update process and then run updater again
        yad --notification "$(echo $VPND_LEFT)" ${VPND_MIDDLE} "$(echo $VPND_RIGHT)" --image="icon:$void_vpnd_iconuptodate" --text="Void Package Notifier Daemon initialising..." --listen <&3 &
    else
        echo "ERROR: The application 'yad' is not available for systray display. Please run 'xbps-install yad'." >&0
                if [ "$(command -v notify-send)" ]
                then
                    notify-send "Void Package Notification Daemon:" "ERROR: The application 'yad' is not available for systray display. Please run 'xbps-install yad'." --icon="$void_vpnd_iconbroken"
                elif [ "$(command -v notify-send.sh)" ]
                then
                    notify-send.sh "Void Package Notification Daemon:" "ERROR: The application 'yad' is not available for systray display. Please run 'xbps-install yad'." --icon="$void_vpnd_iconbroken"
                fi
    fi
fi

# initial notification
if [ "$display_method" -ne 0 ] && [ "$initial_notify_suppress" -ne 1 ]
then
    if ! [ "$(command -v ${preferred_notifier})" ]
       then
           if [ "$(command -v notify-send)" ]
           then
               notify-send "Void Package Notification Daemon:" "Initialising..." --icon="$void_vpnd_iconuptodate"
           elif [ "$(command -v notify-send.sh)" ]
           then
               notify-send.sh "Void Package Notification Daemon:" "Initialising..." --icon="$void_vpnd_iconuptodate"
           else
               echo "ERROR: No notification application available. Please install 'libnotify' or 'notify-send.sh'" >&0
           fi
    fi
fi


# call void-vpnd-updater function for first time, getting initial values 
bash -c void-vpnd-updater
voidvpndupdater_pid=$!

# loop to update every N seconds
while true
do
    sleep "${void_vpnd_cycletime}"  	# wait 30 minutes (N=1800 secs)
    bash -c void-vpnd-updater
done

# ,,Wer mit Ungeheuern kaempft, mag zusehn, dass er nicht dabei zum Ungeheuer wird. Und
#   wenn du lange in einem Abgrund blickst, blickt der Abgrund auch in dich hinein.''
#				   --Friedrich Nietzsche, _Jenseits von Gut und Boese_ no. 146
