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; |