#! /bin/sh # $Header: /home/jpeek/.bin/RCS/mail.sort,v 3.7 1997/09/13 22:16:43 jpeek Exp $ ### 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.7 $ \$Date: 1997/09/13 22:16:43 $" 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; rm -f $temp; exit $stat' 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\# +1f +0,1n | # SORT BY TEXT FIELD, FOLLOWED BY MESSAGE NUMBER 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: # 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