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