#!/usr/pkg/bin/bash
#
# Simple shell script to update db-ip.com database files
#
# Project    : ipv6calc/DBIP
# File       : DBIP-update.sh
# Copyright  : 2014-2025 by Peter Bieringer <pb (at) bieringer.de>
# License    : GNU GPL version 2

# 20240124: add optional -R|t support

DBIP_DAT_DIR_DEFAULT="/usr/share/DBIP"
[ -z "$DBIP_DAT_DIR" -a -n "$IPV6CALC_DB_DBIP2_DIR" ] && DBIP_DAT_DIR="$IPV6CALC_DB_DBIP2_DIR"
[ -z "$DBIP_DAT_DIR" ] && DBIP_DAT_DIR="$DBIP_DAT_DIR_DEFAULT"

DBIP_DAT_URL_BASE="http://download.db-ip.com/free/"
DBIP_DAT_FILES="dbip-country-lite-%Y-%m.mmdb.gz dbip-city-lite-%Y-%m.mmdb.gz dbip-asn-lite-%Y-%m.mmdb.gz"

# optional ipv6calc-db-update-support.sh
supportfile="$(dirname "$0")/ipv6calc-db-update-support.sh"
if [ -r "$supportfile" ]; then
	echo "INFO  : found and sourced: $supportfile"
	source $supportfile
fi

help() {
	cat <<END
Usage: $(basename "$0") [-v] [-s] [-c] [-D <dir>] [-C <days>] [-U <url>] [-T <type>] ${have_ipv6calc_db_update_support:+[-R [-r]]}
	-s		skip download
	-c		skip decompress
	-v		verbose
	-D <dir>	database directory (optional)
	-C <days>	cleanup files older than given days (optional)
	-U <url>	use URL to download full database
	-T <type>	set type of via URL downloaded file
                          MMDB: country|isp|location|*location-isp*
			  CSV : isp|location|*full*
END

	[ -n "$have_ipv6calc_db_update_support" ] && ipv6calc_db_update_support_help

	cat <<END

	database directory: $DBIP_DAT_DIR (default: $DBIP_DAT_DIR_DEFAULT)

 it honors externally defined environment value:
	prio 1: DBIP_DAT_DIR
	prio 2: IPV6CALC_DB_DBIP2_DIR

 this script will download data from
 DB-IP.com (default: free versions) the MaxMindDB (mmdb) files DB files for ipv6calc
 "DBIP" database support

 DBIP_DAT_URL_BASE=$DBIP_DAT_URL_BASE
 DBIP_DAT_FILES=$DBIP_DAT_FILES

 in case -U <url> (take URL from subscription e-mail) is provided, it downloads the database
  use -T <type> in case it's not "location-isp"
END
}

skip_download=false
skip_decompress=false
verbose=false
while getopts "vT:D:C:U:scRrh\?" opt; do
	case $opt in
	    v)
		verbose=true
		;;
	    s)
		skip_download=true
		;;
	    c)
		skip_decompress=true
		;;
	    C)
		DBIP_DAT_CLEANUP_DAYS="$OPTARG"
		;;
	    D)
		DBIP_DAT_DIR="$OPTARG"
		;;
	    U)
		DBIP_URL="$OPTARG"
		;;
	    T)
		DBIP_TYPE="$OPTARG"
		;;
	    R)
		if [ -z "$have_ipv6calc_db_update_support" ]; then
			echo "WARN  : -R is not supported as extension was not loaded: ipv6calc-db-update-support.sh"
		else
			reloadrestart=1
		fi
		;;
	    r)
		testrun=1
		;;
	    *)
		help
		exit 1
		;;
	esac
done

if [ -n "$DBIP_URL" ]; then
	case $DBIP_URL in
	    *.csv)
		urldbtype=${DBIP_TYPE:-full}
		DBIP_DAT_FILES="dbip-$urldbtype-%Y-%m.csv.gz"
		;;
	    *.mmdb)
		urldbtype=${DBIP_TYPE:-location-isp}
		DBIP_DAT_FILES="dbip-$urldbtype-%Y-%m.mmdb.gz"
		;;
	    *)
		echo "ERROR : given URL has unsupported filename suffix"
		exit 1
		;;
	esac
fi

if [ ! -t 0 ] || $verbose; then
	options_generate="-q"
	options_wget="-q"
fi

if [ ! -d "$DBIP_DAT_DIR" ]; then
	echo "ERROR : missing directory: $DBIP_DAT_DIR"
	exit 1
fi

if [ ! -w "$DBIP_DAT_DIR" ]; then
	echo "ERROR : missing write permissions on directory: $DBIP_DAT_DIR"
	exit 1
fi

