#!/bin/bash

#   Script:      Build Custom TrueCrypt Favs File   
#
#
# by Apollia - http://apollia.com/
#
# Completed 
#
# ----

# 06:14:53 04/13/2018.  What a mess!


# July 28, 2017, 5:08 PM.  Depends on apsk-get-disknick-path.


#######################################################################
#
#   Some stuff you can change
#

	
#
#
#   End of Some stuff you can change
#
#   Below this point, nothing else in this script needs to be changed.
#
#
####################################################################################################
####################################################################################################
####################################################################################################


if [ -z "$1" ]
then
	echo "$0 error: Arg #1 must be a filepath (either absolute or relative) to a text file containing a list of TrueCrypt volumes, what slot they should be mounted at, what mountpoint they should be mounted at, and their path!"
	
	exit 1
fi

should_move_aside_original_truecrypt_settings=false

if [ "$2" = "Move Aside Original TrueCrypt Settings" ]
then
	should_move_aside_original_truecrypt_settings=true
	
fi
Filepath____Possible_List_of_TrueCrypt_Fav_Info="$1"

# July 29, 2017, 12:19 AM.  By default, the last line of successful output run will be the path where
# the file was output to.

Require_Config()
{
	local config_fillepath="$1"
	local config_desc="$2"
	local exit_code="$3"
	
	[ -z "$exit_code" ] && exit_code=100
		
	retval=$(cat "$config_fillepath")
	result_code="$?"
	
	if [ "$result_code" != 0 ]
	then
		echo
		echo
		echo "$0 error: Aborting, because it wasn't possible to retrieve $config_desc"
		exit "$exit_code"
	fi
	
	
}

Require_Config "$Filepath____Possible_List_of_TrueCrypt_Fav_Info"

Possible_List_of_TrueCrypt_Fav_Info="$retval"


# July 29, 2017, 12:24 AM.  Now, have to valicheck the list, and abort if it's
# flawed.


Valicheck_Relpath_to_TrueCrypt_Volume()
{
	local Possible_TrueCrypt_Volume_Relpath="$1"
	
	valicheck_comment=""
	
	Valicheck_Path_for_Badchars "$Possible_TrueCrypt_Volume_Relpath"
	
	result_code="$?"
	if [ "$result_code" != 0 ]
	then
		valicheck_comment="Has path badchars."
		return 1
		#Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "relpath to TrueCrypt volume" "2" "Has path badchars."
	fi
	
	Valicheck_That_Path_Is_Relative "$Possible_TrueCrypt_Volume_Relpath"
	result_code="$?"
	if [ "$result_code" != 0 ]
	then
		valicheck_comment="Path is not relative."
		return 1
		#Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "relpath to TrueCrypt volume" "2" "Has path badchars."
	fi
}
Valicheck_That_Path_Is_Relative()
{
	local path="$1"
	echo "Pretending the path $path was valichecked for relativeness successfully."
	
	return 0
} 
		
		
		
Valicheck_That_Path_Is_Absolute()
{
	local path="$1"
	echo "Pretending the path $path was valichecked for absoluteness successfully."
	
	return 0
}

Valicheck_Mountpoint_Path()
{
	local possible_mountpoint_path="$1"
	
	# July 29, 2017, 12:54 AM.  Has to be a fullpath.  
	
	valicheck_comment=""
	Valicheck_That_Path_Is_Absolute "$possible_mountpoint_path"
	result_code="$?"
	
	if [ "$result_code" ]
	then
		return 0
	fi
	
	return 1
}

Valicheck_Slot_Number()
{
	local possible_slot_number="$1"
	
	if [[ "$possible_slot_number" -gt 0 && "$possible_slot_number" -lt 65 ]]
	then
		return 0
	fi
	
	return 1
}


Valicheck_Path_for_Badchars()
{
	# July 29, 2017, 12:59 AM.  Just need to find path badchars.
	
	return 0
}
Get_Mountpoint_Path_and_Valicheck_Mountpoint_Platz()
{
	local possible_mountpoint_platz="$1"
	local result
	local result_code
	
	result=$(platz "$possible_mountpoint_platz" "APSK - Build Custom TrueCrypt Favs List - Mountpoint" )
	result_code="$?"
	retval="$result"
	
	if [ "$result_code" != 0 ]
	then
		valicheck_comment="This platz didn't have an associated path."
		return 1
	fi
	
	#~ mountpoint_comment="This platz yielded a mountpoint path which wasn't an absolute path:
	#~ 
	#~ $Mountpoint_Path"
	#~ 
	#~ return 1
	# July 29, 2017, 1:04 AM.  Check if it has path badchars.
	
	
	return 0
	
}

