MIME::Body

Home | MIME::Body | MIME::Decoder | MIME::Entity | MIME::Head
MIME::IO | MIME::Latin1 | MIME::Parser | MIME::ParserBase
MIME::ToolUtils

# MIME:: Body It's MIME time! | NAME SYNOPSIS DESCRIPTION DEFINING YOUR OWN SUBCLASSES Writing a "body" class Writing/using an "I/O handle" class NOTES Design issues SUBCLASSES MIME::Body::File; MIME::Body::Scalar; AUTHOR VERSION

## 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:

1. 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).

2. 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().`

3. 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().`

4. 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 to `new()`. 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: 1.11 $ $Date: 1997/01/13 00:21:47 $