#! /bin/sh
# $Header: /home/jerry/.bin/RCS/mail.sort,v 3.6 92/08/09 23:26:31 jerry mh_contrib $
###	mail.sort - sort mail messages in place, or link to temporary folder
###	Usage: mail.sort [folder] [-verbose] [-help] [-link [msgs]] [-c|f|o|s|t|x]"
##
##	THE sortm(1) PROGRAM FROM MH 6.6 CAN SORT MAIL MESSAGES BY
##	DATE.  BUT IF YOU WANT TO GROUP ORIGINAL MESSAGES WITH THEIR
##	REPLIES, OR SORT BY THE PERSON WHO SENT THEM, YOU CAN USE THIS
##	SCRIPT.  (THE MH 6.7 sortm IS MORE POWERFUL--AND IT DOES A LOT,
##	BUT NOT ALL, OF WHAT mail.sort DOES.)
##
##	mail.sort CAN SORT BY SUBJECT, IGNORING THE Re: SO THAT REPLIES
##	ARE GROUPED WITH THE ORIGINAL MESSAGE.  IT CAN SORT BY THE
##	Sender:, IF THERE IS ONE-- OTHERWISE, BY THE From:.  THERE ARE 6
##	OTHER WAYS TO SORT, AS WELL.
##
##	mail.sort USES scan FORMAT STRINGS TO PULL HEADER INFORMATION
##	OUT OF EACH MESSAGE.  SO, IF YOU CAN WRITE A FORMAT STRING, YOU
##	CAN SORT BY IT.  IF THERE'S A FORMAT STRING THAT YOU USE A LOT,
##	YOU CAN ADD A NEW OPTION TO mail.sort (BY ADDING A SINGLE LINE
##	OF CODE) THAT LETS YOU USE THAT FORMAT STRING ANY TIME, JUST BY
##	TYPING YOUR NEW OPTION ON THE COMMAND LINE.
##
##	BY DEFAULT, mail.sort SORTS MESSAGES AND PUTS THEM BACK IN THE
##	SAME FOLDER.  IT CAN ALSO LINK ALL THE MESSAGES INTO A TEMPORARY
##	SUB-FOLDER WITHOUT CHANGING THE SOURCE FOLDER ORDER.  WHEN
##	YOU'RE DONE WITH THE SUB-FOLDER, YOU CAN REMOVE IT.
##
##	THE -v OPTION WRITES VERBOSE INFO ABOUT WHAT'S HAPPENING TO stdout.
#
#	NOTE TO HACKERS: TABSTOPS SET AT 4 IN THIS CODE
#
#	USE AT YOUR OWN RISK.  SEEMS TO WORK, BUT IT'S YOUR RESPONSIBILITY!
#	PLEASE TELL ME ABOUT BUGS AND FIXES: Jerry Peek, jerry@ora.com

umask 77											# PROTECT TEMPORARY FILE
folopts="-nolist -nototal"							# OVERRIDE MH PROFILE
mh=/usr/local/mh									# WHERE MH COMMANDS LIVE
myname="`basename $0`"								# THIS PROGRAM'S NAME
scanopts="-width 200 -noclear -noheader -noreverse"	# OVERRIDE MH PROFILE
stat=1	# DEFAULT EXIT STATUS; RESET TO 0 BEFORE NORMAL exit
subfol=MAILSORT$$									# TEMPORARY SUB-FOLDER
temp=/tmp/MSORT$$
usage="Usage: $myname [folder] [-verbose] [-help] [-link [msgs]] [-c|f|o|s|t|x]"

# trapS COME LATER... SEE BELOW.

what=/bin/mv	# DEFAULT IF NO -link
for arg
do
	case "$arg" in
	[+@]*) folder="$arg" ;;
	-h*) echo "$usage

	Replaces messages in same folder unless you use -link,
	when messages are linked into a sorted sub-folder.

	Sorts by Subject with Re:'s stripped,
	unless you use one of the following:
	   -f[rom]
	   -s[ender]
	   -o[rigin]   (Sender, otherwise From)
	   -t[o]
	   -c[c]
	   -r[eply-to]
	   -x          (exact Subject, including Re:'s)

	$myname, \$Revision: 3.6 $ \$Date: 92/08/09 23:26:31 $"
		stat=0
		exit
		;;
	-l*) what=/bin/ln ;;
	-v*) vflag=y ;;
	-*)	# SET COMPONENT TO SORT ON:
		case "$how" in
		?*)	echo "$myname: '$arg'?  Only one of -c, -f, -o, -s, -t, -x." 1>&2
			exit
			;;
		esac
		# NO DATE SORT HERE BECAUSE sortm DOES THAT, AND FASTER...
		case "$arg" in
		-f*) how='%(mbox{from})' ;; # FROM (mbox)
		-s*) how='%(mbox{sender})' ;; # SENDER (mbox)
		-t*) how='%(mbox{to})' ;; # TO (IGNORE MUTIPLE ADDRESSES)
		-c*) how='%(mbox{cc})' ;; # CC (IGNORE MUTIPLE ADDRESSES)
		-r*) how='%(mbox{reply-to})' ;; # REPLY-TO (mbox)
		-x*) how='%{subject})' ;; # EXACT SUBJECT (INCLUDE Re:)
		-o*) # SORT BY Sender, IF THERE IS ONE, OTHERWISE BY From:
			 how='%<{sender}%(mbox{sender})%|%(mbox{from})%>'
			 ;;
		*)	echo "$usage
			(invalid switch '$arg')" 1>&2
			exit
			;;
		esac
		;;
	*)	# ONLY ALLOW MESSAGE ARGUMENTS IF LINKING; CAN RUIN FOLDER OTHERWISE:
		case "$what" in
		*ln) msgargs="$msgargs $arg" ;;
		*)	echo "$usage
			('$arg'?  No message numbers unless using -link.)" 1>&2
			exit 1
			;;
		esac
		;;
	esac
