#
# j/jsee:	Personal Journal Management Program
#		 	Written by Leor Zolman, 3/93

DEBUG=N  	# If Y, use current dir for JOURN_DIR and show debug info

# 
# Usages:
# 	j  [ - (or) -e (or) -ekey ] [journal-dir]
# 	jsee [ - (or) -e (or) -ekey ] [journal-dir (or) journal-file-basename ]
#
# 	
# Encryption Control
# ------------------
#
# Whether or not j/jsee employs encryption is controlled by the command
# line format and several environment variables:
#
# JCRYPT			If defined as Y outside j/jsee, encryption is enabled
#						by default, unless superceded by the "-" option
# ASK_CRYPT			Y to have j/jsee verify encryption if JCRYPT is true
#
# 
# With no configuration whatsoever, encryption is disabled by default.
# If the command line options -e or -e<key> are used, then encryption is
# enabled.
#
# Encryption may be turned on by default for all j/jsee sessions by
# setting JCRYPT to Y in your environment.  Then, if ASK_CRYPT is set to Y in
# the code, then j/jsee will ask for a confirmation before using encryption.
# If JCRYPT is Y and ASK_CRYPT is N, no confirmation is required.
#
# If the "-" option appears on the command line, encryption is NEVER used.
# Use this to disable encryption regardless of the value of JCRYPT in
# your shell environment. 
# 
#
# Getting the value of the encryption key from the user
# -----------------------------------------------------
#
# CRYPT_KEY_VAR		Name of env var containing encryption key 
#
# It is not a good idea to store the encryption key in any file on the system,
# nor to supply it on the j/jsee command line via the -e<key> option (for
# security reasons.) So, there needs to be a secure way for the user to inform
# j/jsee of the key value. If the user assigns a value to the environment
# variable whose name is stored in CRYPT_KEY_VAR before running j/jsee (as,
# for example, through use of the key() shell function), then j/jsee uses
# that value as the encryption key. If the variable named by CRYPT_KEY_VAR
# is null, then j/jsee prompts the user to enter the encryption key at
# each run.
#
# How j/jsee supplies the encryption key to the crypt program
# -----------------------------------------------------------
#
# CRYPT_HAS_K		Y if your version of crypt supports the -k option
#
# If CRYPT_HAS_K is N, then j/jsee is obliged to include the encryption
# key as part of the crypt command line (least secure, since the key
# is potentially visible to users running the ps command at just the
# right moment.)
# 
# If CRYPT_HAS_K is Y, then j/jsee passes the key to crypt by making sure 
# that the environment variable named by CRYPT_KEY_VAR contains the key
# value, and specifying -k alone on the crypt command line.
#
#
# What j does:
# ------------
#
# j creates a journal entry and appends it to the appropriate current monthly
# incremental journal file in the JOURN_DIR directory (or, if the subdir
# argument was given, the named subdirectory of JOURN_DIR).  If encryption is
# used, then a journal file having an extension of ".txe" is used; otherwise,
# the journal file having the extension ".txt" is used. By having two files
# for each month, one encrypted (.txe) and one plain (.txt), we avoid the
# potential inadvertant mixing of encrypted and non-encrypted text within a
# a single file.
# 
# When using j, the journal filename (less extension) is always of the
# form YY-MM, where YY is the 2-digit year and MM is the two-digit
# month (with leading 0's if required.)
# 
#
# What jsee does:
# ---------------
# 
# When invoked without any name argument, jsee brings up the current month's
# cumulative journal file on the screen in your editor, and you may edit
# it as desired. This form is used to make changes to an existing entry,
# as opposed to creating a new entry. Whether the encrypted or non-
# encrypted file is used depends on whether encryption is enabled (as
# described above).
#
# When the argument to jsee is the name of a subdirectory of the $JOURN_DIR
# directory, then jsee operates on the current month's cumulative journal
# file in the named subdirectory. 
#
# When supplied an explicit journal pathname (without extension), then
# jsee operates on the file whose pathname is specified. In this case,
# $JOURN_DIR is NOT pre-pended to the filename, so a conventional full
# or relative path name must be specified. The extension implicitly added
# to the supplied pathname is dependent upon the encryption status as
# determined above.
#
# 
# Automatic encryption key synchronization
# ----------------------------------------
#
# Both j and jsee guard against inadvertant mixed encryption keys being
# applied to the same single montly journal file. Whenever encryption is
# called for in conjunction with the examination of (jsee) or appending
# to (j) a cumulative monthly journal file, the cumulative file is first
# decrypted using the specified key and the first line is examined for
# the presence of the signature text "Journal" (whenever a cumulative
# journal file is created, a line containing that text is always written
# at the beginning). If the signature text is not found, no further action
# is taken. Users should never delete or insert any lines before this 
# signature header line. 
#

