File Coverage

blib/lib/Mail/Box/Mbox.pm
Criterion Covered Total %
statement 103 105 98.1
branch 50 60 83.3
condition 30 49 61.2
subroutine 14 14 100.0
pod 7 8 87.5
total 204 236 86.4


line stmt bran cond sub pod time code
1             # Copyrights 2001-2023 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.03.
5             # This code is part of distribution Mail-Box. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package Mail::Box::Mbox;
10 25     25   10324 use vars '$VERSION';
  25         60  
  25         1729  
11             $VERSION = '3.010';
12              
13 25     25   159 use base 'Mail::Box::File';
  25         146  
  25         12104  
14              
15 25     25   193 use strict;
  25         71  
  25         594  
16 25     25   126 use warnings;
  25         52  
  25         721  
17 25     25   124 use filetest 'access';
  25         53  
  25         144  
18              
19 25     25   12373 use Mail::Box::Mbox::Message;
  25         71  
  25         33911  
20              
21              
22             our $default_folder_dir = exists $ENV{HOME} ? $ENV{HOME} . '/Mail' : '.';
23             our $default_sub_extension = '.d';
24              
25             sub init($)
26 49     49 0 676 { my ($self, $args) = @_;
27              
28             $self->{MBM_sub_ext} # required during init
29 49   66     1571 = $args->{subfolder_extension} || $default_sub_extension;
30              
31 49         306 $self->SUPER::init($args);
32             }
33              
34              
35             sub create($@)
36 11     11 1 99 { my ($thingy, $name, %args) = @_;
37 11   33     68 my $class = ref $thingy || $thingy;
38 11   33     54 $args{folderdir} ||= $default_folder_dir;
39 11   66     71 $args{subfolder_extension} ||= $default_sub_extension;
40              
41 11         125 $class->SUPER::create($name, %args);
42             }
43              
44              
45             sub foundIn($@)
46 21     21 1 149 { my $class = shift;
47 21 100       100 my $name = @_ % 2 ? shift : undef;
48 21         162 my %args = @_;
49 21 50 66     129 $name ||= $args{folder} or return;
50              
51 21   66     92 my $folderdir = $args{folderdir} || $default_folder_dir;
52 21   33     107 my $extension = $args{subfolder_extension} || $default_sub_extension;
53 21         85 my $filename = $class->folderToFilename($name, $folderdir, $extension);
54              
55 21 100       315 if(-d $filename)
56             { # Maildir and MH Sylpheed have a 'new' sub-directory
57 7 100       214 return 0 if -d File::Spec->catdir($filename, 'new');
58 5         40 local *DIR;
59 5 50       203 if(opendir DIR, $filename)
60 5         468 { my @f = grep !/^\./, readdir DIR; # skip . .. and hidden
61 5 100 66     238 return 0 if @f && ! grep /\D/, @f; # MH
62 1         24 closedir DIR;
63             }
64              
65 1 50       32 return 0 # Other MH
66             if -f "$filename/.mh_sequences";
67              
68 0         0 return 1; # faked empty Mbox sub-folder (with subsub-folders?)
69             }
70              
71 14 100       180 return 0 unless -f $filename;
72 13 100       162 return 1 if -z $filename; # empty folder is ok
73              
74 12 50       540 open my $file, '<:raw', $filename or return 0;
75 12         79 local $_;
76 12         413 while(<$file>)
77 12 50       86 { next if /^\s*$/; # skip empty lines
78 12         123 $file->close;
79 12         419 return substr($_, 0, 5) eq 'From '; # found Mbox separator?
80             }
81              
82 0         0 return 1;
83             }
84              
85             sub delete(@)
86 12     12 1 26 { my $self = shift;
87 12         68 $self->SUPER::delete(@_);
88              
89 12         83 my $subfdir = $self->filename . $default_sub_extension;
90 12         292 rmdir $subfdir; # may fail, when there are still subfolders (no recurse)
91             }
92              
93             sub writeMessages($)
94 14     14 1 54 { my ($self, $args) = @_;
95              
96 14 50       92 $self->SUPER::writeMessages($args) or return;
97              
98 14 50       65 if($self->{MB_remove_empty})
99             { # Can the sub-folder directory be removed? Don't mind if this
100             # doesn't work: probably no subdir or still something in it. This
101             # is a rather blunt approach...
102 14         123 rmdir $self->filename . $self->{MBM_sub_ext};
103             }
104              
105 14         94 $self;
106             }
107              
108             sub type() {'mbox'}
109              
110              
111             sub listSubFolders(@)
112 20     20 1 6210 { my ($thingy, %args) = @_;
113 20   66     75 my $class = ref $thingy || $thingy;
114              
115 20   100     76 my $skip_empty = $args{skip_empty} || 0;
116 20   100     68 my $check = $args{check} || 0;
117              
118 20 100       51 my $folder = exists $args{folder} ? $args{folder} : '=';
119             my $folderdir = exists $args{folderdir}
120             ? $args{folderdir}
121 20 100       50 : $default_folder_dir;
122              
123 20         36 my $extension = $args{subfolder_extension};
124              
125 20         27 my $dir;
126 20 100       42 if(ref $thingy) # Mail::Box::Mbox
127 13   33     69 { $extension ||= $thingy->{MBM_sub_ext};
128 13         83 $dir = $thingy->filename;
129             }
130             else
131 7   33     26 { $extension ||= $default_sub_extension;
132 7         17 $dir = $class->folderToFilename($folder, $folderdir, $extension);
133             }
134              
135 20 100       312 my $real = -d $dir ? $dir : "$dir$extension";
136              
137 20 100       618 opendir DIR, $real
138             or return ();
139              
140             # Some files have to be removed because they are created by all
141             # kinds of programs, but are no folders.
142              
143 11         423 my @entries = grep !m/\.lo?ck$|^\./, readdir DIR;
144 11         145 closedir DIR;
145              
146             # Look for files in the folderdir. They should be readable to
147             # avoid warnings for usage later. Furthermore, if we check on
148             # the size too, we avoid a syscall especially to get the size
149             # of the file by performing that check immediately.
150              
151 11         31 my %folders; # hash to immediately un-double names.
152              
153 11         28 foreach (@entries)
154 48         414 { my $entry = File::Spec->catfile($real, $_);
155 48 100       603 if( -f $entry )
    50          
156 34 100 100     141 { next if $args{skip_empty} && ! -s _;
157 33 100 100     86 next if $args{check} && !$class->foundIn($entry);
158 32         109 $folders{$_}++;
159             }
160             elsif( -d _ )
161             { # Directories may create fake folders.
162 14 100       49 if($args{skip_empty})
163 3 50       59 { opendir DIR, $entry or next;
164 3         83 my @sub = grep !/^\./, readdir DIR;
165 3         29 closedir DIR;
166 3 100       24 next unless @sub;
167             }
168              
169 13         98 (my $folder = $_) =~ s/$extension$//;
170 13         47 $folders{$folder}++;
171             }
172             }
173              
174 11   33     340 map +(m/(.*)/ && $1), keys %folders; # untained names
175             }
176              
177             sub openRelatedFolder(@)
178 11     11 1 27 { my $self = shift;
179             $self->SUPER::openRelatedFolder(subfolder_extension => $self->{MBM_sub_ext}
180 11         52 , @_);
181             }
182              
183             #-------------------------------------------
184              
185              
186             sub folderToFilename($$;$)
187 88     88 1 312 { my ($thingy, $name, $folderdir, $extension) = @_;
188              
189             $extension ||=
190 88 50 66     451 ref $thingy ? $thingy->{MBM_sub_ext} : $default_sub_extension;
191              
192 88         534 $name =~ s#^=#$folderdir/#;
193 88         472 my @parts = split m!/!, $name;
194              
195 88         212 my $real = shift @parts;
196 88 100       275 $real = '/' if $real eq '';
197              
198 88 100       262 if(@parts)
199 79         147 { my $file = pop @parts;
200              
201             $real = File::Spec->catdir($real.(-d $real ? '' : $extension), $_)
202 79 100       3545 foreach @parts;
203              
204 79 100       2030 $real = File::Spec->catfile($real.(-d $real ? '' : $extension), $file);
205             }
206              
207 88         611 $real;
208             }
209              
210             #-------------------------------------------
211              
212              
213             1;