NAME
MIME::Body - the body of a MIME message
SYNOPSIS
Here's how a typical body object is created and used:
# Create new body:
$body = new MIME::Body::File "/path/to/file";
# Write data to the body:
$IO = $body->open("w") || die "open body: $!";
$IO->print($message);
$IO->close || die "close I/O handle: $!";
# Read data from the body:
$IO = $body->open("r") || die "open body: $!";
while (defined($_ = $IO->getline)) {
# do stuff
}
$IO->close || die "close I/O handle: $!";
For example, this subclass stores the data in a disk file, which is only opened when needed:
$body = new MIME::Body::File "/path/to/file";
While this subclass stores the data in an in-core scalar:
$body = new MIME::Body::Scalar \$scalar;
In any case, once a MIME::Body has been created, you use the same mechanisms for reading from or writing to it, no matter what the subclass is.
DESCRIPTION
MIME messages can be very long (e.g., tar files, MPEGs, etc.) or very short (short textual notes, as in ordinary mail). Long messages are best stored in files, while short ones are perhaps best stored in core.
This class is an attempt to define a common interface for objects which contain message data, regardless of how the data is physically stored. Here's an overview:
head() .--------.
returns a... | MIME:: |
.------------>| Head |
.--------. `--------'
| MIME:: |
| Entity | .--------.
`--------' | MIME:: |
`------------>| Body | .--------. read()
bodyhandle() `--------' | MIME:: | getline()
returns a... `------------>| IO | print()
open() `--------' etc...
returns a...
It works this way:
An "entity" has a "head" and a "body". Entities are MIME message parts.
A "body" knows where the data is. You can ask to "open" this data source for reading or writing, and you will get back an "I/O handle".
An "I/O handle" knows how to read/write the data. It is an object that is basically like an IO::Handle or a FileHandle... it can be any class, so long as it supports a small, standard set of methods for reading from or writing to the underlying data source.
The lifespan of a "body" usually looks like this:
Body object is created by a MIME::Parser during parsing. It's at this point that the actual MIME::Body subclass is chosen, and new() is invoked. (For example: if the body data is going to a file, then it is at this point that the class MIME::Body::File, and the filename, is chosen).
Data is written (usually by the MIME parser) like this:
a. Body is opened for writing, via
open("w")
. This will trash any previous contents, and return an "I/O handle" opened for writing.b. Data is written to the I/O handle, via print().
c. I/O handle is closed, via close().
Data is read (usually by the user application) like this:
a. Body is opened for reading by a user application, via
open("r")
. This will return an "I/O handle" opened for reading.b. Data is read from the I/O handle, via read(), getline(), or getlines().
c. I/O handle is closed, via close().
Body object is destructed.
You can write your own subclasses, as long as they follow the interface described below. Implementers of subclasses should assume that steps 2 and 3 may be repeated any number of times, and in different orders (e.g., 1-2-2-3-2-3-3-3-3-3-2-4).
Users should be aware that unless they know for certain what they have, they should not assume that the body has an underlying filehandle.
DEFINING YOUR OWN SUBCLASSES
So you're not happy with files and scalars? No problem: just define your own MIME::Body subclass, and make a subclass of MIME::Parser or MIME::ParserBase which returns an instance of your body class whenever appropriate in the new_body_for(head)
method.
Writing a "body" class
Your "body" class must inherit from MIME::Body (or some subclass of it), and it must either provide or inherit the following methods:
- init ARGS...
-
Instance method. This is called automatically by
new()
, with the arguments given tonew()
. The arguments are optional, and entirely up to your class. - open MODE
-
Instance method. This should do whatever is necessary to open the body for either writing (if MODE is "w") or reading (if mode is "r"). Return an "I/O handle" on success, false on error.
- binmode [ONOFF]
-
Instance method. With argument, flags whether or not open() should return an I/O handle which has binmode() activated. With no argument, just returns the current value. The inherited action should be fine.
- path
-
Instance method. Oh, the joys of encapsulation. If you're storing the body data in a new disk file, you'll want to give applications the ability to get at that file, if only for cleanup (see MIME::Entity::purge() for an example). This method should return the path to the file, or undef if there is none (e.g., if the data is in core). The default inherited method just returns undef.
Writing/using an "I/O handle" class
Your "body" class' open()
method must return an "I/O handle" object, which can be any object that supports a small set of standard methods for reading/writing data.
See the documentation on the MIME::IO class for details on what is expected of an I/O handle. Note that the IO::Handle class already conforms to this interface.
NOTES
Design issues
One reason I didn't just use FileHandle or IO::Handle objects for message bodies was that I wanted a "body" object to be a form of completely encapsulated program-persistent storage; that is, I wanted users to be able to write code like this...
# Get body handle from this MIME message, and read its data:
$body = $entity->bodyhandle;
$IO = $body->open("r");
while (defined($_ = $IO->getline)) {
print STDOUT $_;
}
$IO->close;
...without requiring that they know anything more about how the $body object is actually storing its data (disk file, scalar variable, array variable, or whatever).
Storing the body of each MIME message in a persistently-open IO::Handle was a possibility, but it seemed like a bad idea, considering that a single multipart MIME message could easily suck up all the available file descriptors on som OSes. This risk increases if the user application is processing more than one MIME entity at a time.
SUBCLASSES
Basically, we have the following classes:
Body Stores body When open()ed, Someday soon
class: data in: returns: will return:
----------------------------------------------------------------------
MIME::Body::File disk file MIME::IO::Handle IO::Handle
MIME::Body::Scalar scalar MIME::IO::Scalar IO::????
MIME::Body::File;
A body class that stores the data in a disk file. The I/O handle is a wrapped filehandle. Invoke the constructor as:
$body = new MIME::Body::File "/path/to/file";
In this case, the path()
method would return the given path.
You can even use this class to pipe the data through shell commands on input and/or output. For example, here's an easy way to store the data in compressed format without having to explicitly do the compression yourself:
$body = new MIME::Body::File "/tmp/somefile.gz";
$body->writer("| gzip > /tmp/somefile.gz");
$body->reader("zcat /tmp/somefile.gz |");
...
$IO = $body->open("w") || die "open failed: $!";
$IO->print("I'll automatically be stored compressed!\n");
$IO->close || die "close failed: $!";
Notice the semantics of the "path" in this case: it names the file that is created to hold the data, even though that file can't be used directly.
Note: All of the usual caveats related to shell commands apply! To make sure you won't accidentally do something you'll regret, use taint-checking (perl -T) in your application.
Note: I would have had MIME::Body::File return a FileHandle, except that there are some methods that FileHandle does not support in 5.002, and it was too soon to require IO::Handle.
MIME::Body::Scalar;
A body class that stores the data in-core, in a simple scalar. Invoke the constructor as:
$body = new MIME::Body::Scalar \$scalar;
A single scalar argument sets the body to that value, exactly as though you'd opened for the body for writing, written the value, and closed the body again:
$body = new MIME::Body::Scalar "Line 1\nLine 2\nLine 3";
A single array reference sets the body to the result of joining all the elements of that array together:
$body = new MIME::Body::Scalar ["Line 1\n",
"Line 2\n",
"Line 3"];
Uses MIME::IO::Scalar as the I/O handle.
AUTHOR
Copyright (c) 1996 by Eryq / eryq@rhine.gsfc.nasa.gov
All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Thanks to Achim Bohnet for suggesting that MIME::Parser not be restricted to the use of FileHandles.
VERSION
$Revision: 3.201 $ $Date: 1997/01/19 00:52:58 $