1#!/bin/sh
2#
3# @(#)  /u/des/src/sortmail/sortmail  1.20  00/07/28  18:37:09
4#
5# sortmail: automate decomposemail & recomposemail
6#
7# See "USAGE" and "SUMMARY" below for more information.
8#
9# 10/96, D.Singer
10#
11#
12# Copyright (c) 1998 by Daniel E. Singer.  All rights reserved.
13# Permission is granted to reproduce and distribute this program
14# with the following conditions:
15#   1) This copyright notice and the author identification below
16#      must be left intact in the program and in any copies.
17#   2) Any modifications to the program must be clearly identified
18#      in the source file.
19#
20# Written by:
21#   Daniel E. Singer
22#   UNIX Systems Administrator
23#   Department of Computer Science
24#   Duke University, Durham, NC
25#   Phone: 919/660-6500
26#   Email: des@cs.duke.edu
27#
28
29
30#
31# add a PATH if needed
32#
33#PATH='/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb:/usr/bsd:/usr/etc:/usr/gnu/bin:/usr/local/bin'
34#export PATH
35
36PATH=$PATH:/home/lasse/work
37export PATH
38
39PROG=`basename "$0"`
40
41umask 077	# create files and dirs with restrictive perms,
42		# since this involves email;
43
44WORK_DIR="SM_WORK"	# where work will be done
45BACKUP_DIR="SM_BACKUP"	# where backups will be stored
46
47#
48# SRC_DIR and SRC_PATH refer to the relative starting location of this script;
49# usually we will be working from a subdirectory;  these are altered when
50# using the -H (Here) flag;
51#
52SRC_DIR=".."
53SRC_PATH="../"
54
55#
56# these scripts must be accessible for any of this to work;
57# add paths if needed;
58#
59DECOMPOSE="decomposemail"
60RECOMPOSE="recomposemail"
61
62USAGE="
63Usage:	$PROG [-chHmMyYrRvx] mbox...
64
65	  -c	move current month mbox back to source dir mbox, implies -r
66		(use with -m, -M, -y, or -Y);
67	  -h	help, print help message and exit;
68	  -H	here, do work in this dir instead of in \"./$WORK_DIR\" dir;
69	  -m	sort to monthly mailboxes of type mbox.YYMM;
70	  -M	sort to monthly mailboxes of type YYMM/mbox;
71	  -y	sort to yearly mailboxes of type mbox.YYYY;
72	  -Y	sort to yearly mailboxes of type YYYY/mbox;
73		with -m, yields YYYY/mbox.MM;
74		with -M, yields YYYY/MM/mbox;
75	  -r	remove the original mailbox after sort/merging;
76	  -R	recurse, redo any appended mailboxes (use with -m, -M, -y,
77		or -Y);
78	  -v	verbose, more messages;
79	  -x	don't make any backup copies in \"./$BACKUP_DIR\" dir;
80"
81
82SUMMARY="
83'sortmail' automates the scripts 'decomposemail' and 'recomposemail',
84and provides some additional functionality.
85
86Default behavior is to take each mbox (mailbox) argument, make a copy,
87decompose it into individual message files, and then recompose the
88messages, ordered by date in increasing order.
89
90With the '-m' flag, the messages are re-assembled into separate files
91per month, mbox.YYMM.  For example, \"mlist.9801\".
92
93With the '-M' flag, the messages are re-assembled into separate files
94per month in subdirectories, YYMM/mbox.  For example, \"9801/mlist\".
95
96With the '-y' flag, the messages are re-assembled into separate files
97per year, mbox.YYYY.  For example, \"mlist.1998\".
98
99With the '-Y' flag, the messages are re-assembled into separate files
100per year in subdirectories, YYYY/mbox.  For example, \"1998/mlist\".
101If combined with '-m', the files have a month suffix, for example,
102\"1998/mlist.01\".  If combined with '-M', the files have an additional
103month sudirectory, for example, \"1998/01/mlist\".
104
105With the '-c' flag (along with -m, -M, -y, or -Y), the mbox file for
106the current month (if any) will be moved into the location of the
107original mbox.
108
109With the '-R' flag (along with -m, -M, -y, or -Y), when a month file
110is combined with one that already exists, the resulting file will be
111re-sorted.  If any such existing files are compressed (.Z or .gz),
112they will be uncompressed and then recompressed after being modified.
113
114With the '-H' flag, all work is done in the current directory instead
115of in the \"./$WORK_DIR\" directory.  This reduces the usefulness of
116some of the other options, and is a bit riskier regarding your original
117mboxes.
118
119By default, all work is done in a subdirectory \"./$WORK_DIR\", and
120all files to be modified are backed up in a subdirectory \"./$BACKUP_DIR\".
121These subdirectories are created if they don't already exist.
122
123Due to copies made during the sorting process, you should have enough
124additional space in your current partition and/or quota to hold three
125full copies of each original mbox.
126
127Much of this can be accomplished using 'decomposemail' and 'recomposemail'
128directly, but many more manual steps are required.
129"
130
131# for use with 'eval'
132CMD='echo "$PROG: $cmd" >&2; eval "$cmd"'
133
134CURRENT=0	# current flag (-c)
135DEBUG=0		# debug flag (-d)
136HERE=0		# here flag (-H)
137MFLAG=0		# month flag (-m), merge to mbox.yymm
138MMFLAG=0	# Month flag (-M), merge to yymm/mbox
139PASS_MFLAG=	# month flag to pass to other scripts
140YFLAG=0		# year flag (-y), merge to mbox.yyyy
141YYFLAG=0	# Year flag (-Y), merge to yyyy/mbox
142PASS_YFLAG=	# year flag to pass to other scripts
143RECURSE=0	# recurse flag (-R)
144REMOVE=0	# remove flag (-r)
145VERBOSE=0	# verbose flag (-v)
146PASS_VFLAG=	# verbose flag to pass to other scripts
147BACKUP=1	# backup flag (! -x)
148
149# these are some possible combination of the date sort flags,
150# and are compared against SMODE
151no_SORT="0000"	# no date sorting at all
152 m_SORT="0001"	# -m
153 M_SORT="0011"	# -M
154 y_SORT="0100"	# -y
155 Y_SORT="1100"	# -Y
156Ym_SORT="1101"	# -Y and -m
157YM_SORT="1111"	# -Y and -M
158  SMODE="$no_SORT" # sort mode, a combination of the date sort flags
159
160USE_DATES=0	# will be using dates (any of -[mMyY])
161USE_DIRS=0	# will be using subdirs (any of -[MY])
162
163#
164# platform specific settings
165#
166AWK=awk
167SYS="`uname -sr`"      # OS type
168case "$SYS" in
169  "SunOS "*)
170        AWK=nawk
171  esac
172
173#
174# function to append items to a newline-separated list;
175# list goes to stdout;
176# Usage:  NEW_LIST=`append_list "$LIST" "$ITEM"`
177#
178append_list() {
179	for _AL_ARG do
180		[ "$_AL_ARG" ] && echo "$_AL_ARG"
181	  done
182	return
183}
184
185#
186# function to move a file to a unique name with numeric extension;
187# eg, file => file.1;
188# argument should be the path to a file
189# Usage:  rotate_file "$FILE"
190#
191rotate_file() {
192	_RF_FILE="$1"
193	if [ -f "$_RF_FILE" ]; then
194		_RF_EXT=1
195		while [ -f "$_RF_FILE.$_RF_EXT" ]; do
196			_RF_EXT=`expr "$_RF_EXT" '+' '1'`
197		  done
198		cmd="mv \"$_RF_FILE\" \"$_RF_FILE.$_RF_EXT\""
199		eval "$CMD" ||
200		  return 1
201	  fi
202	return 0
203}
204
205#
206# process command line options
207#
208
209syntax_error() {
210	echo "$PROG: option syntax error." >&2
211	echo "$USAGE" >&2
212	exit 1
213}
214
215unknown_opt() {
216	echo "$PROG: unknown option \"$OPT\"." >&2
217	echo "$USAGE" >&2
218	exit 1
219}
220
221#arg_syntax_check() {
222#	[ "$1" -lt 2 ] && syntax_error
223#}
224
225while [ "$#" -gt 0 ]; do
226	OPT="$1"
227	case "$OPT" in
228	  # options without arguments
229	  -c)	# replace original mbox with current month
230		CURRENT=1
231		REMOVE=1
232		;;
233	  -d)	# debug, many commands are not executed
234		echo "$PROG: debug mode." >&2
235		CMD='echo "$PROG: $cmd" >&2'
236		DEBUG=1
237		;;
238	  -h)	# help
239		echo "
240<< `$AWK <&- 'BEGIN { print toupper(\"'\"$PROG\"'\"); }'` >>
241$SUMMARY$USAGE"
242		exit 0
243		;;
244	  -H)	# do the work in this dir, not "./$WORK_DIR"
245		HERE=1
246		SRC_DIR="."
247		SRC_PATH=
248		;;
249	  -m)	# sort to mbox.YYMM
250		MFLAG=1
251		PASS_MFLAG=" -m"
252		;;
253	  -M)	# sort to YYMM/mbox
254		MMFLAG=1
255		PASS_MFLAG=" -M"
256		;;
257	  -y)	# sort to mbox.YYYY
258		YFLAG=1
259		PASS_YFLAG=" -y"
260		;;
261	  -Y)	# sort to YYYY/mbox
262		YYFLAG=1
263		PASS_YFLAG=" -Y"
264		;;
265	  -r)	# remove the original
266		REMOVE=1
267		;;
268	  -R)	# recurse, resort appended files
269		RECURSE=1
270		;;
271	  -v)	# verbose
272		VERBOSE=1
273		PASS_VFLAG=" -v"
274		;;
275	  -x)	# don't make backup copy
276		BACKUP=0
277		;;
278	#  # options with arguments
279	#  -c)
280	#	CFLAG=1
281	#	arg_syntax_check "$#"
282	#	CARG="$2"
283	#	shift
284	#	;;
285	  --)	# no more flags
286		shift
287		break
288		;;
289
290	  # unknown option
291	  -?)
292		syntax_error
293		;;
294	  # compound option
295	  -??*)
296		# break up a compound option
297		NEW_OPTS=`$AWK 'BEGIN {
298			OPT_STR = "'"$OPT"'";
299			LEN = length(OPT_STR);
300			NEW_OPTS = "";
301			STATUS = 0;
302			for (POS=2; POS+0 <= LEN; ++POS) {
303				OPT = substr(OPT_STR,POS,1);
304				if (OPT !~ /[a-zA-Z0-9_]/)
305					STATUS = 1;
306				NEW_OPTS = NEW_OPTS " -" OPT;
307			}
308			print NEW_OPTS;
309			exit STATUS;
310		  }' <&-` || {
311			syntax_error
312		  }
313		shift
314		if [ "$#" -gt 0 ]; then
315			set -- $NEW_OPTS "$@"
316		  else
317			set -- $NEW_OPTS
318		  fi
319		continue
320		;;
321	  # end of options, just command arguments left
322	  *)
323		break
324	  esac
325	shift
326  done
327
328# some options don't mix
329case "$MFLAG$MMFLAG" in
330  11)
331	echo "$PROG: use only one of -m and -M." >&2
332	echo "$USAGE" >&2
333	exit 1
334	;;
335  01)
336	# this will make some tests below easier
337	MFLAG=1
338  esac
339case "$YFLAG$YYFLAG" in
340  11)
341	echo "$PROG: use only one of -y and -Y." >&2
342	echo "$USAGE" >&2
343	exit 1
344	;;
345  01)
346	# this will make some tests below easier
347	YFLAG=1
348  esac
349
350[ "$MFLAG" = 1 -o "$YFLAG" = 1 ] && USE_DATES=1
351[ "$MMFLAG" = 1 -o "$YYFLAG" = 1 ] && USE_DIRS=1
352
353case "$RECURSE$USE_DATES" in
354  10)
355	echo "$PROG: -R only works with -m, -M, -y, or -Y." >&2
356	echo "$USAGE" >&2
357	exit 1
358  esac
359case "$CURRENT$USE_DATES" in
360  10)
361	echo "$PROG: -c only works with -m, -M, -y, or -Y." >&2
362	echo "$USAGE" >&2
363	exit 1
364  esac
365case "$RECURSE$HERE" in
366  11)
367	echo "$PROG: -R and -H do not mix." >&2
368	echo "$USAGE" >&2
369	exit 1
370  esac
371#
372# check for other bad date option combos, and set SMODE (sort mode)
373#
374SMODE="$YYFLAG$YFLAG$MMFLAG$MFLAG"
375case "$SMODE" in
376  "$no_SORT") ;;
377  "$y_SORT") ;;
378  "$Y_SORT") ;;
379  "$m_SORT") ;;
380  "$M_SORT") ;;
381  "$Ym_SORT") ;;
382  "$YM_SORT") ;;
383  *)
384	echo "$PROG: cannot mix -y with -m or -M." >&2
385	echo "$USAGE" >&2
386	exit 1
387  esac
388
389#
390# must have at least one mailbox arg
391#
392if [ "$#" = 0 ]; then
393	echo "$PROG: need to specify one or more mailboxes." >&2
394	echo "$USAGE" >&2
395	exit 1
396  fi
397
398#
399# check that all mailboxes are accessible before starting;
400# also, see if any match files that are zipped;
401#
402ERROR=0
403NEW_MB_LIST=
404IS_NEW_LIST=0
405for MB do
406	if [ ! -f "$MB" ]; then
407		case "$MB" in
408		  *'.Z'|*'.gz')
409			;;
410		  *)
411			if [ -f "$MB.Z" ]; then
412				MB="$MB.Z"
413				IS_NEW_LIST=1
414			  elif [ -f "$MB.gz" ]; then
415				MB="$MB.gz"
416				IS_NEW_LIST=1
417			  fi
418		  esac
419	  fi
420
421	NEW_MB_LIST=`append_list "$NEW_MB_LIST" "$MB"`
422
423	if [ ! -f "$MB" ]; then
424		echo "$PROG: no such file \"$MB\"." >&2
425		ERROR=1
426	  elif [ ! -r "$MB" ]; then
427		echo "$PROG: cannot read \"$MB\"." >&2
428		ERROR=1
429	  fi
430  done
431#
432# if the mailbox list has been modified, set the new list to the
433# positional parameter list
434#
435if [ "$ERROR" = 1 ]; then
436	exit 1
437  elif [ "$IS_NEW_LIST" = 1 ]; then
438	set -f
439	_IFS="$IFS"
440	IFS='
441'
442	set -- $NEW_MB_LIST
443	IFS="$_IFS"
444	set +f
445  fi
446
447echo "$PROG: Begin..." >&2
448
449#
450# make backup dir?
451#
452if [ "$BACKUP" = 1 ]; then
453	if [ ! -d "$BACKUP_DIR" ]; then
454		cmd="mkdir \"$BACKUP_DIR\""
455		eval "$CMD" || {
456			echo "$PROG: cannot create dir \"$BACKUP_DIR\"." >&2
457			exit 1
458		}
459	  fi
460  fi
461
462#
463# make and/or 'cd' WORKDIR?
464#
465if [ "$HERE" = 0 ]; then
466	if [ ! -d "$WORK_DIR" ]; then
467		cmd="mkdir \"$WORK_DIR\""
468		eval "$CMD" || {
469			echo "$PROG: cannot create dir \"$WORK_DIR\"." >&2
470			exit 1
471		}
472	  fi
473	cmd="cd \"$WORK_DIR\""
474	eval "$CMD" || {
475		echo "$PROG: cannot change to dir \"$WORK_DIR\"." >&2
476		exit 1
477	}
478  fi
479echo "$PROG: working directory is \"`pwd`\"..." >&2
480
481if [ "$CURRENT" = 1 ]; then
482	#
483	# set current date vars C_Y4, C_Y2, C_M2,
484	# for use with CURRENT option
485	#
486	eval `date '+C_Y4="%Y" C_Y2="%y" C_M2="%m"'`
487  fi
488
489
490##
491## each command line mailbox
492##
493for MB do
494#
495	#
496	# MB_DIR and MB_PATH are the relative or absolute path to the
497	# original mailbox;
498	# MB will become the basename of the mbox;
499	#
500	MB_DIR=
501	MB_PATH=
502	#
503	# resolve some mbox path issues
504	#
505	MB_BASE=`basename "$MB"`
506	if [ "./$MB_BASE" = "$MB" ]; then
507		MB="$MB_BASE"
508	  fi
509	case "$MB" in
510	  /*)
511		# absolute path
512		MB_DIR=`dirname "$MB"`
513		MB_PATH="$MB_DIR/"
514		MB=`basename "$MB"`
515		;;
516	  */*)
517		# relative path
518		MB_DIR="$SRC_PATH"`dirname "$MB"`
519		MB_PATH="$MB_DIR/"
520		MB=`basename "$MB"`
521		;;
522	  *)
523		# initial directory
524		MB_DIR="$SRC_DIR"
525		MB_PATH="$SRC_PATH"
526	  esac
527
528	echo "
529$PROG: sorting mailbox \"$MB_PATH$MB\" ..." >&2
530
531	# presumably this has already been checked;
532	# if file is not found, there's definitely a problem...
533	if [ ! -f "$MB_PATH$MB" ]; then
534		echo "$PROG: no such file \"$MB_PATH$MB\"." >&2
535		exit 1
536	  fi
537
538	#
539	# make a backup copy?
540	#
541	if [ "$BACKUP" = 1 ]; then
542		echo "
543$PROG: backing up mailbox \"$SRC_DIR/$MB\" ..." >&2
544		# if there's already a copy, move it, don't overwrite
545		rotate_file "$SRC_PATH$BACKUP_DIR/$MB" || {
546			echo "$PROG: cannot rotate file \"$SRC_PATH$BACKUP_DIR/$MB\"." >&2
547			exit 1
548		}
549
550		cmd="cp \"$MB_PATH$MB\" \"$SRC_PATH$BACKUP_DIR\""
551		eval "$CMD" || {
552			echo "$PROG: cannot copy \"$MB_PATH$MB\" to \"$SRC_PATH$BACKUP_DIR\"." >&2
553			exit 1
554		}
555	  fi
556
557	#
558	# get a copy of the source file;
559	# if REMOVE, then just move it here;
560	#
561	if [ "$MB_DIR" != "." ]; then
562		if [ "$REMOVE" = 1 ]; then
563			echo "
564$PROG: moving mailbox \"$MB_PATH$MB\" to working directory ..." >&2
565			cmd="mv \"$MB_PATH$MB\" \"./$MB\""
566			_STR=move
567		  else
568			echo "
569$PROG: copying mailbox \"$MB_PATH$MB\" to working directory ..." >&2
570			cmd="cp \"$MB_PATH$MB\" \"./$MB\""
571			_STR=copy
572		  fi
573		eval "$CMD" || {
574			echo "$PROG: cannot $_STR \"$MB_PATH$MB\" to \"./$MB\"." >&2
575			exit 1
576		}
577	  fi
578
579	#
580	# do the decomposition, producing a file for each message in the mbox;
581	# if it's a zipped file, DECOMPOSE can deal with it as is;
582	#
583	echo "" >&2
584	cmd="$DECOMPOSE$PASS_VFLAG \"$MB\""
585	eval "$CMD" || {
586		echo "$PROG: problem disassembling \"$MB\"." >&2
587		exit 1
588	}
589
590	#
591	# get rid of ./copy, or
592	# get rid of ./orig if REMOVE;
593	#
594	if [ "$MB_DIR" != '.' ]; then
595		echo "
596$PROG: removing working copy of mailbox \"$MB\" ..." >&2
597		cmd="rm \"$MB\""
598		eval "$CMD" || {
599			echo "$PROG: cannot remove \"$MB\"." >&2
600			exit 1
601		}
602	  elif [ "$REMOVE" = 1 -o "$USE_DATES" = 0 ]; then
603		echo "
604$PROG: removing original copy of mailbox \"$MB\" ..." >&2
605		cmd="rm \"$MB\""
606		eval "$CMD" || {
607			echo "$PROG: cannot remove \"$MB\"." >&2
608			exit 1
609		}
610	  fi
611
612	#
613	# do the recomposition, based on options;
614	# if the mbox was a zipped file, RECOMPOSE needs the
615	# non-zipped filename;
616	#
617	echo "" >&2
618	case "$MB" in
619	  *'.Z'|*'.gz')
620		# get rid of the suffix
621		_MB=`$AWK <&- 'BEGIN {
622			F = "'"$MB"'";
623			sub(/((\.Z)|(\.gz))$/,"",F);
624			print F;
625		}'`
626		;;
627	  *)
628		_MB="$MB"
629	  esac
630	cmd="$RECOMPOSE$PASS_MFLAG$PASS_YFLAG$PASS_VFLAG \"$_MB\""
631	eval "$CMD" || {
632		echo "$PROG: problem reassembling \"$_MB\"." >&2
633		exit 1
634	}
635
636	#
637	# if none of the date flags used, only do this part;
638	# the logic here is a little convoluted -- if you can think
639	# of anything that makes more sense, let me know;
640	#
641	if [ "$USE_DATES" = 0 ]; then
642		#
643		# if REMOVE or
644		# if we're working in the directory of the original mbox,
645		# and if the original file was zipped, then re-zip it;
646		#
647		if [ "$REMOVE" = 1 -o "$MB_DIR" = '.' ]; then
648			case "$MB" in
649			  *'.Z')
650				cmd="compress \"$_MB\""
651				eval "$CMD" || {
652					echo "$PROG: cannot compress \"$_MB\"." >&2
653					exit 1
654				}
655				;;
656			  *'.gz')
657				cmd="gzip \"$_MB\""
658				eval "$CMD" || {
659					echo "$PROG: cannot gzip \"$_MB\"." >&2
660					exit 1
661				}
662			  esac
663		  else
664			MB="$_MB"  # don't want the suffix (if there is one)
665		  fi
666		if [ "$REMOVE" = 1 -a "$MB_DIR" != '.' ]; then
667			cmd="mv \"$MB\" \"$MB_DIR\""
668			eval "$CMD" || {
669				echo "$PROG: cannot move \"$MB\" to \"$MB_DIR\"." >&2
670				exit 1
671			}
672		  fi
673
674		continue
675	  fi
676
677	#
678	# from this point on, we're concerned with moving the various
679	# merged mailboxes to where they need to go, ie, any of:
680	#   SRC_DIR/mbox.YYMM
681	#   SRC_DIR/YYMM/mbox
682	#   SRC_DIR/mbox.YYYY
683	#   SRC_DIR/YYYY/mbox
684	#   SRC_DIR/YYYY/mbox.MM
685	#   SRC_DIR/YYYY/MM/mbox
686	#   SRC_DIR/mbox (CURRENT)
687	#
688
689	REDO_LIST=	# mboxes to redo (ie, after appending, sort/merge again)
690	COMPRESS_LIST=	# mboxes to re-compress
691	GZIP_LIST=	# mboxes to re-gzip
692	MB="$_MB"	# don't want any zip suffix any more (if there was one)
693
694	#
695	# only want to do this (move files and recurse) if not HERE
696	#
697	if [ "$SRC_DIR" != '.' ]; then
698#	#
699		#
700		# get list of [path/]files that were generated;
701		# make them into the positional parameters;
702		# unfortunately, we do not get this info from RECOMPOSEMAIL;
703		#
704		DFILES=
705		case "$SMODE" in
706		  $m_SORT|$y_SORT)
707			DFILES=`ls -d "$MB".[0-9][0-9][0-9][0-9]`
708			;;
709		  $M_SORT|$Y_SORT)
710			DFILES=`ls -d [0-9][0-9][0-9][0-9]/"$MB"`
711			;;
712		  $Ym_SORT)
713			DFILES=`ls -d [0-9][0-9][0-9][0-9]/"$MB".[0-1][0-9]`
714			;;
715		  $YM_SORT)
716			DFILES=`ls -d [0-9][0-9][0-9][0-9]/[0-1][0-9]/"$MB"`
717		  esac
718		set -f
719		_IFS="$IFS"
720		IFS='
721'
722		set -- X $DFILES
723		shift
724		IFS="$_IFS"
725		set +f
726
727		for DFILE do
728#	#	#
729			echo "" >&2
730
731			#
732			# decompose the [path/]mbox name, based on sort mode;
733			# this info will be needed for moves and such;
734			#
735
736			DDIR= SUFX=	# dir and/or suffix
737			B_SUFX=		# for backup filenames
738
739			case "$SMODE" in
740			  "$y_SORT") # mbox.yyyy
741				eval `$AWK <&- 'BEGIN {
742					DF = "'"$DFILE"'";
743					N = split(DF,A,"\.");
744					print "SUFX=\"" A[N] "\"";
745					print "B_SUFX=\"" A[N] "\"";
746				}'`
747				;;
748			  "$Y_SORT") # yyyy/mbox
749				eval `$AWK <&- 'BEGIN {
750					DF = "'"$DFILE"'";
751					N = split(DF,A,"/");
752					print "DDIR=\"" A[1] "\"";
753					print "B_SUFX=\"" A[1] "\"";
754				}'`
755				;;
756			  "$m_SORT") # mbox.yymm
757				eval `$AWK <&- 'BEGIN {
758					DF = "'"$DFILE"'";
759					N = split(DF,A,"\.");
760					print "SUFX=\"" A[N] "\"";
761					print "B_SUFX=\"" A[N] "\"";
762				}'`
763				;;
764			  "$M_SORT") # yymm/mbox
765				eval `$AWK <&- 'BEGIN {
766					DF = "'"$DFILE"'";
767					N = split(DF,A,"/");
768					print "DDIR=\"" A[1] "\"";
769					print "B_SUFX=\"" A[1] "\"";
770				}'`
771				;;
772			  "$Ym_SORT") # yyyy/mbox.mm
773				eval `$AWK <&- 'BEGIN {
774					DF = "'"$DFILE"'";
775					N = split(DF,A,"/");
776					N2 = split(A[2],A2,"\.");
777					print "DDIR=\"" A[1] "\"";
778					print "SUFX=\"" A2[N2] "\"";
779					print "B_SUFX=\"" substr(A[1],3) A2[N2] "\"";
780				}'`
781				;;
782			  "$YM_SORT") # yyyy/mm/mbox
783				DDIR="$_MF_Y4/$_MF_M2"
784				eval `$AWK <&- 'BEGIN {
785					DF = "'"$DFILE"'";
786					N = split(DF,A,"/");
787					print "DDIR=\"" A[1] "/" A[2] "\"";
788					print "B_SUFX=\"" substr(A[1],3) A[2] "\"";
789				}'`
790			  esac
791
792			#
793			# will the existing file need to be unzipped?
794			#
795			if [ -f "$SRC_PATH$DFILE" ]; then
796#	#	#	#
797				[ "$RECURSE" = 1 ] &&
798				  REDO_LIST=`append_list "$REDO_LIST" "$DFILE"`
799			  elif [ -f "$SRC_PATH$DFILE.Z" ]; then
800				cmd="uncompress \"$SRC_PATH$DFILE\""
801				if eval "$CMD"
802				  then
803					COMPRESS_LIST=`append_list "$COMPRESS_LIST" "$DFILE"`
804					REDO_LIST=`append_list "$REDO_LIST" "$DFILE"`
805				  else
806					echo "$PROG: cannot uncompress \"$SRC_PATH$DFILE\"." >&2
807					exit 1
808				  fi
809			  elif [ -f "$SRC_PATH$DFILE.gz" ]; then
810				cmd="gunzip \"$SRC_PATH$DFILE\""
811				if eval "$CMD"
812				  then
813					GZIP_LIST=`append_list "$GZIP_LIST" "$DFILE"`
814					REDO_LIST=`append_list "$REDO_LIST" "$DFILE"`
815				  else
816					echo "$PROG: cannot gunzip \"$SRC_PATH$DFILE\"." >&2
817					exit 1
818				  fi
819			  fi
820
821			#
822			# move or append to the source location
823			#
824			if [ -f "$SRC_PATH$DFILE" ]; then
825#	#	#	#
826				# backup any file already there
827				if [ "$BACKUP" = 1 ]; then
828				    # if there's already a copy, move it, don't overwrite
829				    rotate_file "$SRC_PATH$BACKUP_DIR/$MB.$B_SUFX" || {
830					echo "$PROG: cannot rotate file \"$SRC_PATH$BACKUP_DIR/$MB.$B_SUFX\"." >&2
831					exit 1
832				    }
833				    cmd="cp \"$SRC_PATH$DFILE\" \"$SRC_PATH$BACKUP_DIR/$MB.$B_SUFX\""
834				    eval "$CMD" || {
835					echo "$PROG: cannot copy \"$SRC_PATH$DFILE\" to \"$SRC_PATH$BACKUP_DIR/$MB.$B_SUFX\"." >&2
836					exit 1
837				    }
838				  fi &&
839				#
840				# append to the existing file
841				#
842				{
843				  cmd="cat \"$DFILE\" >> \"$SRC_PATH$DFILE\""
844				  eval "$CMD" || {
845					echo "$PROG: cannot append \"$DFILE\" to \"$SRC_PATH$DFILE\"." >&2
846					exit 1
847				  }
848				} &&
849				{
850				  cmd="rm \"$DFILE\""
851				  eval "$CMD" || {
852					echo "$PROG: cannot remove \"$DFILE\"." >&2
853					exit 1
854				  }
855				}
856			#
857			# if no original
858			#
859			  else
860#	#	#	#
861				#
862				# need to create the directory?
863				#
864				if [ "$USE_DIRS" = 1 -a ! -d "$SRC_PATH$DDIR" ]; then
865#	#	#	#	#
866					cmd="mkdir -p \"$SRC_PATH$DDIR\""
867					eval "$CMD" || {
868					  echo "$PROG: cannot mkdir \"$SRC_PATH$DDIR\"." >&2
869					  exit 1
870					}
871				  fi
872#	#	#	#	#
873				#
874				# new file moves to new dir
875				#
876				cmd="mv \"$DFILE\" \"$SRC_PATH$DFILE\""
877				eval "$CMD" || {
878					echo "$PROG: cannot move \"$DFILE\" to \"$SRC_PATH$DFILE\"." >&2
879					exit 1
880				}
881			  fi
882#	#	#	#
883		  done
884#	#	#
885
886		#
887		# a little message from RECURSE...
888		#
889		if [ "$RECURSE" = 1 ]; then
890#	#	#
891			if [ "$REDO_LIST" = '' ]; then
892#	#	#	#
893				echo "
894$PROG: nothing to recurse..." >&2
895			  else
896
897				_STR=`echo $REDO_LIST`
898				echo "
899$PROG: recursing $_STR ..." >&2
900			  fi
901		  fi
902
903		if [ \( "$RECURSE" = 1 -a -n "$REDO_LIST" \) -o -n "$COMPRESS_LIST" -o -n "$GZIP_LIST" ]; then
904#	#	#
905
906			# if RECURSE, redo any mailboxes that have been
907			# appended to; also recompress any that were
908			# decompressed;
909			set -f
910			_IFS="$IFS"
911			IFS='
912'
913			set -- X $REDO_LIST
914			shift
915			IFS="$_IFS"
916			set +f
917
918			for RFILE do
919#	#	#	#
920				if [ "$RECURSE" = 1 ]; then
921#	#	#	#	#
922					echo "" >&2
923					echo "$PROG: recursing \"$RFILE\"..." >&2
924
925					#
926					# REDO_LIST consists of
927					# [path/]mbox[.sufx]
928					# entries;
929					#
930					# decompose the entries,
931					# based on sort mode
932					#
933					RDIR= RSUF=
934
935					case "$SMODE" in
936					  "$y_SORT") # mbox.yyyy
937						eval `$AWK <&- 'BEGIN {
938							DF = "'"$DFILE"'";
939							N = split(DF,A,"\.");
940							print "RSUF=\"" A[N] "\"";
941						}'`
942						;;
943					  "$Y_SORT") # yyyy/mbox
944						eval `$AWK <&- 'BEGIN {
945							DF = "'"$DFILE"'";
946							N = split(DF,A,"/");
947							print "RDIR=\"" A[1] "\"";
948						}'`
949						;;
950					  "$m_SORT") # mbox.yymm
951						eval `$AWK <&- 'BEGIN {
952							DF = "'"$DFILE"'";
953							N = split(DF,A,"\.");
954							print "RSUF=\"" A[N] "\"";
955						}'`
956						;;
957					  "$M_SORT") # yymm/mbox
958						eval `$AWK <&- 'BEGIN {
959							DF = "'"$DFILE"'";
960							N = split(DF,A,"/");
961							print "RDIR=\"" A[1] "\"";
962						}'`
963						;;
964					  "$Ym_SORT") # yyyy/mbox.mm
965						eval `$AWK <&- 'BEGIN {
966							DF = "'"$DFILE"'";
967							N = split(DF,A,"/");
968							N2 = split(A[2],A2,"\.");
969							print "RDIR=\"" A[1] "\"";
970							print "RSUF=\"" A2[N2] "\"";
971						}'`
972						;;
973					  "$YM_SORT") # yyyy/mm/mbox
974						DDIR="$_MF_Y4/$_MF_M2"
975						eval `$AWK <&- 'BEGIN {
976							DF = "'"$DFILE"'";
977							N = split(DF,A,"/");
978							print "RDIR=\"" A[1] "/" A[2] "\"";
979						}'`
980					  esac
981
982					# move the file to recurse here
983					cmd="mv \"$SRC_PATH$RFILE\" \"./$MB\""
984					eval "$CMD" || {
985						echo "$PROG: cannot move \"$SRC_PATH$RFILE\" to \"./$MB\"." >&2
986						exit 1
987					}
988
989					# sort/merge it, no backup;
990					# no additional recursing should be necessary;
991					# should all be for the same month or year;
992
993					# decompose the mbox
994					echo "" >&2
995					cmd="$DECOMPOSE$PASS_VFLAG \"$MB\""
996					eval "$CMD" || {
997						echo "$PROG: problem disassembling \"$MB\"." >&2
998						exit 1
999					}
1000
1001					# remove the mbox
1002					cmd="rm \"$MB\""
1003					eval "$CMD" || {
1004						echo "$PROG: cannot remove \"$MB\"." >&2
1005						exit 1
1006					}
1007
1008					# recompose the mbox;
1009					# probably dont really need the date
1010					# flags...
1011					echo "" >&2
1012					cmd="$RECOMPOSE$PASS_MFLAG$PASS_YFLAG$PASS_VFLAG \"$MB\""
1013					eval "$CMD" || {
1014						echo "$PROG: problem reassembling \"$MB\"." >&2
1015						exit 1
1016					}
1017
1018					# move the sorted mbox to its final location
1019					echo "" >&2
1020					cmd="mv \"$RFILE\" \"$SRC_DIR/$RFILE\""
1021					eval "$CMD" || {
1022						echo "$PROG: cannot move \"$RFILE\" to \"$SRC_DIR/$RFILE\"." >&2
1023						exit 1
1024					}
1025				  fi
1026#	#	#	#	#
1027
1028				#
1029				# if the orig file
1030				# was compressed or gzipped, then
1031				# restore it thusly
1032				#
1033				case "
1034$COMPRESS_LIST
1035" in
1036#	#	#	#	#
1037				  *"
1038$RFILE
1039"*)
1040					cmd="compress \"$SRC_DIR/$RFILE\""
1041					eval "$CMD" || {
1042						echo "$PROG: cannot compress \"$SRC_DIR/$RFILE\"." >&2
1043						exit 1
1044					}
1045					;;
1046				  *)
1047					case "
1048$GZIP_LIST
1049" in
1050					  *"
1051$RFILE
1052"*)
1053						cmd="gzip \"$SRC_DIR/$RFILE\""
1054						eval "$CMD" || {
1055							echo "$PROG: cannot gzip \"$SRC_DIR/$RFILE\"." >&2
1056							exit 1
1057						}
1058						;;
1059					  *)
1060					  esac
1061				  esac
1062#	#	#	#	#
1063			  done
1064#	#	#	#
1065		  fi
1066#	#	#
1067	  fi
1068#	#
1069
1070	#
1071	# if CURRENT, move current month mbox back to SRC_DIR
1072	#
1073	if [ "$CURRENT" = 1 ]; then
1074#	#
1075 		DDIR= DDIR_=
1076 		SUFX= _SUFX=
1077
1078 		case "$SMODE" in
1079 		  "$y_SORT")
1080 			SUFX="$C_Y4"
1081 			;;
1082 		  "$Y_SORT")
1083 			DDIR="$C_Y4"
1084 			;;
1085 		  "$m_SORT")
1086 			SUFX="$C_Y2$C_M2"
1087 			;;
1088 		  "$M_SORT")
1089 			DDIR="$C_Y2$C_M2"
1090 			;;
1091 		  "$Ym_SORT")
1092 			DDIR="$C_Y4"
1093 			SUFX="$C_M2"
1094 			;;
1095 		  "$YM_SORT")
1096 			DDIR="$C_Y4/$C_M2"
1097 		  esac
1098
1099		DDIR_="${DDIR:+$DDIR/}"
1100		_SUFX="${SUFX:+.$SUFX}"
1101
1102		CFILE="$DDIR_$MB$_SUFX"
1103
1104		if [ -f "$SRC_PATH$CFILE" ]; then
1105#	#	#
1106			cmd="mv \"$SRC_PATH$CFILE\" \"$MB_PATH$MB\""
1107			eval "$CMD" || {
1108				echo "$PROG: cannot move \"$SRC_PATH$CFILE\" to \"$MB_PATH$MB\"." >&2
1109				exit 1
1110			}
1111
1112		#
1113		# if CURRENT and orig mbox is now non-existent,
1114		# make an empty one
1115		#
1116		  elif [ ! -f "$MB_PATH$MB" ]; then
1117			echo "" >&2
1118			cmd="> \"$MB_PATH$MB\""
1119			eval "$CMD" || {
1120				echo "$PROG: cannot create file \"$MB_PATH$MB\"." >&2
1121				exit 1
1122			}
1123		  fi
1124#	#	#
1125	  fi
1126#	#
1127  done
1128#
1129
1130echo "
1131$PROG: done.
1132" >&2
1133
1134exit
1135