#!/bin/bash

# Copyright Jean-Philippe Guillemin <h1p8r10n@yandex.com>. 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 2 of the License, or (at your option)
# any later version. Please take a look at http://www.gnu.org/copyleft/gpl.htm
#
# Netpkg is a tool for easily install or upgrade packages via the network. With Netpkg,
# you can make a minimal installation of Zenwalk Linux and install/upgrade just the
# packages you need the most.
#
#


version="7.3"
zenwalk_version="$(cat /etc/zenwalk-version)"

# Globals #####################################
export LANG=en_US
export configfile="/etc/netpkg.conf"
export PATH="/usr/libexec:/sbin:/bin:/usr/sbin:/usr/bin"

. /etc/shell-colors



# Parsing config files ######################################

netpkgdir=$(sed -n 's/^[ \t]*Netpkg_dir[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export netpkgdir="${netpkgdir:=/var/netpkg}"

# create the netpkgdir directory 
mkdir -p $netpkgdir 2>/dev/null

sources_list=$(sed -n 's/^[ \t]*Source[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export sources_list

local=$(sed -n 's/^[ \t]*Local_repository[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export local="${local:=/var/packages}"

packagelogs=$(sed -n 's/^[ \t]*Package_logs[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export packagelogs="${packagelogs:=/var/log/packages}"

blacklist="$(sed -n 's/^[ \t]*Black_list[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)"
export blacklist="${blacklist:=aaa_base}"

keepit=$(sed -n 's/^[ \t]*Keep_packages[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export keepit="${keepit:=yes}"

untouchable=$(sed -n 's/^[ \t]*Protected_files[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export untouchable="${untouchable:=/etc/lilo.conf /boot/grub/grub.cfg /etc/fstab}"

dependencies=$(sed -n 's/^[ \t]*Handle_dependencies[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export dependencies="${dependencies:=yes}"

export http_proxy=$(sed -n 's/^[ \t]*Proxy_Socket[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export proxyusr=$(sed -n 's/^[ \t]*Proxy_User[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export proxypwd=$(sed -n 's/^[ \t]*Proxy_Password[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
export WGET="wget"
[ "$proxyusr" ] && export WGET="wget --proxy-user=${proxyusr} --proxy-password=${proxypwd}"

logfile=$(sed -n 's/^[ \t]*Logfile[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
if [ "$logfile" == "none" ]; then
	export logfile="/dev/null"
else
	export logfile="${logfile:=/var/log/netpkg.log}"
fi

mill[0]="|" ; mill[16]="/" ; mill[32]="-" ; mill[48]="\\"

# fetch the packages list for available packages
GetRemotePkgList(){
	cat $netpkgdir/RemoteAndLocalPkgList | sort | sed -e 's/^[^|]* *| *\([^|]*.t[glx]z\) *| .*$/\1/'
}

# fetch the packages list for available packages
GetRemotePkgListbycat(){
	cat $netpkgdir/RemotePkgList | sort | sed -n "s/^\($1\) \(.*.t[glx]z\)$/\2/p"
}

# fetch the packages list for package named $1
GetPkgFromShortName(){
	cut -d " " -f2 $netpkgdir/RemotePkgList | sed -n "s/^\($1-[^\-]*-[^\-]*-[^\-]*\.t[glx]z\)$/\1/p" 
}

# Get the category for package $1
GetCategoryFromPkg(){
	category="$(sed -n "s/^\([^ \t]*\)[ \t]*$1[ \t]*$/\1/p" $netpkgdir/RemotePkgList)"
	if [[ "$category" ]] ; then
		echo -n "$category"
	else
		echo -n "local"
	fi
}

# Build a list of installed packages
BuildLocalPkgList(){
	rm -f $netpkgdir/LocalPkgList
	for meta in $(ls $packagelogs) ; do 
		# package="$(sed -n 's/^[ \t]*PACKAGE LOCATION:[ \t]*\(.*\)[ \t]*$/\1/p' $packagelogs/$meta)"
		# echo ${package##*/} >> $netpkgdir/LocalPkgList
		echo $meta.txz >> $netpkgdir/LocalPkgList
	done
}

# The main list <available> | <installed>
BuildRemoteAndLocalPkgList(){
	rm -f $netpkgdir/RemoteAndLocalPkgList
	listbuilder -a $netpkgdir/RemotePkgList -i $netpkgdir/LocalPkgList | sort > $netpkgdir/RemoteAndLocalPkgList
}

# Download and process the meta file 
FetchRepository(){
	
	source="$(tail -n1 $netpkgdir/last_source)"
	echo "Cleaning cache"
	rm -f $netpkgdir/descfile
	rm -f $netpkgdir/RemotePkgList
	rm -f $netpkgdir/PACKAGES.TXT*
	
	echo -e "Connecting to $source..."	
	
	neterror=$($WGET --no-check-certificate -O $netpkgdir/PACKAGES.TXT.gz $source/PACKAGES.TXT.gz 2>&1 | grep -E "failed:|Not Found")
	if [ "$neterror" ] ; then
		neterror=$($WGET --no-check-certificate -O $netpkgdir/PACKAGES.TXT $source/PACKAGES.TXT 2>&1 | grep -E "failed:|Not Found")
		if [ "$neterror" ] ; then
			echo "Unable to connect to $source, please check the network or choose another source" 
			return 1
		fi
	else
		echo "Uncompressing meta information"
		if ! gunzip -f $netpkgdir/PACKAGES.TXT.gz 2>/dev/null ; then 
			echo "Unable to extract meta information, please check the network or choose another source"
			return 1
		fi
	fi
	# cleaning PACKAGE SOURCE: lines
	sed -i '/^PACKAGE MIRROR:.*/d' $netpkgdir/PACKAGES.TXT
	
	if [ "$dependencies" = "yes" ] ; then 
		echo "Computing packages dependencies"
		sed -n '
		/^PACKAGE NAME:.*/{
		N;N;N;N
		s/,/ /g
		s/^PACKAGE NAME:[ \t]*\(.*\)-[^-]*-[^-]*-[^-]*\.t[glx]z[ \t]*\n.*\nPACKAGE SIZE (compressed):[ \t]*\(.*\)\nPACKAGE SIZE (uncompressed):[ \t]*\(.*\)\nPACKAGE REQUIRED:[ \t]*\(.*\)/\1:\4/p
		}' \
		$netpkgdir/PACKAGES.TXT > $netpkgdir/RemoteDeps
	fi

	#echo "Computing packages descriptions"
	#sed -n '
	#/^PACKAGE NAME:.*/{
	#N;N;N;N;N;N;N;N
	#s/^PACKAGE NAME:[ \t]*\(.*\)-[^-]*-[^-]*-[^-]*\.t[glx]z[ \t]*\n.*\nPACKAGE SIZE (compressed):[ \t]*\(.*\)\nPACKAGE SIZE (uncompressed):[ \t]*\(.*\)\nPACKAGE REQUIRED:[ \t]*\(.*\)\n.*\n.*\n.*\n[^ \t]*:[ \t]*\(.*\)/\1: Description :	\5\n\1: Compressed :	\2\n\1: Uncompressed :	\3\n\1: Dependencies :	\4/p
	#}' $netpkgdir/PACKAGES.TXT > $netpkgdir/descfile 
		
		
	echo "Creating packages list"
	sed -n '/^PACKAGE NAME:.*/{ N; s/^PACKAGE NAME:[ \t]*\(.*\.t[glx]z\)[ \t]*\nPACKAGE LOCATION:.*\/\([a-zA-Z0-9]*\)$/\2 \1/p }' \
		$netpkgdir/PACKAGES.TXT > $netpkgdir/RemotePkgList
		
		
	echo "Getting local packages list"
	BuildLocalPkgList		


	echo "Computing packages status"
	BuildRemoteAndLocalPkgList
		
	# Generating a report
	echo -e "Synchronization successful"
	echo ""
}


# take a look at local packages list to see which version of the $1 package installed
GetLocalForRemotePkg(){
	sed -n "s/^\($1-[^\-]*-[^\-]*-[^\-]*\.t[glx]z\)$/\1/p" $netpkgdir/LocalPkgList
}


# Download ($category $package) 
download(){
		
	source="$(tail -n1 $netpkgdir/last_source)"
	
	[ "$(echo $package | egrep ".*\.tlz$")" ] && ZIP="lzma"
	[ "$(echo $package | egrep ".*\.txz$")" ] && ZIP="lzma"	
	[ "$(echo $package | egrep ".*\.tgz$")" ] && ZIP="gzip"
	
	if [[ -e $local/$1/$2 && ! "$($ZIP -tv $local/$1/$2 2>&1 | egrep -e "corrupt|invalid")" ]]; then
		echo -e "${BOLDWHITE}Nothing to do, $2 is already in local cache ${COLOR_RESET}"	
		return
	else
		echo -e "${BOLDWHITE}Downloading $2 ${COLOR_RESET}"	
		
		mkdir -p $local/$1 2>/dev/null
		rm -f $local/$1/$2 2>/dev/null	 
		
		# we need to get an encoded URL if any
		# url=$($WGET -O- -q $source/$1/ \
		#| grep ".*\.t[glx]z<\/[a|A]>" \
		#| grep "$2" \
		#| sed -e "s/^.*<\(a\|A\) \(href\|HREF\)=\"\(.*\.t[glx]z\)\">.*/\3/")
	
		url="${source}/${1}/${2}"
	
		# check if we've got an absolute URL :(
		if [ $( echo "$url" | egrep -e "ftp:.*|http:.*|https:.*" ) ]; then
			$WGET -c --no-check-certificate -O $local/$1/$2 $url 
		else
			$WGET -c --no-check-certificate -O $local/$1/$2 $source/$1/$url 
		fi
	fi
	
	
}


# Checks for configuration files to update.
CheckDotNew(){
	actionlist="differences yes no remove"
	echo "Checking for configuration files to update..."
	dotnewlist="$(find /etc -name "*.new")"
	if [ "$dotnewlist" ] ; then 
		for file in $dotnewlist ; do
		origfile="$(echo $file|sed -e 's/.new//')"
		[ "$(echo $untouchable | grep $origfile)" ] && continue
		echo "Should we move $file to $origfile ?"
		select action in $actionlist exit ; do
			case $action in
			'yes')
				cp -f $file $origfile
				rm -f $file
				break
				;;
			'differences')
				if [ -e $origfile ] ; then
				diff -dU 1 $origfile $file | most
				else
				echo "$file is the only one, no $origfile yet"
				fi 
				;;
			 'no')
				break
				;;
			 'remove')
				rm -f $file
				break
				;;
			 'exit')
				exit
			esac
		done
		done
	else
	echo "No \".new\" configuration files on the system"
	fi
}


# Choose a download location from sources available in config file
SetSource(){
	source="$(tail -n1 $netpkgdir/last_source 2>/dev/null)" 
	echo -e "Current source is : ${BOLDWHITE}$source ${COLOR_RESET}"
	if [ "$sources_list" ] ; then
		echo "Please choose a source :"
		select newsource in $sources_list exit ;do 
			[[ "$newsource" == "exit" ]] && exit
			[ "$newsource" ] && source="$newsource"
			break
		done
		
		# Entry format checking
		if [ ! "$(echo $source | egrep 'http://|ftp://|https://')" ] ; then
		[ "$source" ] && echo -en "${BOLDWHITE}Bad syntax in url to source $source${COLOR_RESET}" 
		else
		mkdir -p $netpkgdir
		echo "$source" > $netpkgdir/last_source
		sourcehash="$(echo "$source" | md5sum | cut -d " " -f 1)"
		fi
	fi
	source="$(tail -n1 $netpkgdir/last_source 2>/dev/null)" 		

	echo -e "New source is : ${BOLDGREEN}$source ${COLOR_RESET}"
}

# Disable source in netpkg.conf
DisableSource(){

	if [ "$sources_list" ] ; then
		echo "Which source do you want to delete? :"
		select source in $sources_list exit ;do 
			[[ "$source" == "exit" ]] && exit
			sed -i "s|.*\($source\).*|# Source = \1|" $configfile
			break
		done
	fi	

	echo -e "${BOLDGREEN}$source${COLOR_RESET} has been disabled"
}

# Disable source in netpkg.conf
EnableSource(){

	disabledsources_list=$(sed -n 's/^#[ \t]*Source[ \t]*=[ \t]*\(.*\)$/\1/p' $configfile)
	
	if [ "$disabledsources_list" ] ; then
		echo "Which source do you want to enable? :"
		select source in $disabledsources_list exit ;do 
			[[ "$source" == "exit" ]] && exit
			sed -i "s|.*\($source\).*|Source = \1|" $configfile
			break
		done
	fi	

	echo -e "${BOLDGREEN}$source${COLOR_RESET} has been enabled"
}

# Disable source in netpkg.conf
AddSource(){

	if [ "$1" ] ; then
		if [ ! "$(echo $1 | egrep 'http://|ftp://|https://')" ] ; then
			[ "$1" ] && echo -e "${BOLDWHITE}Bad syntax in url to source $source${COLOR_RESET}" 
			exit
		else
			if [[ "$( grep "$1" $configfile )" ]]; then
				sed -i "s|.*\($1\).*|Source = \1|" $configfile
				exit
			fi
			echo "Source = $1" >> $configfile
			mkdir -p $netpkgdir ; echo "$1" > $netpkgdir/last_source
			sourcehash="$(echo "$2" | md5sum | cut -d " " -f 1)"
		fi
	else
		echo "you forgot the URL... ;)"
		exit
	fi	

	echo -e "${BOLDGREEN}$1${COLOR_RESET} has been configured"
}

# prompt for action (install / upgrade / reinstall / download) for a list of packages ($1) #########################
SearchAndPrompt(){

	echo "Searching ..."

	# this variable will track for packages installed as dependecies
	processedlist=''

	echo -n "" > $netpkgdir/.buffer

	if [[ "$*" ]] ; then
		for pattern in $* ; do
			sed -n "/$pattern/{p;q}" $netpkgdir/LocalPkgList > $netpkgdir/.buffer
			GetRemotePkgList | grep -E "$pattern" >> $netpkgdir/.buffer
		done
	else
		cat $netpkgdir/LocalPkgList > $netpkgdir/.buffer
		GetRemotePkgList >> $netpkgdir/.buffer
	fi

	for package in $(cat $netpkgdir/.buffer) ; do

		[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
		
		# If we find the package in this list then it's already processed
		[ "$(echo "$processedlist" | grep "$package")" ] && continue

		# the software name
		shortname=${package%-*}; shortname=${shortname%-*}; shortname=${shortname%-*} 

		# We need to find the category for $package
		category=$(GetCategoryFromPkg $package)

		# take a look in the blacklist 
		if [ "$(echo $blacklist | grep "$shortname ")" ]; then
			processedlist="${processedlist} $package"
			[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			continue
		fi	

		# do we have this package installed in ANY version ?
		localpkg="$(GetLocalForRemotePkg $shortname)"
		
		allowed=""
		
		# do we have this package installed in the exact version ?
		if [ -e $packagelogs/${package%.*} ]; then
			if [ -n "$(echo "$filter" | grep 'I')" ]; then
				desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $packagelogs/${package%.*} )"
				[[ "$desc " == " " ]] && desc="installed"
				echo -en "${BOLDBLUE}[I][$category]${COLOR_RESET}"
				echo -n "$package"
				echo " ($desc)"	
				allowed="remove"
				[[ "$category" != "local" ]] && allowed="$allowed reinstall"
				processedlist="${processedlist} $package"
			else
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			fi
		# so it's installed in another version
		elif [ "$localpkg" ]; then
			
			if [ "$(vfilter -u -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then
				if [ -n "$(echo "$filter" | grep 'U')" ]; then
					desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $netpkgdir/PACKAGES.TXT)"
					echo -en "${BOLDRED}[U][$category]${COLOR_RESET}"
					echo -n "$package"
					echo " ($localpkg is installed)"
					allowed="install download remove"
					processedlist="${processedlist} $package"
				else
					[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
				fi				
			elif [ "$(vfilter -d -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then
				if [ -n "$(echo "$filter" | grep 'D')" ]; then
					desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $netpkgdir/PACKAGES.TXT)"
					echo -en "${BOLDYELLOW}[D][$category]${COLOR_RESET}"
					echo -n "$package"
					echo " ($localpkg is installed)"
					allowed="install download remove"	
					processedlist="${processedlist} $package"
				else
					[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
				fi							
			fi
				
		else
			if [ -n "$(echo "$filter" | grep 'N')" ]; then
				desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $netpkgdir/PACKAGES.TXT)"
				[[ "$desc " == " " ]] && desc="installed"
				echo -en "${BOLDCYAN}[N][$category]${COLOR_RESET}"
				echo -n "$package"
				echo " ($desc)"	
				allowed="install download"
				processedlist="${processedlist} $package"
			else
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			fi	
		fi
		if [[ "$allowed " != " " ]] ; then
			actionlist="$allowed skip exit"
			echo " what should I do ?"
			select action in $actionlist ; do
				case $action in
					'install')
						AutoInstall $package
						break
						;;
					'download')
						download $category $package
						break
						;;
					'remove')
						removepkg $package
						break
						;;
					'reinstall')
						AutoInstall $package
						break
						;;
					'skip')
						echo "Skipping [$category] $package"
						echo
						break
						;;
					'exit')
						exit
						
				esac
			done
		fi
	done

}


# Check deps , then Install / Reinstall / Upgrade a list of packages
# The full and exact package name MUST be provided
AutoInstall() {	

if [ "$*" ]; then 

	finallist='' 
	
	# We need an up to date list of installed packages
	BuildLocalPkgList	
	
	for package in $* ; do
	
		# the software name
		shortname=${package%-*}; shortname=${shortname%-*}; shortname=${shortname%-*} 
				
		# take a look in the blacklist 
		if [ "$(echo $blacklist | grep "$shortname ")" ]; then
			continue
		fi	

		finallist="${finallist} $package"
		
		if [ "$dependencies" == "yes" ] ; then
			
			deps="$(grep "^$shortname:.*$" $netpkgdir/RemoteDeps | cut -s -d ":" -f 2-)"
			[ ! "$deps" ] && "$(grep "^$shortname:.*$" $netpkgdir/DepsDB | cut -s -d ":" -f 2-)"
			[ ! "$deps" ] && continue
			
			for dep in $deps ; do
			
				# We need to find package for $dep ($dep is the short name)
				deppackage="$(sed -n "s/^.*[ \t]\($dep-[^\-]*-[^\-]*-[^\-]*.t[glx]z\)[ \t]*$/\1/p" $netpkgdir/RemotePkgList)"
				[ ! "$deppackage" ] && continue		
			
				# If it's already in the list, then skip	
				[ "$(echo $finallist | grep "$deppackage" )" ] && continue
	 
				# Do we have it installed ? then skip
				[ -e $packagelogs/${deppackage%%.t[glx]z} ] && continue

				# Is it a downgrade ? then skip
				## [ "$(vfilter -d -f $netpkgdir/RemoteAndLocalPkgList -q $deppackage)" ] && continue		 

				# take a look in the blacklist 
				if [ "$(echo $blacklist | grep "$dep ")" ]; then
					continue
				fi	
				finallist="${finallist} $deppackage"
				prompt="yes"
			done	 
		fi
	done
	
	if [[ "$prompt" == "yes" ]] ; then
		prompt=''
		echo "We are about to install the following packages : continue ?"
		echo -e "-> ${BOLDWHITE}${finallist}${COLOR_RESET}"
		select action in yes skip ; do
			case $action in
				yes)
					break
					;;
				skip)
					finallist=''
					break
			esac
		done
	fi
	
	for package in $finallist ; do

		# We need to find the category for $package
		category=$(GetCategoryFromPkg $package)

		# the software name
		shortname=${package%-*}; shortname=${shortname%-*}; shortname=${shortname%-*} 

		# do we have this package installed in ANY version ?
		localpkg="$(GetLocalForRemotePkg $shortname)"

		# download the package if needed
		download $category $package
		
		# Failed to download ?
		if [[ ! "$(cat $local/$category/$package)" || ! -e $local/$category/$package ]] ; then
			echo "[F] $local/$category/$package $(date)" >> $logfile
			echo "Failed to download $package, please checkout another source : skipping"
			continue
		fi
		
	[ "$(echo $package | egrep ".*\.tlz$")" ] && ZIP="lzma"
	[ "$(echo $package | egrep ".*\.txz$")" ] && ZIP="lzma"
	[ "$(echo $package | egrep ".*\.tgz$")" ] && ZIP="gzip"
	
		# check package integrity
		if [ "$($ZIP -tv $local/$category/$package 2>&1 | egrep -e "corrupt|invalid")" ]; then
			echo "$package is corrupted, please checkout another source : skipping"
			rm -f $local/$category/$package 2>/dev/null
			continue
		fi
		
		if [ -e $packagelogs/${package%.*} ]; then
			echo -n "Reinstalling"
			echo -e "${BOLDBLUE} [$category]$package${COLOR_RESET}"
			upgradepkg --reinstall $local/$category/$package 
			echo "[U] $local/$category/$package $(date)" >> $logfile
		elif [ "$(vfilter -u -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then
			echo -n "Upgrading"
			echo -e "${BOLDRED} [$category]$package${COLOR_RESET}"
			upgradepkg $local/$category/$package
			echo "[U] $local/$category/$package $(date)" >> $logfile
		elif [ "$(vfilter -d -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then
			echo -n "Downgrading"
			echo -e "${BOLDYELLOW} [$category]$package${COLOR_RESET}"
			upgradepkg $local/$category/$package	
			echo "[U] $local/$category/$package $(date)" >> $logfile	
		else
			echo -n "Installing"
			echo -e "${BOLDCYAN} [$category]$package${COLOR_RESET}"
			installpkg $local/$category/$package
			echo "[I] $local/$category/$package $(date)" >> $logfile
		fi
		
		# remove package if we don't want to keep it
		if [ ! "$keepit" = "yes" ]; then
			rm -f $local/$category/$package 2>/dev/null
		fi
		
		# We need an up to date list of installed packages
		BuildLocalPkgList
		
	done
fi
}




# GetAll ###############################################
GetAll() {
	echo "Connecting to the packages repository..."
	echo
	for package in $(GetRemotePkgList) ; do

		if [ "$package" ]; then
		
			# We need to find the category for $package
			category=$(GetCategoryFromPkg $package)
			
	
			if [[ ! "$( echo "$* " | grep "$category " )" && "$*" != "" ]] ; then
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
				continue
			fi		 
			
			download $category $package
			
		fi
	done


}


# upgrade the whole system ###############################################
UpdateAll() {
	
	rm -f $netpkgdir/.buffer 2>/dev/null
	
	if [[ "$1" ]] ; then
		GetRemotePkgListbycat $1 > $netpkgdir/.buffer
	else
		GetRemotePkgList > $netpkgdir/.buffer
	fi
	
	echo "Searching for updates ..."	
	for package in $(cat $netpkgdir/.buffer) ; do
			
			# We need to find the category for $package
			category=$(GetCategoryFromPkg $package)				 

			# the software name
			shortname=${package%-*}; shortname=${shortname%-*}; shortname=${shortname%-*} 
			
			# do we have this package installed in ANY version ?
			localpkg="$(GetLocalForRemotePkg $shortname)"
			
			if [ -e $packagelogs/${package%.*} ]; then
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
				continue
			
			elif [ -n "$localpkg" ]; then
								
				# take a look in the blacklist 
				if [ "$(echo $blacklist | grep "$shortname ")" ]; then
					[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
					continue
				fi						 

				# If we reached this point then this package needs to be upgraded				
				if [ "$(vfilter -u -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then 
									
					finallist="${finallist} $package"
					
				fi
			fi
		[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
	done
	
	export prompt="yes"
	AutoInstall "$finallist"

}


# list packages from repository #########################
FilterListPkg() {
	
	processedlist=''
	
	echo -n "" > $netpkgdir/.buffer
	
	if [[ "$1" == "local" ]] ; then
		[[ -n "$(echo "$filter" | grep 'I')" ]] && cat $netpkgdir/LocalPkgList > $netpkgdir/.buffer
	elif [[ "$1" ]] ; then
		GetRemotePkgListbycat $1 > $netpkgdir/.buffer
	else
		[[ -n "$(echo "$filter" | grep 'I')" ]] && cat $netpkgdir/LocalPkgList > $netpkgdir/.buffer
		GetRemotePkgList >> $netpkgdir/.buffer
	fi
	echo "Searching ..."
	for package in in $(cat $netpkgdir/.buffer) ; do
		[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
		# the software name
		shortname=${package%-*}; shortname=${shortname%-*}; shortname=${shortname%-*} 
		
		# If we find the package in this list then it's already processed
		[ "$(echo "$processedlist" | grep "$package")" ] && continue
	
		# We need to find the category for $package
		category=$(GetCategoryFromPkg $package)

		# take a look in the blacklist 
		if [ "$(echo $blacklist | grep "$shortname ")" ]; then
			if [ -n "$(echo "$filter" | grep 'I')" ]; then
				desc="blacklisted"
				echo -n "[X][$category]" 
				echo -n " $package"
				echo " $desc"
			else
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			fi
			processedlist="${processedlist} $package"
			continue
		fi	

		# do we have this package installed in ANY version ?
		localpkg="$(GetLocalForRemotePkg $shortname)"
		
		# do we have this package installed in the exact version ?
		if [ -e $packagelogs/${package%.*} ]; then
			if [ -n "$(echo "$filter" | grep 'I')" ]; then
				desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $packagelogs/${package%.*} )"
				[[ "$desc " == " " ]] && desc="installed"
				echo -en "${BOLDBLUE}[I][$category]${COLOR_RESET}" 
				echo -en " $package"
				echo " $desc"
				processedlist="${processedlist} $package"		 
			else
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			fi
		# so it's installed in another version
		elif [ -n "$localpkg" ]; then
			if [ -n "$(echo "$filter" | grep 'U')" ]; then		
				if [ "$(vfilter -u -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then
					desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $netpkgdir/PACKAGES.TXT)"
					echo -en "${BOLDRED}[U][$category]${COLOR_RESET}"
					echo -en " $package"
					echo " $desc"
					processedlist="${processedlist} $package"
				fi
			else
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			fi
			if [ -n "$(echo "$filter" | grep 'D')" ]; then
				if [ "$(vfilter -d -f $netpkgdir/RemoteAndLocalPkgList -q $package)" ]; then
					desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $netpkgdir/PACKAGES.TXT)"
					echo -en "${BOLDYELLOW}[D][$category]${COLOR_RESET}"
					echo -en " $package"
					echo " $desc"	
					processedlist="${processedlist} $package"		
				fi		
			else
				[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
			fi
		else
			if [ -n "$(echo "$filter" | grep 'N')" ]; then
				desc="$(sed -n "/$shortname:\(.*\)/{p;q}" $netpkgdir/PACKAGES.TXT)"
				[[ "$desc " == " " ]] && desc="installed"
				echo -en "${BOLDCYAN}[N][$category]${COLOR_RESET}" 
				echo -en " $package"
				echo " $desc"	
				processedlist="${processedlist} $package"
				else
					[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))
				fi
		fi
		[[ "${mill[$pos]}" != "" ]] && printf "\e[31m%s\e[0m\b" "${mill[$pos]}" ; ((rotation++)) ; pos=$(( $rotation % 64 ))		
	done

}


# File protector function ######################################
protect() {
	# we backup all critical files as .old
	for protectedfile in $untouchable ; do
		[ -e $protectedfile ] && cp -f $protectedfile $protectedfile.old 2>/dev/null
	done
}

# File unprotector function 
unprotect() {
# delete backuped files in case it's the same OR no newer was added
for protectedfile in $untouchable ; do
	if [ -e $protectedfile ]; then
		newfile="$protectedfile"
		oldfile="$newfile.old"
		# clean up the redundant copy
		if [ "$(cat $oldfile 2>/dev/null | md5sum)" = "$(cat $newfile 2>/dev/null | md5sum)" ]; then
			rm $oldfile 2>/dev/null
		fi
	fi
	# Otherwise, we leave the .old copy for root to consider...
done

}

# Final cleanup ######################################
cleanup(){
	# We delete unchanged protected files or keep the old backuped one
	unprotect
	echo -e "Bye ${BOLDRED};)${COLOR_RESET}"
	echo
	exit 0
}

# remove the netpkgdired files on any type of exit
trap 'cleanup' TERM INT EXIT

# main( :) #########################

# We always need an up to date list of installed packages
BuildLocalPkgList

# Some fun :)
baneer() {
echo -en "${BOLDRED}"
echo "      _  __      __         __        ";
echo "     / |/ /___  / /_ ___   / /__ ___  ";
echo "    /    // -_)/ __// _ \ /  '_// _ \ ";
echo "   /_/|_/ \__/ \__// .__//_/\_\ \_, / ";
echo "                  /_/          /___/  ";
echo -e "${COLOR_RESET}"
}
# CLI howto ###############################################

usage() {

	echo -e "Commands are :"
	echo -e " ${BOLDWHITE}netpkg pattern1 [pattern2 ...]${COLOR_RESET} : Match pattern(s) and prompt for action"
	echo -e "    (actions can be : install, remove, reinstall, download)"	
	echo -e " ${BOLDWHITE}netpkg update|-u ${COLOR_RESET} : Prompt user for all \"updatable\" packages)"
	echo -e " ${BOLDWHITE}netpkg all|-a [category] ${COLOR_RESET} : list all packages in category (ie : xap)"
	echo -e "    (category specification is optional)"
	echo -e " ${BOLDWHITE}netpkg changes|-c [category] ${COLOR_RESET} : list all CHANGED packages"
	echo -e " ${BOLDWHITE}netpkg news|-n [category] ${COLOR_RESET} : list all NEW packages"
	echo -e " ${BOLDWHITE}netpkg local|-l [category] ${COLOR_RESET} : list all LOCAL packages"
	echo -e " ${BOLDWHITE}netpkg update-all|-uu [category] ${COLOR_RESET} : Update all packages without prompting"
	echo -e " ${BOLDWHITE}netpkg download-all ${COLOR_RESET} : Download all repository packages without prompting"

	echo
	echo -e "Setup commands :"			 
	echo -e " ${BOLDWHITE}netpkg add-source|-as \"URL\"${COLOR_RESET} : add repository URLs to netpkg.conf"	
	echo -e " ${BOLDWHITE}netpkg disable-source|-ds ${COLOR_RESET} : disable repository URLs in netpkg.conf"	
	echo -e " ${BOLDWHITE}netpkg enable-source|-es ${COLOR_RESET} : enable repository URLs in netpkg.conf"
	echo -e " ${BOLDWHITE}netpkg dotnew|-z${COLOR_RESET} : search for .new config files in the suystem and prompt for action"
	echo -en ${COLOR_RESET}
	echo
}

# Local options
if [ "$1" ]; then
	case "$1" in
		'--help' | '-help' | 'help' | '-h')
			usage
			exit 1
			;;
		'source' | '-s')			
			SetSource
			FetchRepository
			export source="$(tail -n1 $netpkgdir/last_source 2>/dev/null)"
			exit 0
			;;
		'dotnew' | '-d')
			CheckDotNew
			exit 1
			;;
		'add-source' | '-as')
			shift
			AddSource $1
			exit 0
			;;
		'disable-source' | '-ds')
			DisableSource
			exit 0
			;;
		'enable-source' | '-es')
			EnableSource
			exit 0
			;;
		'remove' | '-r')
			export dependencies="no"
			shift
			removepkg "$*"
			exit 0
	esac
