From: wohler@sap-ag.de (Bill Wohler)
Subject: mailarch-1.4: archive MH mail
Newsgroups: comp.mail.mh
Organization: SAP AG  Walldorf, Germany
Date: 23 Jan 93 19:03:08 GMT
Phone: +49 6227-341658  Home: +49 6221-163255

  this is mailarch 1.4, a program to archive MH mail.

  it tars and compresses mh directories for substantial disk savings
  (inodes too).  for example:

	[wohler@is0001:510]% du -s 1992/mar 1992/mar.tar.Z
	6528    1992/mar
	1360    1992/mar.tar.Z

  the idea of mailarch is to move certain folders into an archive area
  monthly.  older archives are tarred and compressed.

  the programs seek and extract (enclosed) are used to extract
  messages from the archive.

  please read the headers of the scripts for more information.  if you
  use these, let me know and i'll place you on my mailing list.  if
  you find the documentation in the headers non-illuminating, i want
  to know about it.

  note: mailarch is a csh script and seek and extract are ksh scripts.
  the PATH in these scripts may have to be updated for your environment.
  known to work on aix and hpux.

  changes in mailarch since 1.3:
  * Updated documentation for MH 6.8.
  * Works on hpux.
  * Extract's default output folder now +hold (instead on +hold$$).
  * Bug fixes.

  changes in mailarch since 1.2:
  * Create replacement folders with desired permissions.  (Major new
    feature in the user interface.)
  * Use mhparam to get .mh_profile components.
  * Updated documentation.
  * Check to ensure that a folder exists before processing.  On some errors,
    either mailarch would hang, or bogus folders would get created.

						--bw

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  extract mailarch seek
# Wrapped by wohler@is0001 on Sat Jan 23 19:45:29 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'extract' -a "${1}" != "-c" ; then
  echo shar: Will not clobber existing file \"'extract'\"