######### User-Customizable Definitions #################################

JOURN_DIR=$HOME/.Journ	# Directory where journal text kept
[ $DEBUG = Y ] && JOURN_DIR=.		# When debugging, force current dir

# System-dependent features:


if [ -z "$CRYPT_KEY_VAR" ]		# If already set, don't mess with it...
then							
	CRYPT_KEY_VAR=CRYPTKEY 		# env var holding key (for use with  -k)
#	CRYPT_KEY_VAR=CrYpTkEy		# SCO Unix variation
fi

#CRYPT_HAS_K=N			# XENIX's crypt does not support -k option
CRYPT_HAS_K=Y			# SCO UNIX's crypt does support -k option

ASK_CRYPT=N				# Y=Query encryption if JCRYPT true, N=assume yes
 
EDITOR=/usr/local/e.old	# Text editor
EPSILON=N				# Y if using Epsilon as text editor
MICRO_EMACS=Y			# Y if using microEMACS as text editor
TABS="\t\t\t\t\t\t\t\t"	# string to precede date string for each entry

FILEPERMS=600			# Permissions to assign to cumulative text files
DIRPERMS=700			# Perms to assign to JOURN_DIR and its subdirs

############ End of User-Customizable Definitions ###########################

cmdname=`basename $0`	# j or jsee
crypt=N					# start out without encryption (by default)

jdir=$JOURN_DIR			# default Journal directory
monthly=`date +"%y-%m"`	
jfile=$monthly			# default Journal file
name_given=N			# whether or not name parameter supplied

usage() {
	echo "Usages:"
	echo "  j    [-[e[key]]] [journal-subdir]"
	echo "  jsee [-[e[key]]] [journal-subdir (or) journal-file-basename]"
	exit 0
}

#
# ed_invoke():	Invoke the text editor on the named file, with
#				initializations and command line usage approproate
#				to the particular editor used (microEMACS and Epsilon
#				initializations pre-configured.)
#				Exit the program if the file is not changed after the
#				editing session.
#

ed_invoke() {
	sav_stats=`ls -l $1`

	if [ $MICRO_EMACS = Y ]; then
		echo	"find-file $1
				set \$hardtab 4
				add-mode \"wrap\"
				end-of-file" > /tmp/erc$$
		$EDITOR @/tmp/erc$$
		rm /tmp/erc$$
	elif [ $EPSILON = Y ]; then
		$EDITOR $1 +3
	else
		$EDITOR $1
	fi
	clear

	if [ ! -f $1 ]; then
		echo "Arghhh! The file $1 has disappeared! What did you DO? Aborting."
		exit 1
	fi

	if [ "`ls -l $1`" = "$sav_stats" ]; then
		echo "You didn't change anything. No update performed."
		rm $1
		exit 0
	fi
}


#
# get_key():	Obtain the encryption key. 
#				If the environment variable named by CRYPT_KEY_VAR is
#				defined, then use its value as the encryption key.
#				If not, then prompt the user for the key string and
#				read it from the standard input (without echo).
#

