File Coverage

blib/lib/Mail/Cap.pm
Criterion Covered Total %
statement 92 138 66.6
branch 29 56 51.7
condition 8 17 47.0
subroutine 11 25 44.0
pod 14 20 70.0
total 154 256 60.1


line stmt bran cond sub pod time code
1             # Copyrights 1995-2018 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.02.
5             # This code is part of the bundle MailTools. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md for Copyright.
7             # Licensed under the same terms as Perl itself.
8              
9             package Mail::Cap;
10 2     2   989 use vars '$VERSION';
  2         4  
  2         114  
11             $VERSION = '2.20';
12              
13              
14 2     2   13 use strict;
  2         5  
  2         4087  
15              
16 0     0 0 0 sub Version { our $VERSION }
17              
18              
19             our $useCache = 1; # don't evaluate tests every time
20              
21             my @path;
22             if($^O eq "MacOS")
23             { @path = split /\,/, $ENV{MAILCAPS} || "$ENV{HOME}mailcap";
24             }
25             else
26             { @path = split /\:/
27             , ( $ENV{MAILCAPS} || (defined $ENV{HOME} ? "$ENV{HOME}/.mailcap:" : '')
28             . '/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap'
29             ); # this path is specified under RFC1524 appendix A
30             }
31              
32             #--------
33              
34             sub new
35 1     1 1 137 { my $class = shift;
36            
37 1 50       6 unshift @_, 'filename' if @_ % 2;
38 1         4 my %args = @_;
39              
40 1   33     3 my $take_all = $args{take} && uc $args{take} eq 'ALL';
41              
42 1         2 my $self = bless {_count => 0}, $class;
43              
44             $self->_process_file($args{filename})
45 1 50 33     22 if defined $args{filename} && -r $args{filename};
46              
47 1 50 33     13 if(!defined $args{filename} || $take_all)
48 0         0 { foreach my $fname (@path)
49 0 0       0 { -r $fname or next;
50              
51 0         0 $self->_process_file($fname);
52 0 0       0 last unless $take_all;
53             }
54             }
55              
56 1 50       4 unless($self->{_count})
57             { # Set up default mailcap
58 0         0 $self->{'audio/*'} = [{'view' => "showaudio %s"}];
59 0         0 $self->{'image/*'} = [{'view' => "xv %s"}];
60 0         0 $self->{'message/rfc822'} = [{'view' => "xterm -e metamail %s"}];
61             }
62              
63 1         4 $self;
64             }
65              
66             sub _process_file
67 1     1   2 { my $self = shift;
68 1 50       2 my $file = shift or return;
69              
70 1         3 local *MAILCAP;
71 1 50       29 open MAILCAP, $file
72             or return;
73              
74 1         8 $self->{_file} = $file;
75              
76 1         2 local $_;
77 1         12 while()
78 13 100       27 { next if /^\s*#/; # comment
79 12 100       57 next if /^\s*$/; # blank line
80 5         50 $_ .= # continuation line
81             while s/(^|[^\\])((?:\\\\)*)\\\s*$/$1$2/;
82 5         8 chomp;
83 5         6 s/\0//g; # ensure no NULs in the line
84 5         32 s/(^|[^\\]);/$1\0/g; # make field separator NUL
85 5         29 my ($type, $view, @parts) = split /\s*\0\s*/;
86              
87 5 100       12 $type .= "/*" if $type !~ m[/];
88 5         9 $view =~ s/\\;/;/g;
89 5         7 $view =~ s/\\\\/\\/g;
90 5         11 my %field = (view => $view);
91              
92 5         8 foreach (@parts)
93 6         56 { my($key, $val) = split /\s*\=\s*/, $_, 2;
94 6 100       15 if(defined $val)
95 3         7 { $val =~ s/\\;/;/g;
96 3         4 $val =~ s/\\\\/\\/g;
97 3         13 $field{$key} = $val;
98             }
99             else
100 3         9 { $field{$key} = 1;
101             }
102             }
103              
104 5 100       15 if(my $test = $field{test})
105 1 50       4 { unless ($test =~ /\%/)
106             { # No parameters in test, can perform it right away
107 0         0 system $test;
108 0 0       0 next if $?;
109             }
110             }
111              
112             # record this entry
113 5 100       12 unless(exists $self->{$type})
114 4         7 { $self->{$type} = [];
115 4         5 $self->{_count}++;
116             }
117 5         6 push @{$self->{$type}}, \%field;
  5         24  
118             }
119              
120 1         15 close MAILCAP;
121             }
122              
123             #------------------
124              
125 0     0 1 0 sub view { my $self = shift; $self->_run($self->viewCmd(@_)) }
  0         0  
126 0     0 1 0 sub compose { my $self = shift; $self->_run($self->composeCmd(@_)) }
  0         0  
127 0     0 1 0 sub edit { my $self = shift; $self->_run($self->editCmd(@_)) }
  0         0  
128 0     0 1 0 sub print { my $self = shift; $self->_run($self->printCmd(@_)) }
  0         0  