flaws_in_TrueCrypt_Fav_Info=""

Note_Missing_Field_in_TrueCrypt_Fav_Info()
{
	local line="$1"
	local line_number="$2"
	local missing_field_number="$3"
	
	echo "missing field $missing_field_number "
	
	flaws_in_TrueCrypt_Fav_Info+="Missing field $missing_field_number in line $line_number:

	$line

"
}

Note_Invalid_Field_in_TrueCrypt_Fav_Info()
{
	local line="$1"
	local line_number="$2"
	local invalid_field_name="$3"
	local invalid_field_number="$4"
	local invalid_field_value="$5"
	local comment="$6"
	
	flaws_in_TrueCrypt_Fav_Info+="Invalid field $invalid_field_number ($invalid_field_name) with value '$invalid_field_value' in line $line_number:

	$line
	
"
	
	if [ ! -z "$comment" ]
	then
		flaws_in_TrueCrypt_Fav_Info+="$comment

"
	fi
flaws_in_TrueCrypt_Fav_Info+="
"
}

fields=()


Valicheck_Setting____Writable_or_Readonly()
{
	local possible_setting="$1"
	
	case "$possible_setting" in
		"Writable"|"Read Only"|"Read-Only")
			return 0
			;;
		*)
			return 1
	esac
}
	Possible_Mountpoint_Platz="${fields[1]}"
	Possible_TrueCrypt_Volume_Relpath="${fields[2]}"
	Possible_TrueCrypt_Slot_Number="${fields[3]}"
	Possible_Setting____Writable_or_Readonly="${fields[4]}"
	Possible_Alt_Mountpoint="${fields[5]}"
	
	
	
Get_TrueCrypt_Fav_Info_Fields_from_Line()
{
	local line="$1"
	local line_number="$2"
	
	local i=1
	local result_code
	
	
	while [ $i -lt 6 ]
	do

		
		result=$(echo "$line" | cut -d, -f $i )
		result_code="$?"
		
		echo "$i Result: $result"
		
		if [ "$result_code" != 0 ]
		then 
			if [ "$i" != 5 ]
			then
				:

			fi
		else
			field=$(echo "$result" | sed 's/^[[:blank:]]*//; s/[[:blank:]]*$//')
			
			if [ ! -z "$field" ]
			then
				echo "NOT EMPTY FIELD"
				echo "Field: $field"
				fields[$i]="$field"
			
				echo "Fields: ${fields[$i]}"
			else
				echo "EMPTY FIELD"
				fields[$i]=""
				#Note_Missing_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "$i"
			fi
		fi
		echo "Result: $result"
		
		let "i++"
	done
	echo "Result: $result"

	
	Possible_Mountpoint_Platz="${fields[1]}"
	echo "Possible_Mountpoint_Platz: $Possible_Mountpoint_Platz"
	
	Possible_TrueCrypt_Volume_Relpath="${fields[2]}"
	Possible_TrueCrypt_Slot_Number="${fields[3]}"
	Possible_Setting____Writable_or_Readonly="${fields[4]}"
	Possible_Alt_Mountpoint="${fields[5]}"
	
	
}


Mountpoint_Path=""

Standardized_Mountpoint_Path=""
Standardized_TrueCrypt_Volume_Relpath=""
Standardized_TrueCrypt_Slot_Number=""
Standardized_Setting____Writable_or_Readonly=""
Standardized_Alt_Mountpoint=""