get_key() {
	eval "key=\$$CRYPT_KEY_VAR"
	if [ -z "$key" ]; then						# key defined in environment?
		trap "stty echo; exit 1" 1 2 3 14 15	# if not, prompt for it now
		stty -echo
		echo "Enter encryption key: \c"
		read key	
		stty echo
		echo
		if [ -z "$key" ]; then
			echo "Null key invalid. Must enter some text."
			exit 1
		fi
	fi
}


#
# test_k():	if crypt program supports -k option (CRYPT_HAS_K is Y), then
#			set the key variable named by CRYPT_KEY_VAR to the key value
#			stored in the $key variable.
#

test_k() {									# determine if we can use -k:
	if [ $CRYPT_HAS_K = Y ]					# if -k supported,
	then
		eval "$CRYPT_KEY_VAR=$key"			# export key into environment
		eval "export $CRYPT_KEY_VAR"
		key=-k								# use -k alone in crypt commands
	fi
}

#
# ask():	ask user a yes/no question
#			Return Y on std output if answer is yes, else N.
#	 		usage: ask "string"
# 			( " (y/n)? " automatically appended to the string)
#

ask()
{
	while true
	do
		echo "$1 (y/n)? \c" >&2
		read answer
		case $answer in 
			[Nn]*) echo "N"
				 break;;
			[Yy]*) echo "Y"
				break;;
			*) echo 'Please answer "y" or "n"...' >&2
		esac
	done
}


echo "Electronic Journal Management System v3.0\n"

#
# Create master journal directory if not already there
#

if [ ! -d $JOURN_DIR ]; then
	echo "Master Journal directory $JOURN_DIR does not exist. Creating..."
	if mkdir $JOURN_DIR
	then
		echo "$JOURN_DIR created successfully."
		chmod $DIRPERMS $JOURN_DIR
	else
		echo "Could not create $JOURN_DIR. Aborting."
		exit 1
	fi
fi

#
# Process command line arguments:
#

case $# in
	1)  if echo $1 | grep "^-" >/dev/null
		then
			OPTS=$1
		else
			name_given=Y
			case $cmdname in
				j) 		jdir=$jdir/$1;;
				jsee)	jfile=$1;;
			esac
		fi;;
 	2)  if echo $1 | grep "^-" >/dev/null
		then
			OPTS=$1
			case $cmdname in
				j) 		jdir=$jdir/$2;;
				jsee)	jfile=$2;;
			esac
		elif echo $2 | grep "^-" >/dev/null
		then
			OPTS=$2
			case $cmdname in
				j) 		jdir=$jdir/$1;;
				jsee)	jfile=$1;;
			esac
		else
			usage
		fi
		name_given=Y;;
esac

if [ $DEBUG = Y ]; then
	echo "OPTS = $OPTS, jdir = $jdir, jfile = $jfile, crypt = $crypt"
fi

if [ "$OPTS" = - ]; then				# disable encryption?
	crypt=N
elif echo "$OPTS" | grep "^-e" >/dev/null	# -e option specified? 
then
	crypt=Y								# yes. turn on encryption.
	if [ "$OPTS" = -e ]; then			# -e alone?
		get_key
	else								# -ekey specified....
		key=`echo $OPTS | sed s/-e//p`	# extract key from cmd line
	fi
	test_k								# choose best way to pass crypt key
elif [ "$JCRYPT" = Y ]; then			# encryption flag in environment set?
	if [ $ASK_CRYPT = Y ]; then			# if so, does user need to verify?
		crypt=`ask "Encrypt"`			# yes, prompt user for verification
	else
		crypt=Y							# no, just go ahead and use encryption
	fi

	if [ $crypt = Y ]; then
		get_key							# get the key
		test_k							# and use -k if possible
	fi
fi

if [ $crypt = Y ]; then
	EXT=txe
else
	EXT=txt
fi

if [ $cmdname = jsee ]; then
	case $name_given in
		N)	if [ ! -r $jdir/$jfile.$EXT ]; then
				echo "No file $jdir/$jfile.$EXT."
				exit 1
			fi;;
		Y)	if [ ! -r $jfile.$EXT ]; then
				save_name=$jfile.$EXT
				jdir=$JOURN_DIR/$jfile
				jfile=$monthly.$EXT
				if [ ! -r $jdir/$jfile ]; then
					echo "Can't locate filespec \"$save_name\""
					exit 1
				fi
			fi;;
	esac
