1package MIME::Body; 2 3=head1 NAME 4 5MIME::Body - the body of a MIME message 6 7 8=head1 SYNOPSIS 9 10Before reading further, you should see L<MIME::Tools> to make sure that 11you understand where this module fits into the grand scheme of things. 12Go on, do it now. I'll wait. 13 14Ready? Ok... 15 16 17=head2 Obtaining bodies 18 19 ### Get the bodyhandle of a MIME::Entity object: 20 $body = $entity->bodyhandle; 21 22 ### Create a body which stores data in a disk file: 23 $body = new MIME::Body::File "/path/to/file"; 24 25 ### Create a body which stores data in an in-core array: 26 $body = new MIME::Body::InCore \@strings; 27 28 29=head2 Opening, closing, and using IO handles 30 31 ### Write data to the body: 32 $IO = $body->open("w") || die "open body: $!"; 33 $IO->print($message); 34 $IO->close || die "close I/O handle: $!"; 35 36 ### Read data from the body (in this case, line by line): 37 $IO = $body->open("r") || die "open body: $!"; 38 while (defined($_ = $IO->getline)) { 39 ### do stuff 40 } 41 $IO->close || die "close I/O handle: $!"; 42 43 44=head2 Other I/O 45 46 ### Dump the ENCODED body data to a filehandle: 47 $body->print(\*STDOUT); 48 49 ### Slurp all the UNENCODED data in, and put it in a scalar: 50 $string = $body->as_string; 51 52 ### Slurp all the UNENCODED data in, and put it in an array of lines: 53 @lines = $body->as_lines; 54 55 56=head2 Working directly with paths to underlying files 57 58 ### Where's the data? 59 if (defined($body->path)) { ### data is on disk: 60 print "data is stored externally, in ", $body->path; 61 } 62 else { ### data is in core: 63 print "data is already in core, and is...\n", $body->as_string; 64 } 65 66 ### Get rid of anything on disk: 67 $body->purge; 68 69 70=head1 DESCRIPTION 71 72MIME messages can be very long (e.g., tar files, MPEGs, etc.) or very 73short (short textual notes, as in ordinary mail). Long messages 74are best stored in files, while short ones are perhaps best stored 75in core. 76 77This class is an attempt to define a common interface for objects 78which contain message data, regardless of how the data is 79physically stored. The lifespan of a "body" object 80usually looks like this: 81 82=over 4 83 84=item 1. 85 86B<Body object is created by a MIME::Parser during parsing.> 87It's at this point that the actual MIME::Body subclass is chosen, 88and new() is invoked. (For example: if the body data is going to 89a file, then it is at this point that the class MIME::Body::File, 90and the filename, is chosen). 91 92=item 2. 93 94B<Data is written to the body> (usually by the MIME parser) like this: 95The body is opened for writing, via C<open("w")>. This will trash any 96previous contents, and return an "I/O handle" opened for writing. 97Data is written to this I/O handle, via print(). 98Then the I/O handle is closed, via close(). 99 100=item 3. 101 102B<Data is read from the body> (usually by the user application) like this: 103The body is opened for reading by a user application, via C<open("r")>. 104This will return an "I/O handle" opened for reading. 105Data is read from the I/O handle, via read(), getline(), or getlines(). 106Then the I/O handle is closed, via close(). 107 108=item 4. 109 110B<Body object is destructed.> 111 112=back 113 114You can write your own subclasses, as long as they follow the 115interface described below. Implementers of subclasses should assume 116that steps 2 and 3 may be repeated any number of times, and in 117different orders (e.g., 1-2-2-3-2-3-3-3-3-3-2-4). 118 119In any case, once a MIME::Body has been created, you ask to open it 120for reading or writing, which gets you an "i/o handle": you then use 121the same mechanisms for reading from or writing to that handle, no matter 122what class it is. 123 124Beware: unless you know for certain what kind of body you have, you 125should I<not> assume that the body has an underlying filehandle. 126 127 128=head1 PUBLIC INTERFACE 129 130=over 4 131 132=cut 133 134 135### Pragmas: 136use strict; 137use vars qw($VERSION); 138 139### System modules: 140use Carp; 141use IO::File; 142 143### The package version, both in 1.23 style *and* usable by MakeMaker: 144$VERSION = "5.509"; 145 146 147#------------------------------ 148 149=item new ARGS... 150 151I<Class method, constructor.> 152Create a new body. Any ARGS are sent to init(). 153 154=cut 155 156sub new { 157 my $self = bless {}, shift; 158 $self->init(@_); 159 $self; 160} 161 162#------------------------------ 163 164=item init ARGS... 165 166I<Instance method, abstract, initiallizer.> 167This is called automatically by C<new()>, with the arguments given 168to C<new()>. The arguments are optional, and entirely up to the 169subclass. The default method does nothing, 170 171=cut 172 173sub init { 1 } 174 175#------------------------------ 176 177=item as_lines 178 179I<Instance method.> 180Return the contents of the body as an array of lines (each terminated 181by a newline, with the possible exception of the final one). 182Returns empty on failure (NB: indistinguishable from an empty body!). 183 184Note: the default method gets the data via 185repeated getline() calls; your subclass might wish to override this. 186 187=cut 188 189sub as_lines { 190 my $self = shift; 191 my @lines; 192 my $io = $self->open("r") || return (); 193 local $_; 194 push @lines, $_ while (defined($_ = $io->getline())); 195 $io->close; 196 @lines; 197} 198 199#------------------------------ 200 201=item as_string 202 203I<Instance method.> 204Return the body data as a string (slurping it into core if necessary). 205Best not to do this unless you're I<sure> that the body is reasonably small! 206Returns empty string for an empty body, and undef on failure. 207 208Note: the default method uses print(), which gets the data via 209repeated read() calls; your subclass might wish to override this. 210 211=cut 212 213sub as_string { 214 my $self = shift; 215 my $str = ''; 216 my $fh = IO::File->new(\$str, '>:') or croak("Cannot open in-memory file: $!"); 217 $self->print($fh); 218 close($fh); 219 return $str; 220} 221*data = \&as_string; ### silently invoke preferred usage 222 223 224#------------------------------ 225 226=item binmode [ONOFF] 227 228I<Instance method.> 229With argument, flags whether or not open() should return an I/O handle 230which has binmode() activated. With no argument, just returns the 231current value. 232 233=cut 234 235sub binmode { 236 my ($self, $onoff) = @_; 237 $self->{MB_Binmode} = $onoff if (@_ > 1); 238 $self->{MB_Binmode}; 239} 240 241#------------------------------ 242 243=item is_encoded [ONOFF] 244 245I<Instance method.> 246If set to yes, no decoding is applied on output. This flag is set 247by MIME::Parser, if the parser runs in decode_bodies(0) mode, so the 248content is handled unmodified. 249 250=cut 251 252sub is_encoded { 253 my ($self, $yesno) = @_; 254 $self->{MB_IsEncoded} = $yesno if (@_ > 1); 255 $self->{MB_IsEncoded}; 256} 257 258#------------------------------ 259 260=item dup 261 262I<Instance method.> 263Duplicate the bodyhandle. 264 265I<Beware:> external data in bodyhandles is I<not> copied to new files! 266Changing the data in one body's data file, or purging that body, 267I<will> affect its duplicate. Bodies with in-core data probably need 268not worry. 269 270=cut 271 272sub dup { 273 my $self = shift; 274 bless { %$self }, ref($self); ### shallow copy ok for ::File and ::Scalar 275} 276 277#------------------------------ 278 279=item open READWRITE 280 281I<Instance method, abstract.> 282This should do whatever is necessary to open the body for either 283writing (if READWRITE is "w") or reading (if mode is "r"). 284 285This method is expected to return an "I/O handle" object on success, 286and undef on error. An I/O handle can be any object that supports a 287small set of standard methods for reading/writing data. 288See the IO::Handle class for an example. 289 290=cut 291 292sub open { 293 undef; 294} 295 296#------------------------------ 297 298=item path [PATH] 299 300I<Instance method.> 301If you're storing the body data externally (e.g., in a disk file), you'll 302want to give applications the ability to get at that data, for cleanup. 303This method should return the path to the data, or undef if there is none. 304 305Where appropriate, the path I<should> be a simple string, like a filename. 306With argument, sets the PATH, which should be undef if there is none. 307 308=cut 309 310sub path { 311 my $self = shift; 312 $self->{MB_Path} = shift if @_; 313 $self->{MB_Path}; 314} 315 316#------------------------------ 317 318=item print FILEHANDLE 319 320I<Instance method.> 321Output the body data to the given filehandle, or to the currently-selected 322one if none is given. 323 324=cut 325 326sub print { 327 my ($self, $fh) = @_; 328 my $nread; 329 330 ### Get output filehandle, and ensure that it's a printable object: 331 $fh ||= select; 332 333 ### Write it: 334 my $buf = ''; 335 my $io = $self->open("r") || return undef; 336 $fh->print($buf) while ($nread = $io->read($buf, 8192)); 337 $io->close; 338 return defined($nread); ### how'd we do? 339} 340 341#------------------------------ 342 343=item purge 344 345I<Instance method, abstract.> 346Remove any data which resides external to the program (e.g., in disk files). 347Immediately after a purge(), the path() should return undef to indicate 348that the external data is no longer available. 349 350=cut 351 352sub purge { 353 1; 354} 355 356 357 358=back 359 360=head1 SUBCLASSES 361 362The following built-in classes are provided: 363 364 Body Stores body When open()ed, 365 class: data in: returns: 366 -------------------------------------------------------- 367 MIME::Body::File disk file IO::Handle 368 MIME::Body::Scalar scalar IO::Handle 369 MIME::Body::InCore scalar array IO::Handle 370 371=cut 372 373 374#------------------------------------------------------------ 375package MIME::Body::File; 376#------------------------------------------------------------ 377 378=head2 MIME::Body::File 379 380A body class that stores the data in a disk file. Invoke the 381constructor as: 382 383 $body = new MIME::Body::File "/path/to/file"; 384 385In this case, the C<path()> method would return the given path, 386so you I<could> say: 387 388 if (defined($body->path)) { 389 open BODY, $body->path or die "open: $!"; 390 while (<BODY>) { 391 ### do stuff 392 } 393 close BODY; 394 } 395 396But you're best off not doing this. 397 398=cut 399 400 401### Pragmas: 402use vars qw(@ISA); 403use strict; 404 405### System modules: 406use IO::File; 407 408### Kit modules: 409use MIME::Tools qw(whine); 410 411@ISA = qw(MIME::Body); 412 413 414#------------------------------ 415# init PATH 416#------------------------------ 417sub init { 418 my ($self, $path) = @_; 419 $self->path($path); ### use it as-is 420 $self; 421} 422 423#------------------------------ 424# open READWRITE 425#------------------------------ 426sub open { 427 my ($self, $mode) = @_; 428 429 my $path = $self->path; 430 431 if( $mode ne 'r' && $mode ne 'w' ) { 432 die "bad mode: '$mode'"; 433 } 434 435 my $IO = IO::File->new($path, $mode) || die "MIME::Body::File->open $path: $!"; 436 437 $IO->binmode() if $self->binmode; 438 439 return $IO; 440} 441 442#------------------------------ 443# purge 444#------------------------------ 445# Unlink the path (and undefine it). 446# 447sub purge { 448 my $self = shift; 449 if (defined($self->path)) { 450 unlink $self->path or whine "couldn't unlink ".$self->path.": $!"; 451 $self->path(undef); 452 } 453 1; 454} 455 456 457 458 459#------------------------------------------------------------ 460package MIME::Body::Scalar; 461#------------------------------------------------------------ 462 463=head2 MIME::Body::Scalar 464 465A body class that stores the data in-core, in a simple scalar. 466Invoke the constructor as: 467 468 $body = new MIME::Body::Scalar \$string; 469 470A single scalar argument sets the body to that value, exactly as though 471you'd opened for the body for writing, written the value, 472and closed the body again: 473 474 $body = new MIME::Body::Scalar "Line 1\nLine 2\nLine 3"; 475 476A single array reference sets the body to the result of joining all the 477elements of that array together: 478 479 $body = new MIME::Body::Scalar ["Line 1\n", 480 "Line 2\n", 481 "Line 3"]; 482 483=cut 484 485use vars qw(@ISA); 486use strict; 487 488use Carp; 489 490@ISA = qw(MIME::Body); 491 492 493#------------------------------ 494# init DATA 495#------------------------------ 496sub init { 497 my ($self, $data) = @_; 498 $data = join('', @$data) if (ref($data) && (ref($data) eq 'ARRAY')); 499 $self->{MBS_Data} = (defined($data) ? $data : ''); 500 $self; 501} 502 503#------------------------------ 504# as_string 505#------------------------------ 506sub as_string { 507 shift->{MBS_Data}; 508} 509 510#------------------------------ 511# open READWRITE 512#------------------------------ 513sub open { 514 my ($self, $mode) = @_; 515 $self->{MBS_Data} = '' if ($mode eq 'w'); ### writing 516 517 if ($mode eq 'w') { 518 $mode = '>:'; 519 } elsif ($mode eq 'r') { 520 $mode = '<:'; 521 } else { 522 die "bad mode: $mode"; 523 } 524 525 return IO::File->new(\ $self->{MBS_Data}, $mode); 526} 527 528 529 530 531 532#------------------------------------------------------------ 533package MIME::Body::InCore; 534#------------------------------------------------------------ 535 536=head2 MIME::Body::InCore 537 538A body class that stores the data in-core. 539Invoke the constructor as: 540 541 $body = new MIME::Body::InCore \$string; 542 $body = new MIME::Body::InCore $string; 543 $body = new MIME::Body::InCore \@stringarray 544 545A simple scalar argument sets the body to that value, exactly as though 546you'd opened for the body for writing, written the value, 547and closed the body again: 548 549 $body = new MIME::Body::InCore "Line 1\nLine 2\nLine 3"; 550 551A single array reference sets the body to the concatenation of all 552scalars that it holds: 553 554 $body = new MIME::Body::InCore ["Line 1\n", 555 "Line 2\n", 556 "Line 3"]; 557 558=cut 559 560use vars qw(@ISA); 561use strict; 562 563use Carp; 564 565@ISA = qw(MIME::Body::Scalar); 566 567 568#------------------------------ 569# init DATA 570#------------------------------ 571sub init { 572 my ($self, $data) = @_; 573 if (!defined($data)) { ### nothing 574 $self->{MBS_Data} = ''; 575 } 576 elsif (!ref($data)) { ### simple scalar 577 $self->{MBS_Data} = $data; 578 } 579 elsif (ref($data) eq 'SCALAR') { 580 $self->{MBS_Data} = $$data; 581 } 582 elsif (ref($data) eq 'ARRAY') { 583 $self->{MBS_Data} = join('', @$data); 584 } 585 else { 586 croak "I can't handle DATA which is a ".ref($data)."\n"; 587 } 588 $self; 589} 590 5911; 592__END__ 593 594 595#------------------------------ 596 597=head2 Defining your own subclasses 598 599So you're not happy with files and scalar-arrays? 600No problem: just define your own MIME::Body subclass, and make a subclass 601of MIME::Parser or MIME::ParserBase which returns an instance of your 602body class whenever appropriate in the C<new_body_for(head)> method. 603 604Your "body" class must inherit from MIME::Body (or some subclass of it), 605and it must either provide (or inherit the default for) the following 606methods... 607 608The default inherited method I<should suffice> for all these: 609 610 new 611 binmode [ONOFF] 612 path 613 614The default inherited method I<may suffice> for these, but perhaps 615there's a better implementation for your subclass. 616 617 init ARGS... 618 as_lines 619 as_string 620 dup 621 print 622 purge 623 624The default inherited method I<will probably not suffice> for these: 625 626 open 627 628 629 630=head1 NOTES 631 632One reason I didn't just use IO::Handle objects for message bodies was 633that I wanted a "body" object to be a form of completely encapsulated 634program-persistent storage; that is, I wanted users to be able to write 635code like this... 636 637 ### Get body handle from this MIME message, and read its data: 638 $body = $entity->bodyhandle; 639 $IO = $body->open("r"); 640 while (defined($_ = $IO->getline)) { 641 print STDOUT $_; 642 } 643 $IO->close; 644 645...without requiring that they know anything more about how the 646$body object is actually storing its data (disk file, scalar variable, 647array variable, or whatever). 648 649Storing the body of each MIME message in a persistently-open 650IO::Handle was a possibility, but it seemed like a bad idea, 651considering that a single multipart MIME message could easily suck up 652all the available file descriptors on some systems. This risk increases 653if the user application is processing more than one MIME entity at a time. 654 655=head1 SEE ALSO 656 657L<MIME::Tools> 658 659=head1 AUTHOR 660 661Eryq (F<eryq@zeegee.com>), ZeeGee Software Inc (F<http://www.zeegee.com>). 662David F. Skoll (dfs@roaringpenguin.com) http://www.roaringpenguin.com 663 664All rights reserved. This program is free software; you can redistribute 665it and/or modify it under the same terms as Perl itself. 666 667Thanks to Achim Bohnet for suggesting that MIME::Parser not be restricted 668to the use of FileHandles. 669 670#------------------------------ 6711; 672 673