Valicheck_and_Standardize_Possible_List_of_TrueCrypt_Fav_Info()
{
	line_number="0"
	
	while read -r line; do
		let "line_number++"
		
		Get_TrueCrypt_Fav_Info_Fields_from_Line "$line" "$count_of_lines"
		
		Get_Mountpoint_Path_and_Valicheck_Mountpoint_Platz "$Possible_Mountpoint_Platz"
		result_code="$?"
		
		if [ "$result_code" != 0 ]
		then
			Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "mountpoint platz" "1" "$Possible_Mountpoint_Platz"
		fi
		Mountpoint_Path="$retval"
		result_code="$?"
		if [ "$result_code" != 0 ]
		then
			Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "mountpoint platz" "1" "$Possible_Mountpoint_Platz" "$valicheck_comment"
		fi
	
		Valicheck_Path_for_Badchars "$Mountpoint_Path"
		result_code="$?"
		if [ "$result_code" != 0 ]
		then
			Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "mountpoint platz" "1" "$Possible_Mountpoint_Platz" "This platz yielded a mountpoint path badchars."
		fi
		
		
		Valicheck_Relpath_to_TrueCrypt_Volume "$Possible_TrueCrypt_Volume_Relpath"
		
		#~ Valicheck_Path_for_Relativity "$Possible_TrueCrypt_Volume_Relpath"
		#~ Valicheck_Path_for_Badchars "$Possible_TrueCrypt_Volume_Relpath"
		result_code="$?"
		if [ "$result_code" != 0 ]
		then
			Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "relpath to TrueCrypt volume" "2" "$Possible_TrueCrypt_Volume_Relpath" "$valicheck_comment"
		fi
		
		
		Valicheck_Slot_Number "$Possible_TrueCrypt_Slot_Number"
		result_code="$?"
		if [ "$result_code" != 0 ]
		then
			Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "TrueCrypt slot number" "3" "$Possible_TrueCrypt_Slot_Number" "Not a number from 1 through 64."
		fi
		
		
		Valicheck_Setting____Writable_or_Readonly "$Possible_Setting____Writable_or_Readonly"
		result_code="$?"
		if [ "$result_code" != 0 ]
		then
			Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "Writable or Read Only setting" "4" "$Possible_Setting____Writable_or_Readonly" "Not equal to \"Writable\", \"Read Only\", or \"Read-Only\" without quotes."
		fi
		
		
		if [ ! -z "$Possible_Alt_Mountpoint" ]
		then
			Valicheck_Mountpoint_Path "$Possible_Alt_Mountpoint"
			result_code="$?"
			if [ "$result_code" != 0 ]
			then
				Note_Invalid_Field_in_TrueCrypt_Fav_Info "$line" "$line_number" "optional alternate mountpoint path" "5" "$Possible_Alt_Mountpoint" "$valicheck_comment"
			fi
		fi
		
		Standardized_Mountpoint_Path[$line_number]="$Mountpoint_Path"
		Standardized_TrueCrypt_Volume_Relpath[$line_number]="$Possible_TrueCrypt_Volume_Relpath"
		Standardized_TrueCrypt_Slot_Number[$line_number]="$Possible_TrueCrypt_Slot_Number"
		Standardized_Setting____Writable_or_Readonly[$line_number]="$Possible_Setting____Writable_or_Readonly"
		Standardized_Alt_Mountpoint[$line_number]="$Possible_Alt_Mountpoint"

		Standardized_Fillepath____TrueCrypt_Volume[$line_number]="$Mountpoint_Path/$Possible_TrueCrypt_Volume_Relpath"
		
		Standardized_Count_of_Lines="$line_number"
		let "Standardized_Count_of_Lines++"
		
		echo "Standardized_Mountpoint_Path: ${Standardized_Mountpoint_Path[$line_number]}"
		
		echo "Standardized_TrueCrypt_Volume_Relpath: ${Standardized_TrueCrypt_Volume_Relpath[$line_number]}"
		
		echo "Standardized_TrueCrypt_Slot_Number: ${Standardized_TrueCrypt_Slot_Number[$line_number]}"
		
		echo "Standardized_Setting____Writable_or_Readonly: ${Standardized_Setting____Writable_or_Readonly[$line_number]}"
		
		echo "Standardized_Alt_Mountpoint: ${Standardized_Alt_Mountpoint[$line_number]}"
		
		echo "Standardized_Fillepath____TrueCrypt_Volume: ${Standardized_Fillepath____TrueCrypt_Volume[$line_number]}"
		
		
	done <<< "$Possible_List_of_TrueCrypt_Fav_Info"
	
	
}

