[comp.sys.next] joinMail - putting e-mail together

rob@lighthouse.com (02/07/91)

The shar-archive below contains joinMail, a Perl script which "joins" e-mail
messages created when large files are split.  In particular, it makes
life easier when requesting files from the Purdue Archive server.

I realize that Perl is not standard on NeXT computers.  It is, however,
freely available from any comp.sources.unix archive as well as other
machines such as uunet.uu.net, tut.cis.ohio-state.edu and
jpl-devvax.jpl.nasa.gov.  See comp.lang.perl for more information on
Perl.

Rob Kedoin	rob@lighthouse.com
Lighthouse Design, Ltd
6516 Western Avenue Chevy Chase, MD 20815

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	joinMail
# This archive created: Wed Feb  6 21:26:03 1991
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(2479 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
*Legal Mumbo-Jumbo*

Copyright (C) 1991 by Rob Kedoin

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.  This software is provided "as is" without express or
implied warranty.

*Background*

Receiving large files from people via e-mail has always been a
problem.  Inevitably, some machine in the Internet has a maximum file
size that you have exceeded.  To cope with the file size problem large
files are often broken into multiple mail messages - the Purdue NeXT
Archive server does this when sending requested files and some users
break their files using tools like Bryce Jasmer's "splitmail".

Putting the pieces back together using NeXT's Mail is somewhat of a pain
because you have to select the text of each message body and copy and
paste it into one long big text file before you can begin the process
of actually unpacking your files.

joinMail makes it much less painful to put the pieces back together.

*Using joinMail*

In a Mailbox window, select the header lines of all the relevant
messages. Choose Copy from the Edit menu (it's a little known fact
that this will copy all the contents of all the selected messages),
get to a command line, and type the following:

        paste | joinMail | uudecode

JoinMail sorts the messages according to their Subject lines, extracts
their bodies, concatenates them, and sends the result to standard out.
Uudecode then converts this mess back to a binary file.

When sorting the messages, joinMail looks for Subject lines like those
sent by the Purdue Archive Server (for example, "1/11 of
next/demos/Diagram.tar.Z"). If the Subject lines don't look this way,
they are used to lexicographically sort the messages (just like
sort(1)).

*Installation Instructions*

Modify the first line of joinMail if necessary to
tell it where to find Perl.  Here I have Perl installed as
/LocalApps/perl.  The more typical place to find Perl is in
/usr/bin/perl.

Copy joinMail to a directory in your search path (~/Unix/bin, 
~/Apps, or /LocalApps are good possibilities)

*The End*

I hope this saves people time.  If nothing else, it was a good
introduction to Perl for me.

Rob Kedoin		rob@lighthouse.com
Lighthouse Design, Ltd
6516 Western Avenue Chevy Chase, MD 20815

06 February 91


SHAR_EOF
if test 2479 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 2479 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'joinMail'" '(2965 characters)'
if test -f 'joinMail'
then
	echo shar: will not over-write existing file "'joinMail'"
else
cat << \SHAR_EOF > 'joinMail'
#! /LocalApps/perl 
# joinMail
# 	Read a bunch of mail messages with headers from stdin, arrange in the
#	correct order based on the Subject lines, and print it to stdout 
#	without mail headers.
#
# Copyright (C) 1991 by Rob Kedoin
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted, provided
# that the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation.  This software is provided "as is" without express or
# implied warranty.
#
# 06-Feb-91	Rob Kedoin	rob@lighthouse.com	Initial version
#

# bring in all the data
# offset is the number of lines that have been ignored from the file.  offset
# is subtracted from $. to figure out how long a message body is.
$offset = 0;

# first is 1 when we read the first message body
$first = 1;

while (<>)
{
	# read in only lines that begin with the characters, 'M', 'b', 'e' or
	# backquote ignoring "Message-Id" lines
	if (/^[Mbe`]/ && ($_ !~ /Message-Id/) )
	{
		push(@mailMsgs,$_);
	}
	elsif (/Subject:/)
	{	
		push(@mailMsgs,$_);
		if ($first == 1)
		{
			$first = 0;
		}
		else
		{
			# subjectsAndLines maps the index of the
			# ending line of the body text and the messages
			# subject.
			$subjectsAndLines{$.-$offset} = $subject;
		}
		($junk, $subject) = split(/: /);
		chop $subject;
		$offset += 1;
	}
	else
	{
		$offset += 1;
	}	
	$lastLine = $.;
	
}
$subjectsAndLines{$.-$offset} = $subject;

# look at one subject line to determine if this came from Purdue
# assume that its from Purdue if the Subject begins with numbers followed by a
# slash
$purdue = $subject =~ /^[0-9]+\//;
	

# the keys of %subjectsAndLines are the line numbers of the ending
# line of the message text. The values are the Subject: lines of the
# message.  Create a new assoc array, %msg which uses the subject name
# as the key and has the message body text as the value
$linesSoFar = 0;
foreach $key (sort numeric (keys %subjectsAndLines))
{
# ignore the Subject line
	shift(@mailMsgs); $linesSoFar += 1;

	@theSplice = splice(@mailMsgs,0,$key-$linesSoFar);
	$linesSoFar += $#theSplice;
	$subject = $subjectsAndLines{$key};
	$msg{$subject} = join(//,@theSplice);
}
$msg{$subject} = join("",($msg{$subject},@mailMsgs));

# sort the subjects as appropriate and print the message bodies to
# standard out.
if ($purdue == 0)
{
	foreach $key (sort(keys %msg))
	{
		print $msg{$key};
	}
}
else
{
# use special sorting routine for purdue files
	foreach $key (sort purdue (keys %msg))
	{
		print $msg{$key};
	}
}


sub numeric
#  numeric is used to sort in numerical rather than string order
{
	$a > $b;
}

sub purdue
#  the subject line on files from purdue looks like:
# 	1/11 of next/demos/Diagram.tar.Z
#  use the number before the first '/' and sort numerically
{
	($aNum,@rest) = split(/\//,$a);
	($bNum,@rest) = split(/\//,$b);
	$aNum > $bNum;
}
SHAR_EOF
if test 2965 -ne "`wc -c < 'joinMail'`"
then
	echo shar: error transmitting "'joinMail'" '(should have been 2965 characters)'
fi
chmod +x 'joinMail'
fi # end of overwriting check
#	End of shell archive
exit 0