else
	baneer
	echo -e "Netpkg $version running on Zenwalk $zenwalk_version"
	echo -e "Synopsys : ${BOLDWHITE}netpkg pattern [pattern2 ...]${COLOR_RESET}"
	echo -e "   match pattern(s) and prompt for install, remove, reinstall, download"
	exit 1
fi

# How old is the DB ?
RemoteAndLocalPkgListage="0"
[ -e $netpkgdir/RemoteAndLocalPkgList ] && RemoteAndLocalPkgListage=$(stat -c %Z $netpkgdir/RemoteAndLocalPkgList )

# Retrieve the last chosen source if any
if [ -e $netpkgdir/last_source ] ; then 
	export source="$(tail -n1 $netpkgdir/last_source 2>/dev/null)"
	
	if [ $(($(date +%s) - $RemoteAndLocalPkgListage)) -ge 60 ] ; then
	
		echo -en "Current source is ${BOLDGREEN}$source ${COLOR_RESET}"	
		echo "Keep it ? (\"1\" for change, default keep)"
		echo -n "> "

		while read answer ; do
			case $answer in
			1|change)
				SetSource
				FetchRepository
				echo -n "New source is "
				echo -en "${BOLDGREEN}"
				echo $source
				echo -en "${COLOR_RESET}"	
				break
				;;
			*)
				if [ $(($(date +%s) - $RemoteAndLocalPkgListage)) -ge 600 ] ; then
					FetchRepository
				fi
				break
			esac
		done
	fi