# July 28, 2017, 12:18 PM.  Format for the favs list text file
# which this script will convert into TrueCrypt Favs XML file:
#
# * Slot number
#
# * Read only or not.  0 is writable, 1 is read-only.
# 
# * Folderpath where the TrueCrypt volume will be mounted,
#   or nothing if you just want to use /apmnt/truecrypt[slot number]
# 
# * Mountpointless relpath to the TrueCrypt volume file.
#
# * The disknick (nickname of the disk) where the TrueCrypt volume
#   is located.
#
# All those items must be separated by , in between them.
# (Surrounding whitespace will be trimmed.)
#
# Disknick, TrueCrypt Volume's Relpath, TrueCrypt Slot Number, Writable or Read-Only, Optional Unusual Mountpoint

# Gia, Meadows/Legacy Meadow, 26, Read-Only, /apmnt/Legacy_Meadow
#
# July 28, 2017, 5:37 PM.  I can even use a disknick like Main Flash Drive, 
# and set that automatically somehow, so if I ever copy this
# to something other than Gia, it will still work!


# Slot, Read-Only (0 = writable and 1 = read-only), Mountpoint To Use, TrueCrypt Volume's Relpath, Disknick
# 26, 1, , Meadows/Legacy Meadow, Gia


# July 28, 2017, 1:07 PM.  Need to loop through the text file's lines,
# and check all 5 fields for validity, and abort if anything is invalid.
#
# Also, all the disk nicknames the file uses must be known, or else
# we abort.

# July 29, 2017, 12:08 AM.  ok, field one, a mountpoint platz.  we just need
# to know a platz by that name actually exists, so we run apsk-get-platz-path to check that out.
#
# putting together the mountpoint platz and the truecrypt volume relpath, we can now get
# a fullpath to the truecrypt volume.  If it leads to an existing file, we assume that's OK.
#
# field #3 has to be 1 thru 64.
#
# field #4 has to be either Writable or Read Only.
#
# field #5 is optional.  hmm, do mountpoints have to be in the ramdisk?  don't know...
# anyway tho, i guess even if a file is there, we can just ignore that and let the user
# handle it.  As long as it's a valid fullpath, might as well accept it.  shouldn't
# resolve symlinks, but should make a standardized path and compare it to the one
# in the file, and if they differ (like the user put two slashes in a row), might as
# well nitpick about that, but give them the good version which they can paste instead.
# then again, could avoid nitpicking... hmm... might be harmless to allow multiple
# slashes.  don't want pathdots tho... hmm... i don't recall if i found a way to get
# rid of those without resolving symlinks...
#
# 06:08:36 04/13/2018.  Finally found a way - the Cwd::Ext Perl module's abs_path_nd() function.
# http://search.cpan.org/~leocharre/Cwd-Ext-1.06/lib/Cwd/Ext.pod#abs_path_nd%28%29


Valicheck_and_Standardize_Possible_List_of_TrueCrypt_Fav_Info

if [ ! -z "$flaws_in_TrueCrypt_Fav_Info" ]
then
	echo "Flaws found in TrueCrypt favorite volumes info list at:
	
	$Filepath____Possible_List_of_TrueCrypt_Fav_Info
	
$flaws_in_TrueCrypt_Fav_Info"
	exit 2
fi



# July 29, 2017, 1:20 AM.  OK, 

#echo "$line" | cut -d, -f 1 | sed 's/^[[:blank:]]*//; s/[[:blank:]]*$//'


# July 28, 2017, 12:54 PM.  Usually our mountpoints have two foldernames,
# so this will probably will give us most mountpoints:

#echo "$path" | cut -d/ -f 1-3


readonly Fillepath____This_Script=$(realpath "${BASH_SOURCE[0]}")
readonly Follpath____This_Script=$(dirname "$Fillepath____This_Script")

readonly Follpath____Output="/root/zzzzz-tmp/Custom TrueCrypt Favs Output"
readonly Follpath____TrueCrypt_Settings="/root/.TrueCrypt"

#readonly Follpath____Output="$Follpath____TrueCrypt_Settings"
readonly Filename____TrueCrypt_Favs="Favorite Volumes.xml"

