2
###############################################################################
4
# Install-MIME: Install programs into "/etc/mailcap", resolve conflicts,
5
# auto-uninstall, make dinner, and wash dishes.
7
# Written by Brian White <bcwhite@pobox.com>.
9
# This program has been placed in the public domain. Do whatever you wish
10
# with it, though I'd appreciate it if my name stayed on it as the original
13
###############################################################################
17
# --install Install the entries for specified package
18
# --remove Remove all entries for specified package
20
# --package=<pkg-name> Name of installing package
22
# --content=<content-type> Content-Type for specified programs
23
# --test=<conditional> Condition to test if line is valid
24
# --needsterminal=<t/f> Do these programs need a terminal
25
# --copiousoutput=<t/f> Do these programs generate extra output
27
# --description=<string> Text description for this content-type
28
# --textualnewlines=<t/f> Convert newline to CRLF before encoding
29
# --x11-bitmap=<file> Pathname to X icon bitmap representing type
30
# --nametemplate=<string> Template indicating files of this type
31
# --comment=<string> Comment to display to user at priority list
33
# --view=<program-string> Command line for viewing this type
34
# --compose=<program-string> Command line for composing this type
35
# --composetyped=<program> Command line for composing specified type
36
# --edit=<program-string> Command line for editing this type
37
# --print=<program-string> Command line for printing this type
39
# --quiet Avoid unnecessary output
40
# --noparmcheck Don't abort upon detecting a bad parameter
42
###############################################################################
50
$mimedb="/var/lib/mime/mime-db";
51
$mailcap="/etc/mailcap";
52
$compat="/var/lib/mime/mime-support-compat";
53
$action{view} = "view";
54
$action{compose} = "compose";
55
$action{composetyped} = "compose";
56
$action{edit} = "edit";
57
$action{print} = "print";
58
$action{"x11-bitmap"} = "x11-bitmap";
62
###############################################################################
67
# Subrutine to 'uniq' a sorted list
83
# Subroutine to output a string and move to next column
86
my($string,$size) = @_;
89
# $string = substr($string,0,$size-1);
90
print $string, " " x ($size - length($string));
96
# Subroutine to reformat text for the screen
99
my($string,$size) = @_;
100
my(@letters,$index,$count,$length);
101
$size = 80 unless $size;
103
@letters = split(//,$string);
108
while ($index < $length) {
110
if ($count < $length - $index) {
111
$count-- while (@letters[$index + $count] ne ' ');
113
print substr($string,$index,$count) . "\n";
114
$index += $count + 1;
121
# Subroutine to work around netscape's test bug
130
$file =~ s/\|\|/or/g;
133
$file = "/var/lib/mime/tests/".lc($file);
136
open(TESTFILE,">$file") || die "$0: could not write '$file' -- $!\n";
137
print TESTFILE '#! /bin/sh',"\n";
138
print TESTFILE $test,"\n";
139
print TESTFILE 'exit $?',"\n";
149
###############################################################################
154
# Subroutine to give help for "order"
159
Because many packages can be installed that are capable of performing actions
160
on the same types of files, it is necessary to specify your preference here.
161
Entries with smaller numbers will be tried first. If they have "test"
162
conditions that will not allow them to work in a given case, the next
163
alternative will be tried. This will continue until a valid entry is found or
164
all possibilities have been exausted.
166
For example: Two common ways of view GIF pictures are with the "xv" and the
167
"xloadimage" programs. If the "xv" package were installed and the "xloadimage"
168
package was being installed, you might see something like the following:
170
New action 'view' for MIME type 'image/gif' ("gif picture format")...
171
--> package=xloadimage view=xloadimage -view -quiet %s
173
1) package=xv view=xv %s
175
Place at what priority? (1-2, help) -->
177
Selecting "1" would place "xloadimage" as the top priority to be tried before
178
the "xv" program. Selecting "2" would place it after "xv".
182
print "Press <RETURN> to continue: ";
189
###############################################################################
194
# Subroutine to change type information
197
my($content,$field,$value) = @_;
199
if ($D{$content} =~ m/$field=(.*?)\t/) {
200
print "Resolving redefined '$field'...\n" if $debug;
201
return if ($1 eq $value);
203
# print "\nThis package recommends changing the value of '$field'\n";
204
# print "in the 'mailcap' file.\n\n";
205
# print " old: $1\n";
206
# print " new: $value\n\n";
207
# print "Do you wish to accept the new value? [y] ";
208
# my $resp = <STDIN>;
211
# return if ($resp =~ m/n/i);
214
$D{$content} =~ s|$field=.*?\t||g;
215
$D{$content} .= "$field=$value\t";
221
# Subroutine to choose an ordering
224
my($content,$command,$package,$value,$index) = @_;
225
my $action = $action{$command};
226
my @list = split(/\t/,$O{"$content,$action"});
229
my $i,$pkg,$idx,$other,$resp;
232
$O{"$content,$action"} .= "$package($index)\t";
233
print "- Added new action '$action' for MIME type '$content'\n" unless $A{quiet};
237
$max = ($size>9 ? 9 : $size) + 1;
241
$desc=" ($A{description})" if $A{description};
242
print "\nNew action '$action' for MIME type '$content'$desc...\n";
243
print "-->\tpackage=$package\t$value\n";
244
Reformat("Note: $A{comment}") if $A{comment};
246
for ($i=1; $i < $max; $i++) {
247
($pkg,$idx) = ($list[$i-1] =~ m/(.*?)\((\d+)\)/);
249
@lines = split(/\n/,$other);
250
$other = $lines[$idx];
251
$other =~ s|content=.*?\t||;
252
$other =~ s|action=.*?\t||;
253
print "$i)\t$other\n";
255
print "\nPlace at what priority (1-$max, help)? [1] ";
259
if ($resp =~ m/^h$/ || $resp =~ m/^help$/) {
261
} elsif ($resp eq "") {
265
} while ($resp < 1 || $resp > $max);
267
$O{"$content,$action"} = "";
268
for ($i=1; $i <= $size; $i++) {
269
$O{"$content,$action"} .= "$package($index)\t" if ($i == $resp);
270
$O{"$content,$action"} .= "$list[$i-1]\t";
272
$O{"$content,$action"} .= "$package($index)\t" if ($i == $resp);
278
# Subroutine to insert an ability for a package
281
my($pkg,$typ,$act,$prg,$tst,$flg) = @_;
282
my $value = "$act=$prg";
287
die "$0: semicolons are not allowed in commands -- use || or &&\n" if $prg=~m/;/ || $tst=~m/;/;
289
$value .= "; test=$tst" if $tst;
290
$value .= "; $flg" if $flg;
292
if ($P{$pkg} =~ m/package=\Q$pkg\E\tcontent=\Q$typ\E\t\Q$value\E\n/) {
293
print "- Ignoring already installed content '$typ' with value '$value'\n" if $debug;
297
my(@index)= ($P{$pkg} =~ m/\n/g);
299
$P{$pkg} .= "package=$pkg\tcontent=$typ\t$value\n";
301
print "Adding new action '$act' for package '$pkg' at index #$index\n" if $debug;
302
Order($typ,$act,$pkg,$value,$index);
308
# Subroutine to generate mailcap entries
318
my($idx) = shift @list;
319
my($val) = shift @list;
320
my($content,$action) = ($idx =~ m/^(.*),(.*)$/);
321
push @content,$content;
323
@content = uniq(sort(@content));
325
foreach $content (@content) {
327
if ($D{$content} =~ m/description=(.*?)\t/) { $flags .= "; description=$1"; }
328
if ($D{$content} =~ m/textualnewlines=(.*?)\t/) { $flags .= "; textualnewlines=1"; }
329
if ($D{$content} =~ m/nametemplate=(.*?)\t/) { $flags .= "; nametemplate=$1"; }
331
if ($O{"$content,x11-bitmap"} =~ m/(.*?)\((\d+)\)\t/) {
332
$P{$1} =~ m/x11-bitmap=(.*?)\n/s;
333
$flags .= "; x11-bitmap=$1";
336
print "* * * Printing content '$content'... ($flags)\n" if $debug;
337
foreach $action ("view","compose","edit","print") {
338
print " * * Printing action '$action'...\n" if $debug;
339
my $order = $O{"$content,$action"};
341
foreach (split(/\t/,$order)) {
342
my($pkg,$idx) = m/(.*?)\((\d+)\)/;
343
my @values = split(/\n/,$P{$pkg});
344
my $value = $values[$idx];
345
$value =~ s|package=.*?\tcontent=.*?\t||;
346
# print " * Fixing test for package '$_'... ($value)\n" if $debug;
347
# $value =~ s/test=(.*?)(;|$)/"test=".TestHack($1).$2/e; # Hack to fix Netscape's test bug
348
print " * Printing package '$_'... ($value)\n" if $debug;
349
if ($value =~ /^view=/) {
351
print $path "$content; $value$flags; priority=$prior\n";
353
print $path "$content; echo \"No viewer for type '$content'\"; $value$flags; priority=$prior\n";
356
$prior = 0 if ($prior < 0);
364
###############################################################################
369
# "Remove" subroutine
372
my $pkg = $A{package};
377
my $order = shift @list;
378
my $names = shift @list;
380
$O{$order} =~ s|$pkg\(\d+\)\t||g;
381
unless ($O{$order}) {
382
my($content,$action) = ($order =~ m/(.*),(.*)/);
383
print "- There is now nothing as '$2' for MIME type '$1'\n" unless $A{quiet};
394
# "Install" subroutine
399
my $arg = shift @list;
400
my $val = shift @list;
402
if ($arg =~ m/^(description|textualnewlines|nametemplate)$/ && $val) {
403
Change($A{content},$arg,$val);
407
Insert($A{package},$A{content},"x11-bitmap",$A{"x11-bitmap"}) if $A{"x11-bitmap"};
410
$flags .= "; needsterminal" if $A{needsterminal} =~ m/[Tt]/;
411
$flags .= "; copiousoutput" if $A{copiousoutput} =~ m/[Tt]/;
412
$flags .= "; textualnewlines" if $A{textualnewlines} =~ m/[Tt]/;
417
my $arg = shift @list;
418
my $val = shift @list;
420
if ($arg =~ m/^(view|compose|composetyped|edit|print)$/ && $val) {
421
die "Error: action '$arg' ($val) cannot be backgrounded within mailcap\n" if $val=~m/\&\s*$/;
422
Insert($A{package},$A{content},$arg,$val,$A{test},$flags);
437
my $order = shift @list;
438
my $value = shift @list;
439
my($content,$action) = ($order =~ m/(.*),(.*)/);
441
next if $A{content} && $content !~ m/^$A{content}/;
442
next if $A{package} && $value !~ m/$A{package}\(/;
444
print "\n$content: ";
445
$D{$content} =~ m/description=(.*?)\t/;
446
print " \"$1\"" if $1;
447
print " ($action)\n";
449
foreach (split(/\t/,$value)) {
450
my($package,$index) = (m/(.*)\((\d+)\)/);
451
my @pkgdata = split(/\n/,$P{$package});
452
next if $A{package} && $A{package} ne $package;
454
OutputColumn($package,20);
456
# print "\nExtracting from line: $pkgdata[$index]\n" if $debug;
457
my($command) = ($pkgdata[$index] =~ m/$action.*?=([^;]*)/);
458
my($test) = ($pkgdata[$index] =~ m/(test=[^\t]*)/);
459
OutputColumn($command,40);
469
###############################################################################
476
print STDOUT ""; $| = 1; # No 'autoflush' because perl may not be configured
490
$A{needsterminal} = '@';
491
$A{copiousoutput} = '@';
492
$A{description} = '@';
493
$A{textualnewlines} = '@';
494
$A{"x11-bitmap"} = '@';
495
$A{nametemplate} = '@';
498
$A{composetyped} = '@';
502
$A{noparmcheck} = -1;
507
# Look for parameter parsing flags (i.e. "--noparmcheck")
511
/^--noparmcheck$/ and $strictparms = 0;
513
#print "($0: parameter checking disabled)\n" unless $strictparms;
524
if (/^--(.*?)=(.*)$/) {
526
} elsif (/^--([^=]*)$/) {
529
die "$0: bad parameter '$_'\n" if $strictparms;
532
die "$0: unknown option '--$p'\n" if !$A{$p} and $strictparms;
533
die "$0: redefined option '--$p'\n" if ($A{$p} && $A{$p} ne '@' && $A{$p} != -1);
535
print "Setting '$p' = '$v'\n" if $debug;
541
# Don't use this program any more
543
print STDERR "Warning: 'install-mime' is obsolete -- use 'update-mime' instead (see man page)\n" if $strictparms;
547
# Remove any undefined parameters and do simple sanity check
551
my($parm) = shift @list;
552
my($valu) = shift @list;
553
undef $A{$parm} if $valu == -1;
554
undef $A{$parm} if $valu eq '@';
555
die "$0: missing mandatory option '--$parm'\n" if $valu eq '*';
558
die "$0: '--install' and '--remove' are mutually exclusive options\n" if $A{install} && $A{remove};
559
die "$0: install requires '--package' and '--content'\n" if $A{install} && (! $A{package} || ! $A{content});
560
die "$0: remove requires '--package'\n" if $A{remove} && ! $A{package};
561
die "$0: no action given!\n" unless $A{install} || $A{remove} || $A{list};
562
die "$0: content-type must be explicit (no '*' allowed)\n" if $A{content} =~ m/\*/;
564
print "$0: (warning) content-type '$A{content}' is not 'type/subtype'\n" if $A{content} && $A{content} !~ m|^[^/]+/[^/]+$|;
566
$A{content} = lc($A{content}) if $A{content};
573
open(PATH,"<$mimedb") || die "$0: could not read database '$mimedb' -- $!\n";
575
if (m/^content=(.*?)\taction=(.*?)\t(.*)\n$/) {
577
die "$0: database corruption! (multiple 'content=$1, action=$2' lines)\n" if $O{$idx};
579
} elsif (m/^content=(.*?)\t(.*)\n$/) {
580
die "$0: database corruption! (multiple 'content=$1;<data>' lines)\n" if $D{$1};
582
} elsif (m/^package=(.*?)\t/) {
586
die "$0: database corruption! (unknown line '$_')\n";
595
# Do actions specified by user
598
Remove if $A{remove};
599
Install if $A{install};
602
exit 0 unless $changed; # stop here if no changes were made
606
# Generate new mailcap file if necessary
608
open(PATH,">$compat") || die "$0: could not write '$compat' -- $!\n";
614
# Write data back to the database
616
open (PATH,">$mimedb") || die "$0: could not write database '$mimedb' -- $!\n";
620
my $idx = shift @list;
621
my $val = shift @list;
622
$idx =~ m/(.*?),(.*)/;
623
print PATH "content=$1\taction=$action{$2}\t$val\n" if $val;
628
my $idx = shift @list;
629
my $val = shift @list;
630
print PATH "content=$idx\t$val\n";
635
my $idx = shift @list;
636
my $val = shift @list;
644
# Run new 'update-mime' program
646
exec "/usr/sbin/update-mime";