fi

if [ $DEBUG  = Y ]; then
	echo "crypt=$crypt, key=$key, \c"
	echo "\$$CRYPT_KEY_VAR=\c"
	eval "echo \$$CRYPT_KEY_VAR"
	echo "jdir = $jdir"
	echo "Press Return to continue...."
	read dummy
fi

#
# Check to make sure an explicitly named j subdirectory exists
#

if [ $cmdname = j -a ! -d $jdir ]; then
	echo "Journal sub-directory $jdir does not exist. Creating it..."
	if mkdir $jdir
	then
		chmod $DIRPERMS $jdir
		echo "$jdir created successfully."
		sleep 1
	else
		echo "Could not create $jdir. Aborting."
		exit 1
	fi
fi

#
# Establish name of cumulative journal file we'll be working with:
#

jfile=$jdir/$jfile
if [ $cmdname = jsee -a -r $jfile ]; then
	:
else
	jfile=$jfile.$EXT
fi

[ $DEBUG = Y ] && echo "jfile = $jfile"

#
# Initialize a new monthly cumulative file, if necessary:
#

if [ ! -f $jfile ]; then		# only necessary if it doesn't already exist
	touch $jfile
	if [ $? -eq  0 ]; then
		echo "Created new monthly journal file $jfile."
		sleep 1
	else
		echo "Could not create new journal file $jfile. Aborting."
		exit 1
	fi
	chmod $FILEPERMS $jfile		# Assign perms to journal file

	if [ $crypt = Y ]; then		# if encrypting, insert sig line
		echo "\
------------------- `logname`'s encrypted Journal file for `date \"+%h %y\"` ------------------\
\n\n" | crypt $key >> $jfile
	else
		echo "\
------------------- `logname`'s plain text Journal file for `date \"+%h %y\"` ------------------\
\n\n" >> $jfile
	fi
else							# journal file does exist...
	if [ $crypt = Y ]; then		# check key synchronization
		crypt $key < $jfile | head -1 | grep Journal >/dev/null
		if [ $? -ne 0 ]; then	# abort if no sig text after decryption
			echo "Current journal file $jfile encrypted with a different key."
			exit 1
		fi
	fi
fi

#
# Perform jsee logic:
#

if [ $cmdname = jsee ]; then
	touch /tmp/jsee$$
	chmod $FILEPERMS /tmp/jsee$$
	if [ $crypt = Y ]; then					# If using encrption, then:
		crypt $key <$jfile >>/tmp/jsee$$	# decrypt into temp file
		ed_invoke /tmp/jsee$$				# edit the temp file
		crypt $key </tmp/jsee$$ >$jfile		# encrypt back into cum. file
		rm /tmp/jsee$$						# remove temp file
	else
		ed_invoke $jfile					# Simple edit if no encryption.
	fi		
	echo "Journal file $jfile updated."
	exit 0
fi

#
# Perform j logic:
#

date=`date "+%a  %h %d, 19%y"`					# initialize new entry file
[ $crypt = Y ] && cryptmsg="  (Encrypted)"		# include encryption notice
echo "$TABS$date$cryptmsg\n" >> /tmp/journ$$

echo "Starting up your text editor on a new journal entry. . ."

ed_invoke /tmp/journ$$							# create the new entry

if [ $crypt = Y ]; then							# if encrypting,	
	crypt $key < $jfile | cat - /tmp/journ$$ |	# decrypt cum. file, append
				 crypt $key  > /tmp/journ2$$	# new entry, re-encrypt,
	mv /tmp/journ2$$ $jfile						# and replace originl cum. file
	chmod $FILEPERMS $jfile
else											# if not encrypting,
	cat /tmp/journ$$ >> $jfile					# then just append the entry
fi

rm /tmp/journ$$
clear
echo "Entry appended onto journal file $jfile."