else
	SetSource
	FetchRepository
	export source="$(tail -n1 $netpkgdir/last_source 2>/dev/null)"
fi


	[ ! -e $netpkgdir/RemoteAndLocalPkgList ] && exit 1
# Network options
if [ "$1" ]; then
	case "$1" in
		'updade-all' | '-uu')	
			shift
			filter='IUND'*
			protect
			UpdateAll $*
			unprotect
			CheckDotNew
			exit 0
			;;
		'download-all' | '-da')
			shift
			filter='IUND' 
			GetAll
			exit 0
			;;
		'all' | '-a')
			shift
			filter='IUND' 
			FilterListPkg $*
			exit 0
			;;
		'changes' | '-c')
			shift
			filter='UD' 
			FilterListPkg $*
			exit 0
			;;
		'news' | '-n')
			shift
			filter='N' 
			FilterListPkg $*
			exit 0
			;;
		'local' | '-l')
			shift
			filter='I' 
			FilterListPkg $*
			exit 0
			;;
		'install' | '-i')
			shift
			export dependencies="no"
			filter='IUND' 
			protect
			SearchAndPrompt $*
			unprotect
			exit 0
			;;
		'update' | '-u')
			shift
			filter='UD' 
			protect
			SearchAndPrompt
			unprotect
			exit 0
			;;
		*)
			filter='IUND' 
			protect
			SearchAndPrompt $*
			unprotect
			exit 0
		esac
else
	usage
	exit 1
fi

exit 0


