#! /usr/bin/perl

    #	Break a monolithic mail folder into a directory
    #	with one message per file.
        
    #	by John Walker  http://www.fourmilab.ch/
    #	    	   September 2002

    if ($#ARGV < 1) {
    	print("Usage: perl fragmail.pl mail_folder_file target_directory\n");
	exit(2);
    }
    
    if (!(-d $ARGV[1])) {
    	die "Target directory $ARGV[1] does not exist";
    }
    
    $totalMessages = 0;
    
    $inf = $ARGV[0];
    if ($inf =~ m/\.gz$/) {
    	open(IN, "zcat $inf |") || die "Cannot open gzipped input file $inf";
    } else {
    	open(IN, "<$inf") || die "Cannot open input file $inf";
    }
    
    while (($l = <IN>)) {
    	if ($l =~ m/^From /) {
    	    last;
	}
    }
    
    if (!$l) {
    	print("No messages in mail folder!\n");
	exit(0);
    }
    
    $eof = 0;
    
    while (!$eof) {
    
    	#   Read next message from mail folder.  At
	#   this point $l contains the first ("From ")
	#   line of the message.
	
	$nlines = 0;
	undef @message;
	$msize = length($l);
	&trim_end_of_line;
	$message[$nlines++] = $l;
	
	#   Read the balance of the message into the
	#   @message array.  Quit when the "From " line
	#   of the next message is encountered or the
	#   end of the folder is encountered.
	
	while ($l = <IN>) {
	    if ($l =~ m/^From /) {
		last;
	    } else {
	    	&trim_end_of_line;
	    	$message[$nlines++] = $l;
	    	$msize += length($l);
    	    }
	}
	if ($nlines > 0) {
	    &dispose_of_message;
	}
	$eof = !($l);
# if ($bail++ > 20) { $eof = 1; }  # Quick bail-out for testing
    }
    
    #	Compute and display aggregate statistics
    
    print("Total messages: $totalMessages\n");

#   Dispose of the message in the @message
#   array.
    
sub dispose_of_message {
    local($i, $from, $to, $subject, $disp,
    	  $afrom, $act, $oname);
    
    #	Parse message header for "interesting" items
    
    for ($i = 0; $i < $nlines; $i++) {
    	if ((length($message[$i]) == 0) ||
	    ($message[$i] =~ m/^\s*$/)) {
#print("Bail on line $i\n");
	    last;
	}
	
	if ($message[$i] =~ m/^From\s/) {
	    if (!($message[$i] =~ m/^From\s+-\s+/)) {
	    	$from = $message[$i];
	    } else {
	    	$afrom = $message[$i];
	    }
	}
	elsif ((!defined($from)) && ($message[$i] =~ m/^From:\s/)) {
	    $from = $message[$i];
	}
	elsif ($message[$i] =~ m/^To:\s/) {
	    $to = $message[$i];
	}
	elsif ($message[$i] =~ m/^Subject:\s/) {
	    $subject = $message[$i];
	}
	elsif ($message[$i] =~ m/^Date:\s/) {
	    $date = $message[$i];
	}
    }
    if (!defined($from)) {
    	$from = $afrom;
    }
    
    
    $totalMessages++;
    
    #	If a file with the proposed message number already
    #	exists, advance the message number until we find
    #	one which avoids collision.  This allows dumping
    #	messages from multiple folders into the same target
    #	directory with multiple runs of this program.
    
    while (-f "$ARGV[1]/message_$totalMessages") {
    	$totalMessages++;
    }
    
    $oname = "$ARGV[1]/message_$totalMessages";
    open(OF, ">$oname") || die
    	"Cannot create $ARGV[1]/message_$totalMessages";
	
    for ($i = 0; $i < $nlines; $i++) {
    	print(OF "$message[$i]\n");
    }
    close(OF);
print("$ARGV[1]/message_$totalMessages: $from\n");
    
}

#   Trim end of line sequences from line

sub trim_end_of_line {
    $l =~ s/(.*)([\r\n]+)$/\1/;
}


syntax highlighted by Code2HTML, v. 0.9.1