else
echo shar: Extracting \"'extract'\" \(3687 characters\)
sed "s/^X//" >'extract' <<'END_OF_FILE'
X#! /bin/ksh
X#
X# $Id: extract,v 1.6 1993/01/23 18:22:53 wohler Exp $
X#
X# NAME
X#   extract - extract mail messages from archives
X#
X# SYNOPSIS
X#   extract [-c new-folder] year folder [msg ...]
X#
X# DESCRIPTION
X#   In the case that no specific messages are designated, extract will extract
X#   all messages in the year in the specified folder.  The folder in this case
X#   is relative to the mail directory (ie +a/others).
X#
X#   If specific messages are specified, then only those messages are
X#   extracted.	In this case, the folder specified must also include the year
X#   and month (ie. +1991/jan/a/others).	 The message list "all" is also
X#   supported and extracts all messages from the folder.
X#
X#   The year argument is essentially an archive directory in the Mail
X#   directory.  This program assumes that this archive contains the
X#   subdirectories "jan," "feb," etc. as created by the mailarch program.
X#
X# OPTIONS
X#   -c new-folder  specify the folder to hold the extracted messages
X#		   (default: +hold).
X#
X# RETURNS
X#   0 normally; 1 upon error.
X#
X# BUGS
X#   In pre-MH-6.8 versions that lack the mhparam command, use the
X#   commented out setting of the "mail" variable below.
X#
X# AUTHOR
X#   Bill Wohler <wohler@sap-ag.de>	SAP AG		22 July 1992
X
X# Constants (variables that do not change during runtime).
X
X# Defaults (variables that may be affected by arguments).
Xnewfolder=hold
X
X# Initializations (internal variables that need to be set to something).
XPATH=/usr/local/bin/mh:/bin:/usr/bin	# set minimum search path
Xcmd=${0##*/}				# name by which command called
Xexitstatus=0				# upon error, set to non-zero
Xinterrupt=0				# upon interrupt, set to 1
X#mail=$HOME/$(awk '/^Path/{print $2}' $HOME/.mh_profile)
Xmail=$HOME/$(mhparam Path)
Xmonths="jan feb mar apr may jun jul aug sep oct nov dec"
X
X# Functions
X
Xusage ()
X{
X	echo "Usage: $cmd [-c new-folder] year folder [msg ...]"
X	bye 1
X}
X
Xintr ()
X{
X	echo ""
X	interrupt=1
X	bye 1
X}
X
X# Usage: bye [exit status] [exit message]
Xbye ()
X{
X	if [ $# -gt 0 ]; then
X		exitstatus=$1
X		shift
X	fi
X	if [ $# -gt 0 ]; then
X		echo "$*"
X	elif [ $interrupt -eq 1 ]; then
X		echo ""
X	elif [ $exitstatus -eq 0 ]; then
X		echo "Done."
X	fi
X	exit $exitstatus
X}
X
X# Parse arguments
Xwhile [ $# != 0 ]; do
X	case "$1" in
X	-c)	shift; newfolder=$1;;
X	-v)	print=1;;
X	-*)	usage;;
X	*)	break;;
X	esac
X	shift
Xdone
X
Xif [ $# -lt 2 ]; then
X	usage
Xfi
X
Xtrap intr 2
X
Xyear=$1
Xfolder=${2#+}
Xshift; shift
Xmsgs=$*
X
X[ ! -d $mail/$year ] && bye 1 "$mail/$year does not exist."
X[ -z "$newfolder" ]  && usage
X
Xfolder +$mail/$newfolder </dev/null > /dev/null  || bye 1
Xcd $mail/$year || bye 1
X
Xecho "Extracting mail from archives."
Xif [ -z "$msgs" ]; then
X	# No messages given; extract all messages in folder for all months.
X	for mon in $months; do
X		if [ -f $mon.tar.Z ]; then
X			zcat $mon.tar.Z | tar xvf - $year/$mon/$folder
X			if [ -d $(mhpath +./$year/$mon/$folder) ]; then
X				folder +./$year/$mon/$folder > /dev/null
X				refile all +$newfolder
X			fi
X		fi
X	done
Xelse
X	# Extract the named messages.
X	if [ "$msgs" = all ]; then
X		msglist=$folder
X	else
X		for i in $msgs; do
X			msglist="$msglist $folder/$i"
X		done
X	fi
X	mon=${folder#*/}			# strip junk to left of month
X	mon=${mon%%/*}				# strip junk to right of month
X	if [ -f $mon.tar.Z ]; then
X		zcat $mon.tar.Z | tar xvf - $msglist
X		if [ -d $(mhpath +./$folder) ]; then
X			folder +./$folder > /dev/null
X			refile all +$newfolder
X		fi
X	else
X		bye 1 "$mon.tar.Z does not exist."
X	fi
Xfi
X
Xif [ ! -d $year ]; then
X	bye 0 "No files extracted."
Xelse
X	# We can remove the now empty folders.
X	rm -rf $mail/$year/$year
Xfi
X
Xecho "Sorting mail."
Xsortm +$newfolder
X
Xecho "Messages in +$newfolder."
X
Xbye
X
X# Local Variables:
X# mode: sh
X# End:
END_OF_FILE
if test 3687 -ne `wc -c <'extract'`; then
    echo shar: \"'extract'\" unpacked with wrong size!
fi
chmod +x 'extract'
# end of 'extract'
fi
if test -f 'mailarch' -a "${1}" != "-c" ; then
  echo shar: Will not clobber existing file \"'mailarch'\"
else
echo shar: Extracting \"'mailarch'\" \(9675 characters\)
sed "s/^X//" >'mailarch' <<'END_OF_FILE'
X#! /bin/csh -f
X#
X# $Id: mailarch,v 1.6 1993/01/23 18:26:04 wohler Exp $
X#
X# NAME
X#   mailarch - archive MH mail folders
X#
X# SYNOPSIS
X#   mailarch [-a folders] [-f folders] [-m mail] [options] [-s] [-v]
X#	     thismonth [lastmonth]
X#
X# DESCRIPTION
X#   After a period of time one's mail folders get quite full with
X#   material that is rarely looked at.  This program is an attempt to
X#   organize old mail.  The idea is that selected folders are moved
X#   into a different place, usually at monthly intervals.  The first
X#   time, the folder hierarchy is preserved.  The second time this
X#   program is called, a month later, the old hierarchy is packed
X#   (currently with tar) and compressed.  The mail itself can then be
X#   easily stored on tape and the index saved on disk for searching
X#   for old mail.
X#
X#   Usage is straightforward.  First create the MH profile components
X#   "Archive" and "Parent-Folders" described below.  If one is
X#   archiving mail from March, 1991, then the usage would be:
X#
X#	mailarch 1991/mar 1991/feb
X#
X#   This will move selected folders in your mail directory to the
X#   folder 1991/mar.  This name is arbitrary and any intermediary
X#   directories will be automatically created.  But, since it is a
X#   folder, it will be created relative to your mail directory.
X#
X#   This archived folder is then rid of .mh_sequences files and
X#   folders are sorted.  An index of all the messages is also created.
X#   An opportunity to edit or remove large, unwanted files is also
X#   given. The older folder is packed (currently with tar) into a single
X#   file and removed.  The packed folder and its index are then
X#   compressed.
X#
X#   Only parts of this process can be run by using the -o flags.
X#
X#   The names of the folders to be archived are found in the MH profile
X#   "Archive"; names are separated by whitespace.
X#
X#   Pre-MH 6.7.1 versions could not create arbitrarily nested folders, so if
X#   folders that contain subfolders are archived, then it is necessary to
X#   recreate folder trees for them.  This MH profile is called
X#   "Parent-Folders".  Folders listed may be suffixed by ":mode" in order to
X#   override the default folder creation mode.  This "mode" is as in the
X#   chmod(1) command (ie. can be either absolute or symbolic).  For example:
X#
X#	Archive: maillists friends out
X#	Parent-Folders: maillists friends:700 out:700
X#
X#   This archives and recreates the "maillists", "friends", and "out" folders.
X#   The friends and out folders are not accessible by members of the group or
X#   others since they may contain sensitive mails.
X#
X# OPTIONS
X#   -a folders
X#	Override the MH profile value of "Archive" with "folders."
X#	Surround multiple folders with double quotes.
X#
X#   -f folders
X#	Override the MH profile value of "Parent-Folders" with "folders."
X#	Surround multiple folders with double quotes.
X#
X#   -m mail
X#	Set the name of the mail directory.  The default is the value
X#	of the MH profile entry "Path."
X#
X#   -s size
X#	Specify the size of file (in K) that should be edited or
X#	removed (default is 25K).
X#
X#   -v
X#	Display each of the steps.
X#
X#   By default, all of the following actions are performed in the
X#   order listed.  If any of these options are specified, then no
X#   other actions will be performed that are not also listed.
X#
X#   -om
X#	Move the current folders into the new archive.
X#   -os
X#	Sort messages of the new archive.
X#   -oi
X#	Make an index of the new archive.
X#   -op
X#	Pack and compress the old archive.
X#
X# ENVIRONMENT
X#   MH			If set, used instead of ~/.mh_profile.
X#
X# PROFILE COMPONENTS
X#   Path		mail directory (must be relative to home directory).
X#   Archive		folders to archive
X#   Parent-Folders	folders to recreate
X#
X# BUGS
X#   If your MH is pre-MH-6.8, uncomment the non-"mhparam" versions of setting
X#   variables below.
X#
X#   I have to investigate whether or not files might be accidently
X#   removed if you run out of disk space while packing files.
X#
X#   Various scan and sortm messages are displayed (ie. "no messages in folder")
X#   These should be suppressed.
X#
X#   The archive folder name should be able to created automatically so that
X#   this script can be cronned!  An idea would be to say that if it is after
X#   the 15th of month B and before the 15th of month C, then the current month
X#   is month B and last month is month A.
X#
X# AUTHOR
X#   Bill Wohler <wohler@sap-ag.de>	SAP AG		1 March 1988
X#
X
X# Defaults
Xset all		= 1			# perform all operations
Xset movefolders = 0			# move folders into old directory
Xset sort	= 0			# sort messages
Xset mkindex	= 0			# make an index
Xset pack	= 0			# pack and compress folder
Xset mail	= ~/`mhparam Path`	# mail directory
Xset folders	= `mhparam Archive`	# folders to archive
Xset mkfolders	= `mhparam Parent-Folders` # folders to recreate
Xset size	= 25			# file size (kbytes) to edit or remove
X
X# In pre-MH.6.8 installations, uncomment these, and comment out like
X# variables above.  mhprofile not needed in MH.6.8 or later.
X#if ($?MH) then				# file containing archive config
X#	set mhprofile = $MH
X#else
X#	set mhprofile = ~/.mh_profile
X#endif
X#set mail	= ~/`awk '/^Path/{print $2}' $mhprofile`
X#set folders	= `awk '/^Archive/{for(i=2;i<=NF;i++)print $i}' $mhprofile`
X#set mkfolders	= `awk '/^Parent-Folders/{for(i=2;i<=NF;i++)print $i}' $mhprofile`
X
X# Initializations
Xset cmd		= $0			# name by which command called
Xset exitstatus	= 0			# upon error, set to non-zero and exit
Xset lastmonth oldarchive
X
X# If either no args, or just the directory, parsing args will get
X# "Subscript out of range."
Xif ($#argv == 0) \
X	goto usage
X
X# Parse arguments
Xwhile ("$argv[1]" =~ -*)
X	switch ("$argv[1]")
X	case "-a":
X		shift
X		set folders = ($argv[1])
X		breaksw
X
X	case "-f":
X		shift
X		set mkfolders = ($argv[1])
X		breaksw
X
X	case "-m":
X		shift
X		set mail = $argv[1]
X		breaksw
X
X	case "-oi":
X		set mkindex = 1
X		set all = 0
X		breaksw
X
X	case "-op":
X		set pack = 1
X		set all = 0
X		breaksw
X
X	case "-om":
X		set movefolders = 1
X		set all = 0
X		breaksw
X
X	case "-os":
X		set sort = 1
X		set all = 0
X		breaksw;
X
X	case "-s":
X		shift
X		set size = $argv[1]
X		breaksw
X
X	case "-v":
X		set print = 1
X		breaksw
X
X	default:
X		goto usage
X	endsw
X	shift
X	if ($#argv == 0) \
X		break
Xend
X
Xif ($#argv < 1) \
X	goto usage
X
Xset archive = $argv[1]
X
Xif ($#argv > 1) then
X	set lastmonth = $argv[2]
Xendif
X
X# Now check that each needed variable is non-nil.
X
Xif (! -e $mail) then
X	echo "${mail}: No such directory."
X	set exitstatus = 1
X	goto bye
Xendif
Xif ($lastmonth != "" && ! -e $mail/$lastmonth) then
X	echo "${lastmonth}: No such directory."
X	set exitstatus = 1
X	goto bye
Xendif
Xif ("$folders" == "") then
X	echo "No folders to archive."
X	set exitstatus = 1
X	goto bye
Xendif
X
Xskipargs:
Xonintr intr
X
X
X# Move folders to archive and then create folders that must always exist.
Xif ($movefolders || $all) then
X	if ($?print) \
X		echo "Moving ($folders) to $archive"
X	cd $mail || exit 1
X	mkdir `echo $mail/$archive|awk -F/ '{for(i=2;i<=NF;i++){for(j=2;j<=i;j++)printf"/%s",$j;printf"\n"}}'` >& /dev/null
X	mv $folders $archive
X
X	# Recreate folders with non-default permissions if desired.
X	if ("$mkfolders" != "") then
X		if ($?print) \
X			echo "Recreating $mkfolders"
X		foreach i ($mkfolders)
X			set folder = `echo $i | sed 's/:.*$//'`
X			set mode = `echo $i | sed 's/^.*://'`
X			# The redirection here is to keep the folder command
X			# from being interactive.
X			folder +$folder			</dev/null>/dev/null
X			if ($folder != $mode) then
X				if ($?print) \
X					echo chmod $mode `mhpath +$folder`
X				chmod $mode `mhpath +$folder`
X			endif
X		end
X	endif
Xendif
X
X# Sort messages in archive.
Xif ($sort || $all) then
X	# Make sure we don't archive postings of sources...
X	cd $mail/$archive || exit 1
X	set large = `find . -size +$size -print`
X	if ("$large" != "") then
X		echo "Edit large files, or remove later."
X		sleep 2
X		vi $large
X		echo "Interactively remove large files."
X		foreach i ($large)
X			grep ^Subject $i
X			rm -i $i
X		end
X	endif
X
X	foreach i (`folders -recurse -fast +$archive`)
X		if (! -d $mail/$i) \
X			continue
X		if ($?print) \
X			echo "Sorting $i..."
X		sortm +$i
X		folder -pack +$i			>/dev/null</dev/null
X	end
Xendif
X
X# Make index of archive.
Xif ($mkindex || $all) then
X	set index = $mail/$archive.idx
X	rm -f $index
X	# try to rewrite to use +$archive rather than +. to reduce characters.
X	foreach i (`folders -recurse -fast +$archive`)
X		if (! -d $mail/$i) \
X			continue
X		if ($?print) \
X			echo "Scanning $i..."
X		echo "" >>! $index
X		scan -header +$i >>! $index
X		# if no messages, should just have a small mesg
X		# on same line as the echo $i.
X	end
Xendif
X
X# Now, tar and compress last month's archive if given.
Xif (($pack || $all) && "$lastmonth" != "") then
X	if ("$oldarchive" == "") \
X		set oldarchive = $lastmonth.tar
X	set oldindex = $lastmonth.idx
X	cd $mail/$lastmonth || exit 1
X	if ($?print) \
X		echo "Cleaning $lastmonth..."
X	find . -name .mh_sequences -exec rm {} \;
X	if ($?print) \
X		echo "Creating $oldarchive..."
X	cd $mail
X	rm -f $oldarchive
X	tar -cf $oldarchive $lastmonth
X	if ($status == 0) \
X		rm -rf $lastmonth
X	if ($?print) \
X		echo "Compressing $oldarchive and $oldindex..."
X	chmod 444 $oldarchive $oldindex
X	compress $oldarchive $oldindex
Xendif
X
Xgoto bye
X
Xusage:
X	echo "Usage: $cmd:t [-a folders ] [-f folders] [-m mail] [options] [-s size] [-v] thismonth [lastmonth]"
X	echo "Options:"
X	echo "	-om  move the current folders into the current month"
X	echo "	-os  sort messages of the current month"
X	echo "	-oi  make an index of the current month"
X	echo "	-op  pack and compress the last month"
X	exit(1)
X
Xintr:
X	echo ""
X	set interrupt exitstatus = 1
X	# Fall through!
X
Xbye:
X	if ($?print) \
X		echo "Done."
X	exit($exitstatus)
END_OF_FILE
if test 9675 -ne `wc -c <'mailarch'`; then
    echo shar: \"'mailarch'\" unpacked with wrong size!
fi
chmod +x 'mailarch'
# end of 'mailarch'
fi
if test -f 'seek' -a "${1}" != "-c" ; then
  echo shar: Will not clobber existing file \"'seek'\"
else
echo shar: Extracting \"'seek'\" \(2796 characters\)
sed "s/^X//" >'seek' <<'END_OF_FILE'
X#! /bin/ksh
X#
X# $Id: seek,v 1.6 1993/01/23 18:25:18 wohler Exp $
X#
X# NAME
X#   seek -- find names or subjects from archives
X#
X# SYNOPSIS
X#   seek search-string [year ...]
X#
X# DESCRIPTION
X#   Seek searches the indexes for the desired string.  If there is white space
X#   within the string, enclose the string in quotes.
X#
X#   Multiple years can be specified; if the year is omitted, the current year
X#   is used.
X#
X#   The year argument is essentially an archive directory in the Mail
X#   directory.  This program assumes that this archive contains the
X#   indices "jan.idx.Z," "feb.idx.Z," etc. as created by the mailarch
X#   program.
X#
X# OPTIONS
X#
X# RETURNS
X#   0 normally; 1 upon error.
X#
X# BUGS
X#   In pre-MH-6.8 versions that lack the mhparam command, use the
X#   commented out setting of the "mail" variable below.
X#
X# AUTHOR
X#   Bill Wohler <wohler@sap-ag.de>	SAP AG		18 May 92
X
X# Constants (variables that do not change during runtime).
X
X# Defaults (variables that may be affected by arguments).
X
X# Initializations (internal variables that need to be set to something).
XPATH=/usr/local/bin/mh:/bin:/usr/bin:/usr/ucb	# set minimum search path
Xcmd=${0##*/}				# name by which command called
Xmail=$HOME/$(mhparam Path)		# mail folder
X#mail=$HOME/$(awk '/^Path/{print $2}' $HOME/.mh_profile)
Xmonths="jan feb mar apr may jun jul aug sep oct nov dec"
Xexitstatus=0				# upon error, set to non-zero and exit
Xinterrupt=0				# upon interrupt, set to 1
X
X# Functions
X
Xusage () {
X	echo "Usage: $cmd search-string [year ...]"
X	bye 1
X}
X
Xintr ()
X{
X	echo ""
X	interrupt=1
X	bye 1
X}
X
Xbye ()
X{
X	if [ $# -gt 0 ]; then
X		exitstatus=$1
X		shift
X	fi
X	if [ $# -gt 0 ]; then
X		echo "$*"
X	elif [ $interrupt -eq 1 ]; then
X		echo ""
X	elif [ $exitstatus -eq 0 ]; then
X		echo "Done."
X	fi
X	exit $exitstatus
X}
X
X# Usage: find pattern
Xsearch ()
X{
X	if [ $# -ne 1 ]; then
X		echo "Internal error: search() usage incorrect."
X		return;
X	fi
X
X	pattern=$1
X
X	awk '
X		/^Folder/ {
X			header = $0
X			header_printed = 0
X			next
X		}
X
X		/'$pattern'/ {
X			if (! header_printed) {
X				print header
X				header_printed = 1
X			}
X			print $0
X		}
X
X		{
X			next
X		}
X	'
X}
X
X# Parse arguments
Xwhile [ $# != 0 ]; do
X	case "$1" in
X	-v)	print=1;;
X	-*)	usage;;
X	*)	break;;
X	esac
X	shift
Xdone
Xif [ $# -lt 1 ]; then
X	usage
Xfi
Xsearch=$1
Xshift
Xyear=$*
X
Xif [ -z "$year" ]; then
X	if whence uname > /dev/null; then
X		[ "$(uname -s)" = HP-UX ] && machine=hp
X	fi
X	case "$machine" in
X	hp)	year=$(date | awk '{print $6}');;
X	*)	year=$(date | awk '{print $5}');;
X	esac
Xfi
X
Xtrap intr 2
X
Xfor i in $year; do
X	cd $mail/$i || continue
X	for j in $months; do
X		if [ -f $j.idx.Z ]; then
X			zcat $j.idx.Z | search "$search"
X		elif [ -f $j.idx ]; then
X			cat $j.idx | search "$search"
X		else
X			echo "No index for $j."
X		fi
X	done
Xdone
X
Xbye
X
X# Local Variables:
X# mode: sh
X# End:
END_OF_FILE
if test 2796 -ne `wc -c <'seek'`; then
    echo shar: \"'seek'\" unpacked with wrong size!
fi
chmod +x 'seek'
# end of 'seek'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
Xref: sparky comp.mail.mh:1557 comp.mail.sendmail:3297