package Mail::Eudora;
# see POD documentation at end

require 5.000;
require Exporter;

@ISA = qw(Exporter);
@EXPORT = qw(get_messages parse_message append_message);

$version = 0.6;
$error = "";

sub get_messages {
# return list of messages in Eudora .mbx file
# takes one lvalue argument with all messages

	my $mbx = shift;
	my $sep_rx = 'From \?{3}\@\?{3} '; #separator is literally 'From ???@??? '

	my @messages = split /$sep_rx/, $mbx;
	shift @messages; # 1st is empty, since $mbx starts with a separator
	return @messages;

} # end sub get_messages

sub parse_message {
# return a hash with headers and body of message
	my $msg = shift;
	my %message;
	my $header;
	my ($headers, $body) = $msg =~ /^(.+?\n)\n(.+)/so;
	$message{Body} = $body;
	$headers = 'X-eudora-date: ' . $headers; # msg starts with Eudora's date
	my @headers = split /^([\w\-]+): */mo, $headers;
	shift @headers; # shift 'cause split makes 1st element empty!
	while (@headers) {
		# this is short, but give 'uninitialized error with -w switch
		# 	$message{shift @headers} .= shift @headers;
		# so let's do this instead
		$header = ucfirst lc(shift @headers);
		unless (exists $message{$header}) { $message{$header} = "" };
		$message{$header} .= shift @headers;
	}
	return %message;
} # sub parse_message

sub append_message {
# append a message obtained with parse_message to an Eudora .mbx message file
	my $FILE = shift;
	my %message = @_;
	my $header;
	
	unless (open FILE, ">>$FILE") {
		$error = "Couldn't open $FILE -- $!\n";
		return undef;
	}
	
	print FILE 'From ???@??? ', $message{'X-eudora-date'};
	delete $message{'X-eudora-date'};
	
	# order some of the headers to print them in the correct position
	my @order = qw(X-Persona Received Sender);
	
	# reform Received headers
	if (exists $message{Received}) {
		$message{Received} =~ s/\n(\S)/\nReceived: $1/go;
	}

	# print first headers
	foreach $header (@order) {
		if (exists $message{$header}) {
			print FILE $header, ": ", $message{$header};
			delete $message{$header};
		}
	}
	
	# now extract body and print all other headers
	my $body =$message{Body};
	delete $message{Body};

	foreach $header (keys %message) {
		print FILE $header, ": ", $message{$header};
	}
	
	# add custom header and then print body
	print FILE "X-hack: Hacked into mailbox by Mail::Eudora v. $Mail::Eudora::version\n";
	
	print FILE "\n", $body, "\n";

	unless (close FILE) {
		$error = "Couldn't close $FILE -- $!\n";
		return 0;
	}
	return 1;
} # sub parse_message


$version;
__END__


=head1 NAME

	Mail::Eudora version 0.6 - Manipulate Eudora mailbox files


=head1 SYNOPSIS

	use Mail::Eudora;
	print "Using Mail::Eudora version $Mail::Eudora::version";
	# read an Eudora .mbx file into $mbx. Then you can:
	@messages = get_messages($mbx);
	%message_24 = parse_message(@messages[24]);
	append_message($FILE, %message_24) or warn "$Mail::Eudora::error";


=head1 DESCRIPTION

	Mail::Eudora provides a few subs to manipulate Eudora .mbx mailbox
	files. It doesn't (yet) handle the .toc index files (I hope to get
	info on the .toc structure from Qualcomm to be able to add .toc
	support in a future version).
	
	It exports the following subs to your namespace:
	    get_messages
	    parse_message
	    append_message


=head1 USAGE DETAILS


=head2

=head2 sub get_messages

=over

=item

@messages = get_messages($mbx);

=item

- takes a string containing any number of messages from an 
  Eudora .mbx mailbox file

=item

- returns an array containing all single messages.

=item

A new header is created in each message:

X-eudora-date: with the date Eudora added when it got the message.
This header is removed when you use append_message.


=head2 sub parse_message


=item

%message = parse_message(@messages[24]);

=item

- takes a string containing one message (usually an element of the
  array returned by get_messages)

=item

- returns a hash where keys are header names plus a 'Body' key and
  values are what you expect: values...

=item

$subject = $message{Subject};

$body = $message{Body};

$x_info = $message{'X-info'}; 

etc...

$message{Received} contains all Received: headers. They are restored
to separate headers when you use append_message.

=item

case of headers is normalized using ucfirst( lc $header ). So even if
the original header was "X-Info", now it is "X-info".


=head2 sub append_message

=item

append_message($FILE, %message) or warn "$Mail::Eudora::error";

=item

- takes a string containing a file name and a hash containing one
  message - usually obtained with parse_message(@messages).

=item

- returns
  1 on success,
  undef on an error opening the file,
  0 on an error closing the file (in case you care to check for
  the difference).
  If there was an error, it's now in $Mail::Eudora::error.

=item

append_message reformats %message into the correct Eudora format
and appends it to $FILE.
It also adds an X-hack: header, so you have	a trace that this message
was added by your script.


=head2 package variables


=item

The following variables are not exported, but you can still access
them with their full name:

=item

$Mail::Eudora::error - Error on a file open or close in append_message

=item

$Mail::Eudora::version - The package version number


=back


=head1 AUTHOR

C<  perl -e "print qq(mi.perl\x40alma.ch\n)"  >


=head1 NOTES

	You can use this freely.

	I would appreciate a short (or long) e-mail note if you do.
	And of course, bug-reports and/or improvements are welcome.

	Last revision: 01.04.98. Latest version should be available at
	http://alma.ch/perl

=cut