#!/usr/bin/perl

##########################################################################
#
# rtf2pdf
# Converts a Microsoft(TM) RTF-file into Adobes(TM) PDF-format.
#
# Written & Copyright (C) 2015 by Peer Schaefer (peer@wolldingwacht.de).
# Licensed under the GNU General Public Licence, version 2 or later (at
# your choice).
#
##########################################################################

use strict;
use warnings;
use File::Temp qw(tempfile);
use File::Copy qw(move);
use File::Spec;

my $VERSION = "0.91";

#####################################################################
# Configuration:
#####################################################################

my $converter     = "";
my $rtf_filename  = "";
my $pdf_filename  = "";
my $verbose       = 0;
my $crop          = 1;

sub print_help();

foreach( @ARGV ) {
    if ( /^-{1,2}(h|help)$/ ) {
	print_help();
	exit 1;
    }
    elsif ( /^-{1,2}(version)$/ ) {
	print STDERR "rtf2pdf version ${VERSION}.\n";
	exit 1;
    }
    elsif ( /^-{1,2}(verbose)$/ ) {
	$verbose++;
    }
    elsif ( /^-{1,2}(c|crop)$/ ) {
	$crop = 1;
    }
    elsif ( /^-{1,2}(v+)$/ ) {
	$verbose += length( $1 );
    }
    elsif ( /^-{1,2}(abiword)$/ ) {
	$converter = "abiword";
    }
    elsif ( /^-{1,2}(ooffice|oowriter|swriter|libreoffice|openoffice)$/ ) {
	$converter = "swriter";
    }
    elsif ( ( -e $_ ) and ( /\.(rtf|RTF)$/ ) ) {
	if ( $rtf_filename ne "" ) {
	    die "Please specify only one RTF-file";
	}
	else {
	    $rtf_filename = $_;
	}
    }
    elsif ( /\.(pdf|PDF)$/ ) {
	if ( $pdf_filename ne "" ) {
	    die "Please specify only one PDF-file";
	}
	else {
	    $pdf_filename = $_;
	}
    }
    else {
	die "Syntax error: $_";
    }
}

#####################################################################
# Prepare filenames
#####################################################################

if ( $rtf_filename eq "" ) { # read input from STDIN
    binmode STDIN;
    my $text = "";
    while( <STDIN> ) {
	$text .= $_;
    }
    my ( $fh, $fn ) = tempfile( SUFFIX => ".rtf" );
    binmode $fh;
    print $fh $text;
    $rtf_filename  = $fn;
}
else { # read input from file
    if ( $pdf_filename eq "" ) { # use input name as output name (with ".pdf" suffix)
	my ( $vol, $pat, $fil ) = File::Spec->splitpath( $rtf_filename );
	if ( $fil =~ /^(.+?)\.(rtf|RTF)$/ ) {
	    $pdf_filename = File::Spec->catpath( $vol, $pat, "$1.pdf" );
	}
	else {
	    die "Can't determine name for PDF output";
	}
    }
}

#####################################################################
# Find converter
#####################################################################

sub find_swriter(); # OpenOffice.org's/LibreOffice's swriter
sub find_abiword(); # GNU's Abiword

# If no one is specified, choose any available (preference for swriter):
my $exe = "";
if ( $converter eq "" ) {
    $exe = find_swriter();
    if ( $exe ne "" ) {
	$converter = "swriter";
    }
    else {
	$exe = find_abiword();
	if ( $exe ne "" ) {
	    $converter = "abiword";
	}
	else {
	    die "Can't find any converter (please install one of OpenOffice.org/LibreOffice or Abiword)";
	}
    }
}

# Find the selected converter:
if ( $exe eq "" ) {
    if ( $converter eq "swriter" ) {
	$exe = find_swriter();
	if ( $exe eq "" ) {
	    die "Can't find OpenOffice.org/LibreOffice";
	}
    }
    if ( $converter eq "abiword" ) {
	$exe = find_abiword();
	if ( $exe eq "" ) {
	    die "Can't find Abiword";
	}
    }
}

#####################################################################
# MAIN
#####################################################################

my $output_filename = "";

# Use swriter:
if ( $converter eq "swriter" ) {
    my $dest_dir = File::Spec->tmpdir();
    my $result  = `${exe} --headless --convert-to pdf \"${rtf_filename}\" --outdir \"${dest_dir}\" 2>&1`;
    if ( ( defined $result ) and ( $result =~ /convert.*using.*writer_pdf_Export/ ) ) {
	if ( $verbose >= 1 ) {
	    print STDERR $result, "\n";
	}
	my ( $vol, $pat, $fil ) = File::Spec->splitpath( $rtf_filename );
	if ( $fil =~ /^(.+?)\.(rtf|RTF)$/ ) {
	    $output_filename = File::Spec->catfile( $dest_dir, "$1.pdf" );
	}
	else {
	    die "Can't find RTF-file";
	}
    }
    else {
	die "Error during conversion: ${result}";
    }
}

# Use abiword:
elsif ( $converter eq "abiword" ) {
    $output_filename = File::Spec->catfile( File::Spec->tmpdir(), "output.pdf" );
    my $result       = `${exe} --to=pdf \"${rtf_filename}\" --to-name=\"${output_filename}\" 2>&1`;
    foreach( split /\n/, $result ) {
	if    ( /gnome-keyring/ ) { next; }
	elsif ( /^\s*$/ )         { next; }
	else  {
	    die "An error occured: ${result}";
	}
    }
}

