File Coverage

blib/lib/Mail/MBX/Message.pm
Criterion Covered Total %
statement 9 36 25.0
branch 0 26 0.0
condition n/a
subroutine 3 6 50.0
pod 3 3 100.0
total 15 71 21.1


line stmt bran cond sub pod time code
1             package Mail::MBX::Message;
2              
3             =head1 NAME
4              
5             Mail::MBX::Message - An MBX mailbox message object
6              
7             =head1 SYNOPSIS
8              
9             use Mail::MBX ();
10              
11             my $mbx = Mail::MBX->open('mailbox.mbx');
12              
13             #
14             # Fetch and read first message in mailbox
15             #
16             my $message = $mbx->message;
17              
18             #
19             # Write message body to standard output
20             #
21             while (my $readlen = $message->read(my $buf, 4096)) {
22             print $buf;
23             }
24              
25             $mbx->close;
26              
27             =head1 DESCRIPTION
28              
29             C represents an MBX message object within an existing
30             C> file object. Because C objects contain
31             state specific to the parent object's file handle, only one message can be
32             read per mailbox at a time.
33              
34             =head1 USAGE
35              
36             =over
37              
38             =cut
39              
40 1     1   6 use strict;
  1         1  
  1         27  
41 1     1   4 use warnings;
  1         1  
  1         17  
42              
43 1     1   438 use Time::Local ();
  1         1606  
  1         622  
44              
45             my %MONTHS = (
46             'Jan' => 0,
47             'Feb' => 1,
48             'Mar' => 2,
49             'Apr' => 3,
50             'May' => 4,
51             'Jun' => 5,
52             'Jul' => 6,
53             'Aug' => 7,
54             'Sep' => 8,
55             'Oct' => 9,
56             'Nov' => 10,
57             'Dec' => 11
58             );
59              
60             =item Cparse(I<$fh>)>
61              
62             Not intended to be used as part of a public interface. Given the file handle
63             specified in I<$fh>, this method will return a new C object
64             representing the message found at the current position of I<$fh>.
65              
66             =cut
67              
68             sub parse {
69 0     0 1   my ( $class, $fh ) = @_;
70              
71 0 0         if ( eof $fh ) {
72 0           return;
73             }
74              
75 0           my $header = readline($fh);
76 0           my $offset = tell($fh);
77              
78             #
79             # tidyoff -- perltidy would wreak havoc on this poor expression
80             #
81 0           my ( $date, $time, $metadata ) = split /\s+/, $header;
82              
83 0 0         my ( $day, $month, $year ) = (
84             $date =~ /^( \d|\d\d)-(\w{3})-(\d{4})$/
85             ) or die('Invalid syntax: Bad date');
86              
87 0 0         my ( $hour, $minute, $second ) = (
88             $time =~ /^(\d{2}):(\d{2}):(\d{2})$/
89             ) or die('Invalid syntax: Bad timestamp');
90              
91 0 0         my ( $tz, $size, $attributes ) = (
92             $metadata =~ /^([+\-]\d{4}),(\d+);(\S+)$/
93             ) or die('Invalid syntax: Bad metadata');
94              
95 0 0         my ( $tzNegative, $tzHourOffset, $tzMinuteOffset ) = (
96             $tz =~ /^([+\-])(\d{2})(\d{2})$/
97             ) or die('Invalid syntax: Bad timezone offset');
98              
99 0 0         my ( $hexFlags, $hexUid ) = (
100             $attributes =~ /^[[:xdigit:]]{8}([[:xdigit:]]{4})-([[:xdigit:]]{8})$/
101             ) or die('Invalid syntax: Bad attributes');
102              
103 0 0         my $flags =
    0          
    0          
    0          
104             ( ( hex($hexFlags) & 0x1 ) ? 'S' : '' )
105             . ( ( hex($hexFlags) & 0x2 ) ? 'T' : '' )
106             . ( ( hex($hexFlags) & 0x4 ) ? 'F' : '' )
107             . ( ( hex($hexFlags) & 0x8 ) ? 'R' : '' );
108              
109 0 0         my $timestamp = Time::Local::timegm(
110             $second, $minute, $hour, $day + 0, $MONTHS{$month}, $year
111             ) + ( ( $tzNegative eq '-' ? 1 : -1 )
112             * ( $tzHourOffset * 60 + $tzMinuteOffset ) * 60 );
113              
114             #
115             # tidyon
116             #
117              
118 0           return bless {
119             'fh' => $fh,
120             'uid' => hex($hexUid),
121             'timestamp' => $timestamp,
122             'flags' => $flags,
123             'size' => $size,
124             'offset' => $offset,
125             'remaining' => $size,
126             'current' => $offset
127             }, $class;
128             }
129              
130             =item C<$message-Ereset()>
131              
132             Reset internal file handle position to beginning of message.
133              
134             =cut
135              
136             sub reset {
137 0     0 1   my ($self) = @_;
138              
139 0           @{$self}{qw(remaining current)} = @{$self}{qw(size offset)};
  0            
  0            
140              
141 0           seek( $self->{'fh'}, $self->{'offset'}, 0 );
142              
143 0           return;
144             }
145              
146             =item C<$message-Eread(I<$buf>, I<$len>)>
147              
148             Read at most I<$len> bytes from the current message, into a scalar variable
149             in the argument of I<$buf>, and return the number of bytes actually read from
150             the current message.
151              
152             =cut
153              
154             sub read {
155 0     0 1   my ( $self, $buf, $len ) = @_;
156              
157 0 0         if ( $self->{'remaining'} <= 0 ) {
158 0           return;
159             }
160              
161 0 0         $len = $self->{'remaining'} if $len > $self->{'remaining'};
162              
163 0           my $readlen = CORE::read( $self->{'fh'}, $_[1], $len );
164              
165 0           $self->{'remaining'} -= $readlen;
166              
167 0           return $readlen;
168             }
169              
170             1;
171              
172             =back
173              
174             =cut
175              
176             __END__