Listing 1: j/jsee
1: #
2: # j/jsee: Personal Journal Management Program
3: # Written by Leor Zolman, 3/93
4:
5: DEBUG=N # If Y, use current dir for JOURN_DIR and show debug info
6:
7: #
8: # Usages:
9: # j [ - (or) -e (or) -ekey ] [journal-dir]
10: # jsee [ - (or) -e (or) -ekey ] [journal-dir (or) journal-file-basename ]
11: #
12: #
13: # Encryption Control
14: # ------------------
15: #
16: # Whether or not j/jsee employs encryption is controlled by the command
17: # line format and several environment variables:
18: #
19: # JCRYPT If defined as Y outside j/jsee, encryption is enabled
20: # by default, unless superceded by the "-" option
21: # ASK_CRYPT Y to have j/jsee verify encryption if JCRYPT is true
22: #
23: #
24: # With no configuration whatsoever, encryption is disabled by default.
25: # If the command line options -e or -e<key> are used, then encryption is
26: # enabled.
27: #
28: # Encryption may be turned on by default for all j/jsee sessions by
29: # setting JCRYPT to Y in your environment. Then, if ASK_CRYPT is set to Y in
30: # the code, then j/jsee will ask for a confirmation before using encryption.
31: # If JCRYPT is Y and ASK_CRYPT is N, no confirmation is required.
32: #
33: # If the "-" option appears on the command line, encryption is NEVER used.
34: # Use this to disable encryption regardless of the value of JCRYPT in
35: # your shell environment.
36: #
37: #
38: # Getting the value of the encryption key from the user
39: # -----------------------------------------------------
40: #
41: # CRYPT_KEY_VAR Name of env var containing encryption key
42: #
43: # It is not a good idea to store the encryption key in any file on the system,
44: # nor to supply it on the j/jsee command line via the -e<key> option (for
45: # security reasons.) So, there needs to be a secure way for the user to inform
46: # j/jsee of the key value. If the user assigns a value to the environment
47: # variable whose name is stored in CRYPT_KEY_VAR before running j/jsee (as,
48: # for example, through use of the key() shell function), then j/jsee uses
49: # that value as the encryption key. If the variable named by CRYPT_KEY_VAR
50: # is null, then j/jsee prompts the user to enter the encryption key at
51: # each run.
52: #
53: # How j/jsee supplies the encryption key to the crypt program
54: # -----------------------------------------------------------
55: #
56: # CRYPT_HAS_K Y if your version of crypt supports the -k option
57: #
58: # If CRYPT_HAS_K is N, then j/jsee is obliged to include the encryption
59: # key as part of the crypt command line (least secure, since the key
60: # is potentially visible to users running the ps command at just the
61: # right moment.)
62: #
63: # If CRYPT_HAS_K is Y, then j/jsee passes the key to crypt by making sure
64: # that the environment variable named by CRYPT_KEY_VAR contains the key
65: # value, and specifying -k alone on the crypt command line.
66: #
67: #
68: # What j does:
69: # ------------
70: #
71: # j creates a journal entry and appends it to the appropriate current monthly
72: # incremental journal file in the JOURN_DIR directory (or, if the subdir
73: # argument was given, the named subdirectory of JOURN_DIR). If encryption is
74: # used, then a journal file having an extension of ".txe" is used; otherwise,
75: # the journal file having the extension ".txt" is used. By having two files
76: # for each month, one encrypted (.txe) and one plain (.txt), we avoid the
77: # potential inadvertant mixing of encrypted and non-encrypted text within a
78: # a single file.
79: #
80: # When using j, the journal filename (less extension) is always of the
81: # form YY-MM, where YY is the 2-digit year and MM is the two-digit
82: # month (with leading 0's if required.)
83: #
84: #
85: # What jsee does:
86: # ---------------
87: #
88: # When invoked without any name argument, jsee brings up the current month's
89: # cumulative journal file on the screen in your editor, and you may edit
90: # it as desired. This form is used to make changes to an existing entry,
91: # as opposed to creating a new entry. Whether the encrypted or non-
92: # encrypted file is used depends on whether encryption is enabled (as
93: # described above).
94: #
95: # When the argument to jsee is the name of a subdirectory of the $JOURN_DIR
96: # directory, then jsee operates on the current month's cumulative journal
97: # file in the named subdirectory.
98: #
99: # When supplied an explicit journal pathname (without extension), then
100: # jsee operates on the file whose pathname is specified. In this case,
101: # $JOURN_DIR is NOT pre-pended to the filename, so a conventional full
102: # or relative path name must be specified. The extension implicitly added
103: # to the supplied pathname is dependent upon the encryption status as
104: # determined above.
105: #
106: #
107: # Automatic encryption key synchronization
108: # ----------------------------------------
109: #
110: # Both j and jsee guard against inadvertant mixed encryption keys being
111: # applied to the same single montly journal file. Whenever encryption is
112: # called for in conjunction with the examination of (jsee) or appending
113: # to (j) a cumulative monthly journal file, the cumulative file is first
114: # decrypted using the specified key and the first line is examined for
115: # the presence of the signature text "Journal" (whenever a cumulative
116: # journal file is created, a line containing that text is always written
117: # at the beginning). If the signature text is not found, no further action
118: # is taken. Users should never delete or insert any lines before this
119: # signature header line.
120: #
121:
122: ######### User-Customizable Definitions #################################
123:
124: JOURN_DIR=$HOME/.Journ # Directory where journal text kept
125: [ $DEBUG = Y ] && JOURN_DIR=. # When debugging, force current dir
126:
127: # System-dependent features:
128:
129:
130: if [ -z "$CRYPT_KEY_VAR" ] # If already set, don't mess with it...
131: then
132: CRYPT_KEY_VAR=CRYPTKEY # env var holding key (for use with -k)
133: # CRYPT_KEY_VAR=CrYpTkEy # SCO Unix variation
134: fi
135:
136: #CRYPT_HAS_K=N # XENIX's crypt does not support -k option
137: CRYPT_HAS_K=Y # SCO UNIX's crypt does support -k option
138:
139: ASK_CRYPT=N # Y=Query encryption if JCRYPT true, N=assume yes
140:
141: EDITOR=/usr/local/e.old # Text editor
142: EPSILON=N # Y if using Epsilon as text editor
143: MICRO_EMACS=Y # Y if using microEMACS as text editor
144: TABS="\t\t\t\t\t\t\t\t" # string to precede date string for each entry
145:
146: FILEPERMS=600 # Permissions to assign to cumulative text files
147: DIRPERMS=700 # Perms to assign to JOURN_DIR and its subdirs
148:
149: ############ End of User-Customizable Definitions ###########################
150:
151: cmdname=`basename $0` # j or jsee
152: crypt=N # start out without encryption (by default)
153:
154: jdir=$JOURN_DIR # default Journal directory
155: monthly=`date +"%y-%m"`
156: jfile=$monthly # default Journal file
157: name_given=N # whether or not name parameter supplied
158:
159: usage() {
160: echo "Usages:"
161: echo " j [-[e[key]]] [journal-subdir]"
162: echo " jsee [-[e[key]]] [journal-subdir (or) journal-file-basename]"
163: exit 0
164: }
165:
166: #
167: # ed_invoke(): Invoke the text editor on the named file, with
168: # initializations and command line usage approproate
169: # to the particular editor used (microEMACS and Epsilon
170: # initializations pre-configured.)
171: # Exit the program if the file is not changed after the
172: # editing session.
173: #
174:
175: ed_invoke() {
176: sav_stats=`ls -l $1`
177:
178: if [ $MICRO_EMACS = Y ]; then
179: echo "find-file $1
180: set \$hardtab 4
181: add-mode \"wrap\"
182: end-of-file" > /tmp/erc$$
183: $EDITOR @/tmp/erc$$
184: rm /tmp/erc$$
185: elif [ $EPSILON = Y ]; then
186: $EDITOR $1 +3
187: else
188: $EDITOR $1
189: fi
190: clear
191:
192: if [ ! -f $1 ]; then
193: echo "Arghhh! The file $1 has disappeared! What did you DO? Aborting."
194: exit 1
195: fi
196:
197: if [ "`ls -l $1`" = "$sav_stats" ]; then
198: echo "You didn't change anything. No update performed."
199: rm $1
200: exit 0
201: fi
202: }
203:
204:
205: #
206: # get_key(): Obtain the encryption key.
207: # If the environment variable named by CRYPT_KEY_VAR is
208: # defined, then use its value as the encryption key.
209: # If not, then prompt the user for the key string and
210: # read it from the standard input (without echo).
211: #
212:
213: get_key() {
214: eval "key=\$$CRYPT_KEY_VAR"
215: if [ -z "$key" ]; then # key defined in environment?
216: trap "stty echo; exit 1" 1 2 3 14 15 # if not, prompt for it now
217: stty -echo
218: echo "Enter encryption key: \c"
219: read key
220: stty echo
221: echo
222: if [ -z "$key" ]; then
223: echo "Null key invalid. Must enter some text."
224: exit 1
225: fi
226: fi
227: }
228:
229:
230: #
231: # test_k(): if crypt program supports -k option (CRYPT_HAS_K is Y), then
232: # set the key variable named by CRYPT_KEY_VAR to the key value
233: # stored in the $key variable.
234: #
235:
236: test_k() { # determine if we can use -k:
237: if [ $CRYPT_HAS_K = Y ] # if -k supported,
238: then
239: eval "$CRYPT_KEY_VAR=$key" # export key into environment
240: eval "export $CRYPT_KEY_VAR"
241: key=-k # use -k alone in crypt commands
242: fi
243: }
244:
245: #
246: # ask(): ask user a yes/no question
247: # Return Y on std output if answer is yes, else N.
248: # usage: ask "string"
249: # ( " (y/n)? " automatically appended to the string)
250: #
251:
252: ask()
253: {
254: while true
255: do
256: echo "$1 (y/n)? \c" >&2
257: read answer
258: case $answer in
259: [Nn]*) echo "N"
260: break;;
261: [Yy]*) echo "Y"
262: break;;
263: *) echo 'Please answer "y" or "n"...' >&2
264: esac
265: done
266: }
267:
268:
269: echo "Electronic Journal Management System v3.0\n"
270:
271: #
272: # Create master journal directory if not already there
273: #
274:
275: if [ ! -d $JOURN_DIR ]; then
276: echo "Master Journal directory $JOURN_DIR does not exist. Creating..."
277: if mkdir $JOURN_DIR
278: then
279: echo "$JOURN_DIR created successfully."
280: chmod $DIRPERMS $JOURN_DIR
281: else
282: echo "Could not create $JOURN_DIR. Aborting."
283: exit 1
284: fi
285: fi
286:
287: #
288: # Process command line arguments:
289: #
290:
291: case $# in
292: 1) if echo $1 | grep "^-" >/dev/null
293: then
294: OPTS=$1
295: else
296: name_given=Y
297: case $cmdname in
298: j) jdir=$jdir/$1;;
299: jsee) jfile=$1;;
300: esac
301: fi;;
302: 2) if echo $1 | grep "^-" >/dev/null
303: then
304: OPTS=$1
305: case $cmdname in
306: j) jdir=$jdir/$2;;
307: jsee) jfile=$2;;
308: esac
309: elif echo $2 | grep "^-" >/dev/null
310: then
311: OPTS=$2
312: case $cmdname in
313: j) jdir=$jdir/$1;;
314: jsee) jfile=$1;;
315: esac
316: else
317: usage
318: fi
319: name_given=Y;;
320: esac
321:
322: if [ $DEBUG = Y ]; then
323: echo "OPTS = $OPTS, jdir = $jdir, jfile = $jfile, crypt = $crypt"
324: fi
325:
326: if [ "$OPTS" = - ]; then # disable encryption?
327: crypt=N
328: elif echo "$OPTS" | grep "^-e" >/dev/null # -e option specified?
329: then
330: crypt=Y # yes. turn on encryption.
331: if [ "$OPTS" = -e ]; then # -e alone?
332: get_key
333: else # -ekey specified....
334: key=`echo $OPTS | sed s/-e//p` # extract key from cmd line
335: fi
336: test_k # choose best way to pass crypt key
337: elif [ "$JCRYPT" = Y ]; then # encryption flag in environment set?
338: if [ $ASK_CRYPT = Y ]; then # if so, does user need to verify?
339: crypt=`ask "Encrypt"` # yes, prompt user for verification
340: else
341: crypt=Y # no, just go ahead and use encryption
342: fi
343:
344: if [ $crypt = Y ]; then
345: get_key # get the key
346: test_k # and use -k if possible
347: fi
348: fi
349:
350: if [ $crypt = Y ]; then
351: EXT=txe
352: else
353: EXT=txt
354: fi
355:
356: if [ $cmdname = jsee ]; then
357: case $name_given in
358: N) if [ ! -r $jdir/$jfile.$EXT ]; then
359: echo "No file $jdir/$jfile.$EXT."
360: exit 1
361: fi;;
362: Y) if [ ! -r $jfile.$EXT ]; then
363: save_name=$jfile.$EXT
364: jdir=$JOURN_DIR/$jfile
365: jfile=$monthly.$EXT
366: if [ ! -r $jdir/$jfile ]; then
367: echo "Can't locate filespec \"$save_name\""
368: exit 1
369: fi
370: fi;;
371: esac
372: fi
373:
374: if [ $DEBUG = Y ]; then
375: echo "crypt=$crypt, key=$key, \c"
376: echo "\$$CRYPT_KEY_VAR=\c"
377: eval "echo \$$CRYPT_KEY_VAR"
378: echo "jdir = $jdir"
379: echo "Press Return to continue...."
380: read dummy
381: fi
382:
383: #
384: # Check to make sure an explicitly named j subdirectory exists
385: #
386:
387: if [ $cmdname = j -a ! -d $jdir ]; then
388: echo "Journal sub-directory $jdir does not exist. Creating it..."
389: if mkdir $jdir
390: then
391: chmod $DIRPERMS $jdir
392: echo "$jdir created successfully."
393: sleep 1
394: else
395: echo "Could not create $jdir. Aborting."
396: exit 1
397: fi
398: fi
399:
400: #
401: # Establish name of cumulative journal file we'll be working with:
402: #
403:
404: jfile=$jdir/$jfile
405: if [ $cmdname = jsee -a -r $jfile ]; then
406: :
407: else
408: jfile=$jfile.$EXT
409: fi
410:
411: [ $DEBUG = Y ] && echo "jfile = $jfile"
412:
413: #
414: # Initialize a new monthly cumulative file, if necessary:
415: #
416:
417: if [ ! -f $jfile ]; then # only necessary if it doesn't already exist
418: touch $jfile
419: if [ $? -eq 0 ]; then
420: echo "Created new monthly journal file $jfile."
421: sleep 1
422: else
423: echo "Could not create new journal file $jfile. Aborting."
424: exit 1
425: fi
426: chmod $FILEPERMS $jfile # Assign perms to journal file
427:
428: if [ $crypt = Y ]; then # if encrypting, insert sig line
429: echo "\
430: --- `logname`'s encrypted Journal file for `date \"+%h %y\"` ------------------\
431: \n\n" | crypt $key >> $jfile
432: else
433: echo "\
434: --- `logname`'s plain text Journal file for `date \"+%h %y\"` ------------------\
435: \n\n" >> $jfile
436: fi
437: else # journal file does exist...
438: if [ $crypt = Y ]; then # check key synchronization
439: crypt $key < $jfile | head -1 | grep Journal >/dev/null
440: if [ $? -ne 0 ]; then # abort if no sig text after decryption
441: echo "Current journal file $jfile encrypted with a different key."
442: exit 1
443: fi
444: fi
445: fi
446:
447: #
448: # Perform jsee logic:
449: #
450:
451: if [ $cmdname = jsee ]; then
452: touch /tmp/jsee$$
453: chmod $FILEPERMS /tmp/jsee$$
454: if [ $crypt = Y ]; then # If using encrption, then:
455: crypt $key <$jfile >>/tmp/jsee$$ # decrypt into temp file
456: ed_invoke /tmp/jsee$$ # edit the temp file
457: crypt $key </tmp/jsee$$ >$jfile # encrypt back into cum. file
458: rm /tmp/jsee$$ # remove temp file
459: else
460: ed_invoke $jfile # Simple edit if no encryption.
461: fi
462: echo "Journal file $jfile updated."
463: exit 0
464: fi
465:
466: #
467: # Perform j logic:
468: #
469:
470: date=`date "+%a %h %d, 19%y"` # initialize new entry file
471: [ $crypt = Y ] && cryptmsg=" (Encrypted)" # include encryption notice
472: echo "$TABS$date$cryptmsg\n" >> /tmp/journ$$
473:
474: echo "Starting up your text editor on a new journal entry. . ."
475:
476: ed_invoke /tmp/journ$$ # create the new entry
477:
478: if [ $crypt = Y ]; then # if encrypting,
479: crypt $key < $jfile | cat - /tmp/journ$$ | # decrypt cum. file, append
480: crypt $key > /tmp/journ2$$ # new entry, re-encrypt,
481: mv /tmp/journ2$$ $jfile # and replace originl cum. file
482: chmod $FILEPERMS $jfile
483: else # if not encrypting,
484: cat /tmp/journ$$ >> $jfile # then just append the entry
485: fi
486:
487: rm /tmp/journ$$
488: clear
489: echo "Entry appended onto journal file $jfile."
|