129              
130             sub _run($)
131 0     0   0 { my ($self, $cmd) = @_;
132 0 0       0 defined $cmd or return 0;
133              
134 0         0 system $cmd;
135 0         0 1;
136             }
137              
138             #------------------
139              
140 4     4 1 4098 sub viewCmd { shift->_createCommand(view => @_) }
141 0     0 1 0 sub composeCmd { shift->_createCommand(compose => @_) }
142 0     0 1 0 sub editCmd { shift->_createCommand(edit => @_) }
143 1     1 1 531 sub printCmd { shift->_createCommand(print => @_) }
144              
145             sub _createCommand($$$)
146 5     5   43 { my ($self, $method, $type, $file) = @_;
147 5         23 my $entry = $self->getEntry($type, $file);
148              
149 5 50 33     71 $entry && exists $entry->{$method}
150             or return undef;
151              
152 5         27 $self->expandPercentMacros($entry->{$method}, $type, $file);
153             }
154              
155             sub makeName($$)
156 0     0 0 0 { my ($self, $type, $basename) = @_;
157 0 0       0 my $template = $self->nametemplate($type)
158             or return $basename;
159              
160 0         0 $template =~ s/%s/$basename/g;
161 0         0 $template;
162             }
163              
164             #------------------
165              
166             sub field($$)
167 1     1 1 3 { my($self, $type, $field) = @_;
168 1         2 my $entry = $self->getEntry($type);
169 1         3 $entry->{$field};
170             }
171              
172              
173 1     1 1 67 sub description { shift->field(shift, 'description'); }
174 0     0 1 0 sub textualnewlines { shift->field(shift, 'textualnewlines'); }
175 0     0 1 0 sub x11_bitmap { shift->field(shift, 'x11-bitmap'); }
176 0     0 1 0 sub nametemplate { shift->field(shift, 'nametemplate'); }
177              
178             sub getEntry
179 6     6 0 13 { my($self, $origtype, $file) = @_;
180              
181             return $self->{_cache}{$origtype}
182 6 100 66     41 if $useCache && exists $self->{_cache}{$origtype};
183              
184 5         33 my ($fulltype, @params) = split /\s*;\s*/, $origtype;
185 5         23 my ($type, $subtype) = split m[/], $fulltype, 2;
186 5   100     23 $subtype ||= '';
187              
188 5         8 my $entry;
189 5         6 foreach (@{$self->{"$type/$subtype"}}, @{$self->{"$type/*"}})
  5         16  
  5         19  
190 6 100       17 { if(exists $_->{'test'})
191             { # must run test to see if it applies
192 2         8 my $test = $self->expandPercentMacros($_->{'test'},
193             $origtype, $file);
194 2         11687 system $test;
195 2 100       113 next if $?;
196             }
197 5         103 $entry = { %$_ }; # make copy
198 5         19 last;
199             }
200 5 50       41 $self->{_cache}{$origtype} = $entry if $useCache;
201 5         55 $entry;
202             }
203              
204             sub expandPercentMacros
205 7     7 0 31 { my ($self, $text, $type, $file) = @_;
206 7 50       18 defined $type or return $text;
207 7 50       13 defined $file or $file = "";
208              
209 7         78 my ($fulltype, @params) = split /\s*;\s*/, $type;
210 7         42 ($type, my $subtype) = split m[/], $fulltype, 2;
211              
212 7         10 my %params;
213 7         23 foreach (@params)
214 5         34 { my($key, $val) = split /\s*=\s*/, $_, 2;
215 5         32 $params{$key} = $val;
216             }
217 7         23 $text =~ s/\\%/\0/g; # hide all escaped %'s
218 7         16 $text =~ s/%t/$fulltype/g; # expand %t
219 7         28 $text =~ s/%s/$file/g; # expand %s
220             { # expand %{field}
221 7         13 local $^W = 0; # avoid warnings when expanding %params
  7         50  
222 7         62 $text =~ s/%\{\s*(.*?)\s*\}/$params{$1}/g;
223             }
224 7         24 $text =~ s/\0/%/g;
225 7         67 $text;
226             }
227              
228             # This following procedures can be useful for debugging purposes
229              
230             sub dumpEntry
231 0     0 0   { my($hash, $prefix) = @_;
232 0 0         defined $prefix or $prefix = "";
233             print "$prefix$_ = $hash->{$_}\n"
234 0           for sort keys %$hash;
235             }
236              
237             sub dump
238 0     0 0   { my $self = shift;
239 0           foreach (keys %$self)
240 0 0         { next if /^_/;
241 0           print "$_\n";
242 0           foreach (@{$self->{$_}})
  0            
243 0           { dumpEntry($_, "\t");
244 0           print "\n";
245             }
246             }
247              
248 0 0         if(exists $self->{_cache})
249 0           { print "Cached types\n";
250             print "\t$_\n"
251 0           for keys %{$self->{_cache}};
  0            
252             }
253             }
254              
255             1;