done

origfol="`$mh/folder $folopts $folder -fast`"
cd `$mh/mhpath +$origfol` || exit

# SET trapS THAT TELL USER HOW TO RECOVER WHEN stat != 1:
trap 'echo "$myname: Interrupted." 1>&2' 1 2 15
case "$what" in
*ln) # SPECIAL MESSAGE FOR LINKING:
   trap 'case "$stat" in 1) echo "$myname: You should run:
   rmf +$origfol/$subfol" 1>&2;; esac;
   rm -f $temp; exit $stat' 0
   ;;
*) trap 'case "$stat" in 1) echo "$myname:  Recover with:
   folder +$origfol/$subfol
   refile all @..
   folder        (be sure +$origfol/$subfol is empty)
   rmf           (remove +$origfol/$subfol)" 1>&2;; esac' 0
   ;;
esac

mkdir $subfol || exit

exec 3>&2		# SAVE ORIGINAL stderr; WE RESTORE IT LATER
exec 2>$temp	# THROW stderr MESSAGES INTO $temp; TEST AT END OF THIS MESS

case "$vflag" in
y) echo "$myname: sorting messages to temporary folder..." ;;
esac
# START LONG PIPELINE TO GET LIST OF MESSAGES, WITH OLD AND NEW NUMBERS.
# SPIT MESSAGE NUMBERS AND TEXT FIELD TO STANDARD OUTPUT OF case.
case "$how" in
"") # SORT BY SUBJECT (DEFAULT); STRIP OFF "Re:", "RE:", "Re: Re:", ETC:
	$mh/scan $scanopts -format '%(msg)#%{subject}' $msgargs |
	sed -n '
	/^[1-9][0-9]*#[Rr][Ee]:/ {
	:rezap
		s/^\([1-9][0-9]*#\)[Rr][Ee]: */\1/
		/^[1-9][0-9]*#[Rr][Ee]:/b rezap
	}
	p'
	;;
*)	# SORT BY WHATEVER ELSE (FORMAT STRING IS IN $how):
	$mh/scan $scanopts -format "%(msg)#$how" $msgargs
	;;
esac |
sort -t\# +1 |	# SORT BY TEXT FIELD
awk '{ kut = index($0, "#")	# ADD NEW MESSAGE NUMBERS, REMOVE "#"
	print NR, substr($0, 1, kut-1), substr($0, kut+1) }' |
while read new old text
do
	# MOVE OR LINK MESSAGES INTO SUB-FOLDER, ONE BY ONE.
	#
	# IF MESSAGE WAS UNREADABLE, scan PRINTED A LINE (TO STANDARD
	# OUTPUT!) LIKE THIS, WITH LEADING BLANKS UNLESS msgnum > 999:
	#   <msgnum>  unreadable
	# WE GET THAT WITH A LINE NUMBER IN FRONT FROM awk...
	# IF THERE ARE LEADING BLANKS, SOME BOURNE SHELLS WILL COPY ALL
	# THIS STUFF INTO $text, AND LEAVE BOTH $new AND $old
	# EMPTY.  TRY TO CATCH BOTH CASES:
	case "$new" in
	"")	echo "$myname: message $new $old $text" 1>&2; break ;;
	esac
	case "$text" in
	unreadable)	echo "$myname: can't read msg '$old'???" 1>&2; break ;;
	esac
	# USE UNIX COMMANDS; AVOID ALL THE OVERHEAD THAT refile WOULD ADD:
	if $what $old $subfol/$new
	then
		case "$vflag" in
		y) echo "$myname: old #$old --> new #$new ($text)" ;;
		esac
	else
		echo "$myname: '$what $old $subfol/$new' failed." 1>&2
		break
	fi
done
exec 2>&-	# CLOSE TEMPORARY stderr
exec 2>&3	# RESTORE ORIGINAL stderr

# IF THERE WERE ANY ERRORS IN THE MESS ABOVE, SHOW THEM AND EXIT:
if test -s $temp
then
	echo "$myname: quitting:" 1>&2
	cat $temp 1>&2
	exit
fi

set -e	# exit IF ANY ERROR FROM NOW ON

case "$what" in
*ln)
	case "$vflag" in
	y)	$mh/folder @$subfol
		echo "$myname: done."
		echo "When you're done with this sub-folder, type 'rmf' to remove it."
		;;
	*)	$mh/folder -fast @$subfol >/dev/null ;;
	esac
	;;
*)
	# cd TO SUB-FOLDER AVOIDS LONG PATHNAMES (& COMMAND LINE OVERFLOW):
	cd $subfol
	case "$vflag" in
	y) echo "$myname: moving messages back to original folder..." ;;
	esac
	/bin/mv * ..
	cd ..
	/bin/rmdir $subfol
	;;
esac
stat=0
exit