# Download files
download_result=true
if ! $skip_download; then
	for file in $DBIP_DAT_FILES; do
		# convert tokens
		year=$(date +%Y)
		month=$(date +%m)

		file=${file//%Y/$year}
		file=${file//%m/$month}

		file_dest="$DBIP_DAT_DIR/`basename "$file"`"

		if [ -z "$DBIP_URL" ]; then
			echo "INFO  : try to download file: $file ($file_dest)"
			wget $options_wget -O "$file_dest" "$DBIP_DAT_URL_BASE$file"
			if [ $? -ne 0 ]; then
				echo "ERROR : download of file not successful: $file ($file_dest)"
				download_result=false
				continue
			fi
		else
			echo "INFO  : try to download file: $DBIP_URL ($file_dest)"
			wget $options_wget -O "$file_dest" "$DBIP_URL"
			if [ $? -ne 0 ]; then
				echo "ERROR : download of file not successful: $DBIP_URL ($file_dest)"
				download_result=false
				continue
			fi
		fi
		echo "INFO  : download of file successful: $DBIP_URL ($file_dest)"
	done
fi

# create db/decompress mmdb files from downloaded files
$skip_decompress && download_result=false
error=0
if $download_result; then
	for file in $DBIP_DAT_FILES; do
		# convert tokens
		year=$(date +%Y)
		month=$(date +%m)

		file_input=${file//%Y/$year}
		file_input=${file_input//%m/$month}

		file_input="$DBIP_DAT_DIR/`basename "$file_input"`"

		case $file in
		    *.mmdb.gz)
			if [ -e "$file_input" ]; then
				echo "INFO  : decompress: $file_input)"
				gunzip "$file_input"
				if [ $? -ne 0 ] ;then
					echo "ERROR : decompress failed: $file_input"
					error=1
					continue
				fi
			fi

			file_input=${file_input/.gz}
			if [ ! -e "$file_input" ]; then
				echo "ERROR : decompressed file missing: $file_input)"
				error=1
				continue
			fi

			file_softlink="${file/-%Y}"
			file_softlink="${file_softlink/-%m}"
			file_softlink="${file_softlink/.gz}"
			file_softlink="$DBIP_DAT_DIR/`basename "${file_softlink}"`"
			echo "NOTICE: mmdb file requires only softlink: $file_softlink -> `basename "$file_input"`"
			if [ -e "$file_softlink" ]; then
				if [ ! -L "$file_softlink" ]; then
					echo "ERROR : file exists but is not a softlink: $file_softlink"
					continue
				fi
				echo "NOTICE: remove existing softlink: $file_softlink"
				rm -f "$file_softlink"
			fi
			ln -sf "`basename "$file_input"`" "$file_softlink"
			;;
		    *)
			echo "WARN  : unsupported file: $file (SKIP)"
			;;
		esac
	done
fi

if [ -n "$DBIP_DAT_CLEANUP_DAYS" ]; then
	# lookup softlinks
	declare -A DBIP_DAT_SOFTLINKS
	declare -A DBIP_DAT_SOFTLINKS_DEST
	DBIP_DAT_SOFTLINKS=$(find $DBIP_DAT_DIR -type l -name 'dbip-*.mmdb' -o -name 'dbip-*.csv')
	for key in ${DBIP_DAT_SOFTLINKS[@]}; do
		$verbose && echo "DEBUG : check softlink   : $key"
		dest=$(readlink "$key")
		if [ -n "$dest" ]; then
			$verbose && echo "DEBUG : softlink resolved: $key -> $dest"
			DBIP_DAT_SOFTLINKS_DEST[$dest]=$key
		else
			$verbose && echo "DEBUG : softlink broken  : $key"
		fi
	done

	# lookup files and check whether they are target of a softlink
	declare -A DBIP_DAT_FILES
	DBIP_DAT_FILES=$(find $DBIP_DAT_DIR -type f -mtime +$DBIP_DAT_CLEANUP_DAYS -name 'dbip-*-????-??.mmdb' -o -name 'dbip-*-????-??.csv')
	for file in ${DBIP_DAT_FILES[@]}; do
		basefile=$(basename "$file")
		$verbose && echo "DEBUG : check file         : $file ($basefile)"
		if [ -n "${DBIP_DAT_SOFTLINKS_DEST[$file]}" ];then
			$verbose && echo "DEBUG : target of softlink1: $file <- ${DBIP_DAT_SOFTLINKS_DEST[$file]}"
			DBIP_DAT_FILES[$file]=2
		elif [ -n "${DBIP_DAT_SOFTLINKS_DEST[$basefile]}" ];then
			$verbose && echo "DEBUG : target of softlink2: $file <- ${DBIP_DAT_SOFTLINKS_DEST[$basefile]}"
			DBIP_DAT_FILES[$file]=3
		else
			$verbose && echo "DEBUG : no softlink target : $file"
			DBIP_DAT_FILES[$file]=1
		fi
	done

	# delete unused files
	for file in ${DBIP_DAT_FILES[@]}; do
		if [ "${DBIP_DAT_FILES[$file]}" = "1" ]; then
			echo "INFO  : delete unused file : $file"
			rm -f "$file"
		fi
	done
fi

# calling external function
if [ -n "$have_ipv6calc_db_update_support" ]; then
	[ "$reloadrestart" = "1" ] && ipv6calc_db_update_support_reloadrestart "$DBIP_DAT_DIR" "$testrun"
fi

exit $error