readonly Fillepath____Output="$Follpath____Output/$Filename____TrueCrypt_Favs-$$"



readonly Fillepath____Original_TrueCrypt_Favs="$Follpath____TrueCrypt_Settings/$Filename____TrueCrypt_Favs"

mkdir --parents "$Follpath____Output"

#touch "$Fillepath____Output"

Output_TrueCrypt_Fav_XML_Header()
{
	echo '<?xml version="1.0" encoding="utf-8"?>
<TrueCrypt>
	<favorites>' > "$Fillepath____Output"
	
}

Output_TrueCrypt_Fav_XML_Footer()
{
	echo '	</favorites>
</TrueCrypt>' >> "$Fillepath____Output"
	
}

Output_TrueCrypt_Fav_XML_Header




Output_TrueCrypt_Fav_Volume_Line()
{
	local line_number="$1"
	
	output_slot_number="${Standardized_TrueCrypt_Slot_Number[$line_number]}"
	
	case "${Standardized_Setting____Writable_or_Readonly[$line_number]}" in
		"Writable")
			output_setting____writable_or_read_only=0
			;;
		"Read Only"|"Read-Only")
			output_setting____writable_or_read_only=1
			;;
	esac
	
	#output_setting____writable_or_read_only="${Standardized_Setting____Writable_or_Readonly[$line_number]}"
	
	output_fillepath____truecrypt_volume="${Standardized_Fillepath____TrueCrypt_Volume[$line_number]}"
	
	if [ -z "${Standardized_Alt_Mountpoint[$line_number]}" ]
	then
		
		output_mountpoint="/apmnt/truecrypt$output_slot_number"
	else
		output_mountpoint="${Standardized_Alt_Mountpoint[$line_number]}"
	fi
	
	# july 29, 2017, 2:44 AM.  egad, lt's or gt's in a truecrypt volume path could be a problem for this xml file.
	
	echo "		<volume mountpoint=\"$output_mountpoint\" readonly=\"$output_setting____writable_or_read_only\" slotnumber=\"$output_slot_number\" system=\"0\">$output_fillepath____truecrypt_volume</volume>" >> "$Fillepath____Output"

	
}



echo "Standardized_Count_of_Lines: $Standardized_Count_of_Lines"

Output_TrueCrypt_Fav_Volume_Lines()
{
	line_number=1
	while [ "$line_number" -lt "$Standardized_Count_of_Lines" ]
	do
		
		Output_TrueCrypt_Fav_Volume_Line "$line_number"
		let "line_number++"
	done
}


Output_TrueCrypt_Fav_Volume_Lines
Output_TrueCrypt_Fav_XML_Footer

Back_Up_Original_TrueCrypt_Settings()
{
	backup_filename="Favorite Volumes.xml-Backup-$$-$(date +%F_%R)"
	Fillepath____Backup_Original_TrueCrypt_Favs="$Follpath____TrueCrypt_Settings/$backup_filename"
	
	if [ -f "$Fillepath____Original_TrueCrypt_Favs" ]
	then
		cp --no-clobber --preserve=all "$Fillepath____Original_TrueCrypt_Favs" "$Fillepath____Backup_Original_TrueCrypt_Favs"
	
		result_code="$?"
	
		if [ "$result_code" != 0 ]
		then
			echo "Aborting.  The original TrueCrypt settings have been left in their place, because somehow trying to create a backup failed.

	Your newly-built TrueCrypt settings can be found at:

		$Fillepath____Output"
			exit 3
		fi
	else
		echo "Found no original TrueCrypt settings, so not backing them up."
		return 0
	fi
	
}
echo "end"

if [ "$should_move_aside_original_truecrypt_settings" = true ]
then
	Back_Up_Original_TrueCrypt_Settings
	
	cp "$Fillepath____Output" "$Fillepath____Original_TrueCrypt_Favs"
	
	echo
	echo
	echo "Original TrueCrypt favs backed up to:

	$Fillepath____Backup_Original_TrueCrypt_Favs"

	echo
	echo
	echo "Output locations:

	$Fillepath____Output
	$Fillepath____Original_TrueCrypt_Favs"

	
exit 0
else
		echo "Output location:
$Fillepath____Output"

exit 0
fi