# Unknown:
else {
    die "Unknown converter: ${converter}";
}

# Check output:
if ( not -e $output_filename ) {
    die "No output produced";
}

# Crop, if requested:
if ( $crop == 1 ) {
    if ( `pdfcrop --version 2>&1` =~ /pdfcrop.*v(\d+)/ ) {
	my ( $cropped_fh, $cropped_fn ) = tempfile( SUFFIX => ".pdf" );
	my $result = `pdfcrop \"${output_filename}\" \"${cropped_fn}\" 2>&1`;
	if ( ( -e $cropped_fn ) and ( ( -s $cropped_fn ) > 0 ) ) {
	    $output_filename = $cropped_fn;
	}
	else {
	    die "Can't crop PDF: ${result}";
	}
    }
    else {
	die "Can't find pdfcrop (see http://www.ctan.org/tex-archive/support/pdfcrop).";
    }
}

# Write output:
if ( ( $pdf_filename eq "" ) or ( $pdf_filename eq "-" ) ) {
    open( my $pdffh, "<", $output_filename ) or die $!;
    binmode $pdffh; undef $/;
    my $pdf_content = <$pdffh>;
    close $pdffh;
    binmode STDOUT; undef $/;
    print STDOUT $pdf_content;
    if ( $verbose >= 1 ) {
	print STDERR "Written PDF output to STDOUT.\n";
    }
}
else {
    move( $output_filename, $pdf_filename );
    if ( $verbose >= 1 ) {
	print STDERR "Renamed \"${output_filename}\" to \"${pdf_filename}\".\n";
    }
}

#####################################################################
# Done!
#####################################################################
exit 0;

#####################################################################
#
# SUBROUTINES
#
#####################################################################

#####################################################################
# Provide help
#####################################################################

sub print_help()
{
    print "Usage: rtf2pdf [OPTIONs] [FILEs]\n";
    print "Convert a Microsoft(TM) RTF-file into Adobes(TM) PDF-format using OpenOffice.org's or LibreOffice's \"swriter\" or GNU's \"abiword\".\n";
    print "\n";
    print " -h, --help      display this help and exit\n";
    print " --verbose       be verbose\n";
    print " --crop          remove all margins from PDF output (\"cropping\")\n";
    print " --abiword       use GNU's abiword for conversion\n";
    print " --swriter       use OpenOffice.org's or LibreOffice's swriter for conversion\n";
    print "\n";
    print "If neither --abiword nor --swriter is specified, any available program is selected (with preference for swriter).\n";
    print "\n";
    print "xml2rtf version ${VERSION}. Written & Copyright (C) 2014 by Peer Schaefer (peer\@wolldingwacht.de). Licensed under the GNU General Public Licence (GPL), version 2 or later (at your choice). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.\n";
    exit 1;
}

#####################################################################
# Find OpenOffice.org's/LibreOffice's swriter
#####################################################################

sub find_swriter() {
    if ( $^O =~ /MSWin32/ ) {
	my $writer_version = `swriter --version 2>&1`;
	if ( ( defined $writer_version ) and ( $writer_version =~ /[Oo]ffice/s ) ) {
	    return "swriter";
	}
	else {
	    return "";
	}
    }
    else {
	my $root = "/opt";
	if ( ( -e $root ) and ( -d $root ) ) {
	    opendir( my $dh, $root ) or die $!;
	    my @dirlist = ();
	    while( readdir( $dh ) ) {
		my $entry = "${root}/$_";
		if ( -d $entry ) {
		    if ( /(open|libre).*office/ ) {
			push @dirlist, $entry;
		    }
		}
	    }
	    closedir $dh;
	    foreach( sort { $b cmp $a } @dirlist ) {
		my $path = $_;
		my @exes = (
		    "${path}/program/swriter"
		    );
		foreach( @exes ) {
		    if ( ( -e $_ ) and ( -x $_ ) ) {
			return $_;
		    }
		}
	    }
	}
	my $which_path = `which swriter 2>&1`;
	if ( defined $which_path ) {
	    $which_path =~ s/\s+$//;
	    if ( $which_path =~ /^\// ) {
		return $which_path;
	    }
	}
	my $writer_version = `swriter --version 2>&1`;
	if ( ( defined $writer_version ) and ( $writer_version =~ /[Oo]ffice/s ) ) {
	    return "swriter";
	}
	else {
	    return "";
	}
    }
    return "";
}

#####################################################################
# Find GNU's Abiword
#####################################################################

sub find_abiword() {
    if ( $^O =~ /MSWin32/ ) {
	my $writer_version = `abiword --version 2>&1`;
	if ( ( defined $writer_version ) and ( $writer_version =~ /\d\.\d/s ) ) {
	    return "abiword";
	}
	else {
	    return "";
	}
    }
    else {
	my $which_path = `which abiword 2>&1`;
	if ( defined $which_path ) {
	    $which_path =~ s/\s+$//;
	    if ( $which_path =~ /^\// ) {
		return $which_path;
	    }
	}
	my $writer_version = `abiword --version 2>&1`;
	if ( ( defined $writer_version ) and ( $writer_version =~ /\d\.\d/s ) ) {
	    return "abiword";
	}
	else {
	    return "";
	}
    }
    return "";
}

#####################################################################
# EOF
#####################################################################
__END__
